簡體   English   中英

使用GLSL着色器隱藏面

[英]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嘗試以另一種方式渲染三角形及其中的每個像素,然后我們的片段着色器一次丟棄每個像素。

這是該技術的樣本

在三個JS中按三角形ID丟棄

在WebGL(tdl)中按三角ID丟棄

使用UV觀察WebGL(tdl)中的紋理按三角形丟棄

注意:這最后一個要求從頂點着色器中的紋理讀取,這是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM