我试图让着色器与three.js一起工作。这是一个用于WebGL的JavaScript库。我刚刚开始阅读GLSL,所以有些事情我遇到了麻烦。基本上我想揭示和隐藏几何的面。我克隆了几何体的面阵并重新排序。重新排序的数组按照我想要显示/隐藏它们的顺序具有面。我已经读过Uniforms可以从管道内的任何地方访问。我可以将数组声明为Uniform并从片段着色器访问它吗?我已经遇到命令gl_FragColor并用它来调整我整个几何体的不透明度。我想也许我可以使用gl_FragColor将特定面的不透明度设置为0.另外,我查看了规格并找到了gl_SampleID。 gl_SampleID会告诉我当前的面部号码吗?抱歉所有的问题,但我仍然试图说清楚我的头脑。如果有更好的事情,请告诉我。我一直在尝试调整现有的着色器,因为我喜欢它的纹理效果。这是一些示例代码。
uniform float time;
uniform vec2 resolution;
uniform sampler2D texture1;
uniform sampler2D texture2;
varying vec2 vUv;
uniform float alpha;
uniform int face_Array;
void main( void ) {
vec2 position = -1.0 + 2.0 * vUv;
vec4 noise = texture2D( texture1, vUv );
vec2 T1 = vUv + vec2( 1.5, -1.5 ) * time *0.02;
vec2 T2 = vUv + vec2( -0.5, 2.0 ) * time * 0.01;
T1.x += noise.x * 2.0;
T1.y += noise.y * 2.0;
T2.x -= noise.y * 0.2;
T2.y += noise.z * 0.2;
float p = texture2D( texture1, T1 * 2.0 ).a;
vec4 color = texture2D( texture2, T2 * 2.0 );
vec4 temp = color * ( vec4( p, p, p, p ) * 2.0 ) + ( color * color - 0.1 );
if( temp.r > 1.0 ){ temp.bg += clamp( temp.r - 2.0, 0.0, 100.0 ); }
if( temp.g > 1.0 ){ temp.rb += temp.g - 1.0; }
if( temp.b > 1.0 ){ temp.rg += temp.b - 1.0; }
gl_FragColor = vec4(temp.r, temp.g, temp.b, alpha);
}
答案 0 :(得分:4)
您是否使用WebGL或three.js并不清楚。它们不是一回事
无论如何,假设我明白你要做什么。一种方法是创建一个属性,让它称之为" triangleId"或" vertexId"。由你决定。 " vertexId"可能更好。
- 顶点着色器 -
attribute float vertexId;
varying float v_triangleId;
...
void main() {
// pass triangleId to the fragment shader
v_triangleId = floor(vertexId / 3.0) + 0.05;
...
}
- 片段着色器 -
...
varying float v_triangleId;
uniform float u_triangleToHide;
void main() {
if (v_triangleId == u_triangleToHide) {
discard;
}
}
然后创建一个缓冲区并用顶点的id填充它。
var vertIds = new Float32Array(numVertices);
for (var i = 0; i < numVertices; ++i) {
vertIds[i] = i;
}
var vertIdBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertIdBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertIds, gl.STATIC_DRAW);
并设置属性
gl.enableVertexAttribArray(locationOfVertIdAttrib);
gl.vertexAttribPointer(locationOfVertIdAttrib, 1, gl.FLOAT, false, 0, 0);
这有多少意义吗?您现在可以通过设置u_triangleToHide
当然你可能想检查一些epsilon而不是像
那样的平等 float diff = abs(v_triangleId - u_triangleToHide);
if (diff < 0.01) {
discard;
}
或者您可以使用一些更复杂的检查来每隔7个隐藏其他一个或根据某个范围或其他任何方式调整alpha。
Here's an example和another example
另一种方法是分配第二个纹理和第二组UV坐标。指定特定三角形的每个顶点以查看第二个纹理中的相同像素。换一种说法。使第一个三角形的所有3个顶点都看到纹理中的第一个像素。使第二个三角形的所有顶点都看到纹理中的第二个像素。使第3个三角形的所有顶点都看到纹理中的第3个像素。
在每个三角形的片段着色器中,您可以查找与纹理中该像素对应的像素。您可以使用它来决定是否显示该三角形。更新纹理以更改显示或未显示的三角形,或将其设置为灰色标度以更改其alpha。如果您将纹理设置为渲染目标,您甚至可以渲染它。
如果您要使用此方法,也可以使用RGBA纹理而不是单个通道纹理为每个三角形着色。
在示例中,我有一个2D画布(左上角)。我使用2D API绘制它。每个像素对应于球体上的一个像素。然后,我通过调用texImage2D(..., canvas)
将该画布上传到每个帧的纹理。
注意:要执行这些技术中的任何一种,几乎都需要非索引顶点。换句话说,使用gl.drawArrays
而不是gl.drawElements
。您可以使用gl.drawElements
,但由于每个顶点都是唯一的,因此您的索引缓冲区将只是[0, 1, 2, 3, 4, 5, 6, ...]
。
Brendan在评论中指出,在片段着色器中丢弃会更有效率。你可以通过移动相机后面的顶点来实现这一点。
- 顶点着色器 -
attribute float vertexId;
uniform float u_triangleToHide;
void main() {
...
triangleId = floor(vertexId / 3.0) + 0.05;
float diff = abs(triangleId - u_triangleToHide);
if (diff < 0.01) {
gl_Position = vec4(0, 0, 2, 1); // put behind the camera
}
这样做的好处是GPU只会剪切三角形。另一种方式是GPU尝试渲染三角形及其中的每个像素,然后我们的片段着色器一次丢弃一个像素。
此处使用该技术的样本
Discarding by triangle id in three JS
Discarding by triangle id in WebGL (tdl)
Discarding by triangle using UVs looking into texture in WebGL (tdl)。
注意:最后一个需要从顶点着色器中读取纹理,该着色器是WebGL的可选特征。根据{{3}},97%的GPU支持这一点,因此您最安全。如果您使用这种技术,对于那些不能工作的3%的人,您应该通过检查是否gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) > 0
进行检查。如果没有退回或至少告诉用户它不会起作用。
答案 1 :(得分:0)
通常在WebGL中你进行绘制调用,并且必须指定从哪里开始绘制以及在每次调用中绘制多少个顶点,很明显你只能&#34;不能绘制& #34;几何体的一部分,或将其分成几个绘制调用。
在threejs中,这被抽象为一个名为drawCalls
的属性。如果您已按照要隐藏的顺序对几何体进行排序,则只需创建一个drawCall并随时间修改范围即可。如果没有指定drawCalls,则三个渲染整个几何体,因为在大多数情况下这可能是人们想要的。
(编辑:此属性显然仅适用于BufferGeometry而不是常规Geometry,因此您可能需要转换它。)