簡體   English   中英

如何在幀緩沖區中為3DTexture的一個層渲染單個像素?

[英]How to render individual pixels for one layer of a 3DTexture in a framebuffer?

我有一個4x4x4 3DTexture,我正在初始化並正確顯示為我的4x4x4頂點網格着色(請參閱附加的紅色網格,其中包含一個白色像素 - 0,0,0)。

在此輸入圖像描述

然而,當我在幀緩沖區渲染4層時(使用gl.COLOR_ATTACHMENT0 - > gl.COLOR_ATTACHMENT3一次全部四層),我的片段着色器(將變為綠色)成功渲染圖層上的16個像素中的四個。

在此輸入圖像描述

當我只使用gl.COLOR_ATTACHMENT0執行一個圖層時,相同的4個像素顯示為1層正確更改,而其他3個圖層保持原始顏色不變。 當我將gl.viewport(0,0,大小,大小)(此示例中的大小= 4)更改為其他類似整個屏幕或大小不同的大小時,則會寫入不同的像素,但不會超過4我的目標是精確地單獨指定每層的所有16個像素。 我現在正在使用顏色作為學習經驗,但紋理實際上是物理模擬中每個頂點的位置和速度信息。 我假設(錯誤的假設?)64點/頂點,我正在運行頂點着色器和片段着色器64次,每次調用着色一個像素。

我已經從着色器中移除了除了重要代碼之外的所有代碼。 我保持javascript不變。 我懷疑我的問題是初始化並錯誤地傳遞頂點位置數組。

//Set x,y position coordinates to be used to extract data from one plane of our data cube
//remember, z we handle as a 1 layer of our cube which is composed of a stack of x-y planes. 
const oneLayerVertices = new Float32Array(size * size * 2);
count = 0;  
for (var j = 0; j < (size); j++) {
    for (var i = 0; i < (size); i++) {
        oneLayerVertices[count] = i;
        count++;

        oneLayerVertices[count] = j;
        count++;

        //oneLayerVertices[count] = 0;
        //count++;

        //oneLayerVertices[count] = 0;
        //count++;

    }
}

const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
   position: {
      numComponents: 2,
      data: oneLayerVertices,
   },
});

然后我使用bufferInfo如下:

gl.useProgram(computeProgramInfo.program);
   twgl.setBuffersAndAttributes(gl, computeProgramInfo, bufferInfo);

   gl.viewport(0, 0, size, size); //remember size = 4

   outFramebuffers.forEach((fb, ndx) => {
      gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
      gl.drawBuffers([
         gl.COLOR_ATTACHMENT0,
         gl.COLOR_ATTACHMENT1,
         gl.COLOR_ATTACHMENT2,
         gl.COLOR_ATTACHMENT3
      ]);

      const baseLayerTexCoord = (ndx * numLayersPerFramebuffer);
      console.log("My baseLayerTexCoord is "+baseLayerTexCoord);
      twgl.setUniforms(computeProgramInfo, {
         baseLayerTexCoord,
         u_kernel: [
             0, 0, 0,
             0, 0, 0,
             0, 0, 0,

             0, 0, 1,
             0, 0, 0,
             0, 0, 0,

             0, 0, 0,
             0, 0, 0,
             0, 0, 0,
         ],
         u_position: inPos,      
         u_velocity: inVel,      
         loopCounter: loopCounter,   

         numLayersPerFramebuffer: numLayersPerFramebuffer
      });
      gl.drawArrays(gl.POINTS, 0, (16));
   });

VERTEX SHADER:calc_vertex:

const compute_vs = `#version 300 es
  precision highp float;
  in vec4 position;
  void main() {
    gl_Position = position;
  }
`;

碎片陰影:calc_fragment:

const compute_fs = `#version 300 es
precision highp float;

out vec4 ourOutput[4];

void main() {
   ourOutput[0] = vec4(0,1,0,1);
   ourOutput[1] = vec4(0,1,0,1);
   ourOutput[2] = vec4(0,1,0,1);
   ourOutput[3] = vec4(0,1,0,1);
}
`;

我不確定你要做什么以及你認為這些職位會做什么。

在WebGL2中有2個GPU模擬選項

  1. 使用變換反饋。

    在這種情況下,您傳入屬性並在緩沖區中生成數據。 有效地,您具有屬性和屬性,通常只運行頂點着色器。 換句話說,你的變化,頂點着色器的輸出,寫入緩沖區。 所以你至少有兩組緩沖區,currentState和nextState,你的頂點着色器從currentState讀取屬性並將它們寫入nextState

    有通過變換反饋寫入緩沖區的例子這里雖然這個例子只使用在開始變換反饋一次填充緩沖器。

  2. 使用附加到framebuffers的紋理

    在這種情況下,類似地你有2個紋理,currentState和nextState,你將nextState設置為你的渲染目標,並從currentState讀取以生成下一個狀態。

    難點在於您只能通過在頂點着色器中輸出圖元來渲染到紋理。 如果currentState和nextState是2D紋理,則為trival。 只需從頂點着色器輸出-1.0到+1.0 quad, nextState所有像素nextState將被渲染到。

    如果你正在使用3D紋理,那么除了你一次只能渲染到4層(好吧, gl.getParameter(gl.MAX_DRAW_BUFFERS) )。 所以你必須做類似的事情

     for(let layer = 0; layer < numLayers; layer += 4) { // setup framebuffer to use these 4 layers gl.drawXXX(...) // draw to 4 layers) } 

    或更好

     // at init time const fbs = []; for(let layer = 0; layer < numLayers; layer += 4) { fbs.push(createFramebufferForThese4Layers(layer); } // at draw time fbs.forEach((fb, ndx) => {; gl.bindFramebuffer(gl.FRAMEBUFFER, fb); gl.drawXXX(...) // draw to 4 layers) }); 

    我猜多個繪制調用比一個繪制調用慢,所以另一個解決方案是將2D紋理視為3D數組並適當地計算紋理坐標。

我不知道哪個更好。 如果您正在模擬粒子,他們只需要查看自己的currentState,那么轉換反饋就更容易了。 如果需要每個粒子能夠查看其他粒子的狀態,換句話說,您需要隨機訪問所有數據,那么您唯一的選擇是將數據存儲在紋理中。

至於職位,我不明白你的代碼。 位置定義一個基元, POINTSLINESTRIANGLES那么如何將整數X,Y值傳遞到我們的頂點着色器中,如何幫助您定義POINTSLINESTRIANGLES

看起來你正在嘗試使用POINTS在這種情況下你需要將gl_PointSize設置為你想要繪制的點的大小(1.0),你需要將這些位置轉換為剪輯空間

gl_Position = vec4((position.xy + 0.5) / resolution, 0, 1);

其中resolution是紋理的大小。

但這樣做會很慢。 更好的是只繪制一個全尺寸(-1到+1)剪輯空間四邊形。 對於目標中的每個像素,將調用片段着色器。 gl_FragCoord.xy將是當前正在渲染的像素中心的位置,因此左下角的第一個像素gl_FragCoord.xy將為( gl_FragCoord.xy )。 右邊的像素為(1.5,0.5)。 右邊的像素為(2.5,0.5)。 您可以使用該值來計算如何訪問currentState 假設1x1映射最簡單的方法是

int n = numberOfLayerThatsAttachedToCOLOR_ATTACHMENT0;
vec4 currentStateValueForLayerN = texelFetch(
    currentStateTexture, ivec3(gl_FragCoord.xy, n + 0), 0);
vec4 currentStateValueForLayerNPlus1 = texelFetch(
    currentStateTexture, ivec3(gl_FragCoord.xy, n + 1), 0);
vec4 currentStateValueForLayerNPlus2 = texelFetch(
    currentStateTexture, ivec3(gl_FragCoord.xy, n + 2), 0);
...

vec4 nextStateForLayerN = computeNextStateFromCurrentState(currentStateValueForLayerN);
vec4 nextStateForLayerNPlus1 = computeNextStateFromCurrentState(currentStateValueForLayerNPlus1);
vec4 nextStateForLayerNPlus2 = computeNextStateFromCurrentState(currentStateValueForLayerNPlus2);
...

outColor[0] = nextStateForLayerN;
outColor[1] = nextStateForLayerNPlus1;
outColor[2] = nextStateForLayerNPlus1;
...

我不知道你是否需要這個但只是為了測試這里是一個簡單的例子,它為4x4x4紋理的每個像素呈現不同的顏色然后顯示它們。

 const pointVS = ` #version 300 es uniform int size; uniform highp sampler3D tex; out vec4 v_color; void main() { int x = gl_VertexID % size; int y = (gl_VertexID / size) % size; int z = gl_VertexID / (size * size); v_color = texelFetch(tex, ivec3(x, y, z), 0); gl_PointSize = 8.0; vec3 normPos = vec3(x, y, z) / float(size); gl_Position = vec4( mix(-0.9, 0.6, normPos.x) + mix(0.0, 0.3, normPos.y), mix(-0.6, 0.9, normPos.z) + mix(0.0, -0.3, normPos.y), 0, 1); } `; const pointFS = ` #version 300 es precision highp float; in vec4 v_color; out vec4 outColor; void main() { outColor = v_color; } `; const rtVS = ` #version 300 es in vec4 position; void main() { gl_Position = position; } `; const rtFS = ` #version 300 es precision highp float; uniform vec2 resolution; out vec4 outColor[4]; void main() { vec2 xy = gl_FragCoord.xy / resolution; outColor[0] = vec4(1, 0, xy.x, 1); outColor[1] = vec4(0.5, xy.yx, 1); outColor[2] = vec4(xy, 0, 1); outColor[3] = vec4(1, vec2(1) - xy, 1); } `; function main() { const gl = document.querySelector('canvas').getContext('webgl2'); if (!gl) { return alert('need webgl2'); } const pointProgramInfo = twgl.createProgramInfo(gl, [pointVS, pointFS]); const rtProgramInfo = twgl.createProgramInfo(gl, [rtVS, rtFS]); const size = 4; const numPoints = size * size * size; const tex = twgl.createTexture(gl, { target: gl.TEXTURE_3D, width: size, height: size, depth: size, }); const clipspaceFullSizeQuadBufferInfo = twgl.createBufferInfoFromArrays(gl, { position: { data: [ -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, ], numComponents: 2, }, }); const fb = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fb); for (let i = 0; i < 4; ++i) { gl.framebufferTextureLayer( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, tex, 0, // mip level i, // layer ); } gl.drawBuffers([ gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3, ]); gl.viewport(0, 0, size, size); gl.useProgram(rtProgramInfo.program); twgl.setBuffersAndAttributes( gl, rtProgramInfo, clipspaceFullSizeQuadBufferInfo); twgl.setUniforms(rtProgramInfo, { resolution: [size, size], }); twgl.drawBufferInfo(gl, clipspaceFullSizeQuadBufferInfo); gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); gl.drawBuffers([ gl.BACK, ]); gl.useProgram(pointProgramInfo.program); twgl.setUniforms(pointProgramInfo, { tex, size, }); gl.drawArrays(gl.POINTS, 0, numPoints); } main(); 
 <canvas></canvas> <script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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