对象的着色器线框

Posted

技术标签:

【中文标题】对象的着色器线框【英文标题】:Shader wireframe of an object 【发布时间】:2018-02-05 15:23:44 【问题描述】:

我想看一个没有对角线的物体的线框

目前,我根据顶点添加线,问题是在我有几个之后我遇到了主要的性能下降。

here 的示例对于我的 Three 版本来说要么太新要么不起作用(我在那里对此发表了评论)。

所以我想尝试实现一个着色器。

我尝试使用此着色器:https://***.com/a/31610464/4279201,但它会将形状分解为多个部分,并且出现 WebGL 错误。

我就是这么用的:

const vertexShader = `
varying vec2 vUv;
void main() 
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);

`

const fragmentShader = `
#version 150 compatibility                                         
flat in float diffuse;
flat in float specular;
flat in vec3  edge_mask;                                           
in vec2 bary;
uniform float mesh_width = 1.0;
uniform vec3 mesh_color = vec3(0.0, 0.0, 0.0);
uniform bool lighting = true;
out vec4 frag_color ;
float edge_factor()                                               
  vec3 bary3 = vec3(bary.x, bary.y, 1.0 - bary.x - bary.y);
  vec3 d = fwidth(bary3);
  vec3 a3 = smoothstep(vec3(0.0, 0.0, 0.0), d * mesh_width, bary3);
  a3 = vec3(1.0, 1.0, 1.0) - edge_mask + edge_mask * a3;
  return min(min(a3.x, a3.y), a3.z);

void main()                                                       
  float s = (lighting && gl_FrontFacing) ? 1.0 : -1.0;
  vec4  Kdiff = gl_FrontFacing ?
    gl_FrontMaterial.diffuse : gl_BackMaterial.diffuse;
  float sdiffuse = s * diffuse;
  vec4 result = vec4(0.1, 0.1, 0.1, 1.0);
  if (sdiffuse > 0.0) 
    result += sdiffuse * Kdiff +
      specular * gl_FrontMaterial.specular;
  
  frag_color = (mesh_width != 0.0) ?
    mix(vec4(mesh_color, 1.0), result, edge_factor()) :
    result;
`     

...

const uniforms = 
  color: 
    value: new THREE.Vector4(0, 0, 1, 1),
    type: 'v4'
  


const material = new THREE.ShaderMaterial(
  fragmentShader: data.fragmentShader,
  vertexShader: data.vertexShader,
  uniforms
)

this._viewer.impl.matman().addMaterial(
  data.name, material, true)

    const fragList = this._viewer.model.getFragmentList()

this.toArray(fragIds).forEach((fragId) => 

  fragList.setMaterial(fragId, material)
)

所以要实现这个着色器,正确的方法是基本上检查每两个顶点之间的角度,如果度数为 90,则画一条线?

如何从顶点着色器访问形状的所有顶点?

我如何告诉片段着色器在符合上述条件的两个顶点之间画一条线? (也保留其他所有内容的默认阴影)

我正在使用使用 Three.js rev 71 的 Autodesk 查看器。

【问题讨论】:

Interest Q , No answer but - 建议 1) 如果我们使用绘制线模式并正确重新生成 vertexIndices 和整个几何体(仅绘制前面的可见片段),我们也可以得到很好的优化(最少的顶点)。 2)也许 glBlend 可以在某种程度上提供帮助。 3)进行着色器计算以削减不需要的值... @NikolaLukic "绘制线模式,正确再生 vertexIndices" 这是什么意思? 你不想要背面线条,实现这个想法的一种方法是在运行时(在每个 drawFrame 上)制作只需要视觉效果(顶点)的新几何体。原始物体几何形状和相机的位置/旋转将是计算的基础值。对于立方体(示例) - 新的立方体几何体有 3 个(也可以是 2 个或 1 个)边,而不是通常顺序的 6 个。对不起我的英语不好。希望你能理解我的评论 您的着色器对 WebGL 无效。这一行尤其是 #version 150 compatibility 不是有效的 WebGL GLSL。您的着色器未成功编译,因此您收到与错误着色器相关的错误。这些行以及flat in float diffuse; 也仅适用于 WebGL2 删除这些行和变量后我仍然收到错误...@gman 【参考方案1】:
// -- Vertex Shader --
precision mediump float;

// Input from buffers
attribute vec3 aPosition;
attribute vec2 aBaryCoord;

// Value interpolated accross pixels and passed to the fragment shader
varying vec2 vBaryCoord;

// Uniforms
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;

void main() 
    vBaryCoord = aBaryCoord;
    gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(aPosition,1.0);

// ---------------------

// -- Fragment Shader --
// This shader doesn't perform any lighting
precision mediump float;

varying vec2 vBaryCoord;

uniform vec3 uMeshColour;

float edgeFactor() 
    vec3 d = fwidth(vBaryCoord);
    vec3 a3 = smoothstep(vec3(0.0,0.0,0.0),d * 1.5,vBaryCoord);
    return min(min(a3.x,a3.y),a3.z);


void main() 
    gl_FragColor = vec4(uMeshColour,(1.0 - edgeFactor()) * 0.95);

// ---------------------

/*
    This code isn't tested so take it with a grain of salt

    Idea taken from
    http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/
*/

【讨论】:

以上是关于对象的着色器线框的主要内容,如果未能解决你的问题,请参考以下文章

渲染管道几何阶段四“几何着色器”

渲染管道几何阶段四“几何着色器”

没有 VAO 的每个着色器属性的 VBO 或不同的方法?

初识OpenGL 链接着色器

初识OpenGL 链接着色器

OpenGLES3.0创建着色器步骤