[英]Hide faces with GLSL shader
我正在嘗試使着色器與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);
}
目前尚不清楚您使用的是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
選擇要消失的u_triangleToHide
當然,您可能需要檢查一些epsilon而不是像
float diff = abs(v_triangleId - u_triangleToHide);
if (diff < 0.01) {
discard;
}
或者,您可以使用一些更復雜的檢查來每隔7個就隱藏一次,或者根據某個范圍或任何其他值來調整alpha。
另一種方法是分配第二紋理和第二組UV坐標。 分配特定三角形的每個頂點以查看第二個紋理中的相同像素。 換一種說法。 使第一個三角形的所有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嘗試以另一種方式渲染三角形及其中的每個像素,然后我們的片段着色器一次丟棄每個像素。
這是該技術的樣本
注意:這最后一個要求從頂點着色器中的紋理讀取,這是WebGL的可選功能。 根據webglstats的統計, 有 97%的GPU支持此功能,因此您大多數情況下都是安全的。 如果使用此技術,那么對於那3%無法使用的人,您應該檢查gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) > 0
來進行檢查。 如果沒有退路,或者至少告訴用戶這是行不通的。
通常,在WebGL中,您需要進行繪制調用,並且必須指定從何處開始繪制以及在每個調用中要繪制多少個頂點,很明顯,您只能“不繪制”幾何圖形的部分或拆分分成幾個抽獎電話。
在threejs中,將其抽象為一個名為drawCalls
的屬性。 如果您已經按照要隱藏幾何的順序對幾何進行了排序,那么您要做的就是創建一個drawCall並隨時間修改范圍。 如果未指定drawCalls,threejs將渲染整個幾何,這是大多數情況下人們想要的。
(編輯:此屬性顯然僅對BufferGeometry存在,而對常規Geometry不存在,因此您可能需要對其進行轉換。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.