Визуализация 16-битной целочисленной двумерной текстуры в WebGL2 - PullRequest
0 голосов
/ 29 июня 2018

Как указано в официальных спецификациях или документах WebGL 2 ( смотрите здесь ), формат внутреннего размера gl.RGBA16UI - это цветопередача. Это означает, что я должен иметь возможность рендерить в текстуру RGBA16UI.

Я могу легко заполнить текстуру UInt16Array, а затем использовать ее. Но мне не удается заполнить рендеринг текстуры шейдером. Тогда я получаю нули только при выборке значений в следующем шейдере.

Кто-нибудь уже преуспел в рендеринге в целочисленную текстуру без знака с WebGL 2? Я был бы очень благодарен, я играю с форматами текстур в течение нескольких недель, и я не понимаю, что я делаю здесь неправильно ... И я не нашел своей ошибки в других SO вопросах по этому вопросу.

Вы можете найти полный код в фрагменте ниже. 6 цветов, напечатанных на левой стороне, являются результатом отображения текстуры RGBA16UI, заполненной массивом UInt16Array. С правой стороны мы должны получить тот же результат, если рендеринг в текстуру RGBA16UI был успешным.

[редактировать] Это была просто глупая опечатка. Я обновил свой код и принял gman answer как два функциональных примера рендеринга в целочисленную текстуру без знака в WebGL 2.

// Position/UV data
var displayPlanePositions = new Float32Array([
  -1, 1,
  -1, -1,
  0, -1,

  -1, 1,
  0, -1,
  0, 1
]);
var displayPlaneRTTPositions = new Float32Array([
  0, 1,
  0, -1,
  1, -1,

  0, 1,
  1, -1,
  1, 1
]);
var effectPlanePositions = new Float32Array([
  -1, 1,
  -1, -1,
  1, -1,

  -1, 1,
  1, -1,
  1, 1
]);
var displayPlaneUVs = new Float32Array([
  0, 1,
  0, 0,
  1, 0,

  0, 1,
  1, 0,
  1, 1
]);
var displayPlaneRTTUVs = new Float32Array([
  0, 1,
  0, 0,
  1, 0,

  0, 1,
  1, 0,
  1, 1
]);

// Texture data
var pixelsRGBA16UI = new Uint16Array([
  65535, 0, 0, 65535,
  0, 65535, 0, 65535,
  0, 0, 65535, 65535,
  65535, 65535, 0, 65535,
  0, 65535, 65535, 65535,
  65535, 65535, 65535, 65535
]);

// Shaders
var displayPlane16UIVertexShaderSource =
 `#version 300 es

  in vec2 position;
  in vec2 uv;
  out vec2 vUV;

  void main()
  {
    vUV = uv;
    gl_Position = vec4(position, 1.0, 1.0);
  }`;
var displayPlane16UIFragmentShaderSource =
 `#version 300 es
  precision highp float;
  precision highp usampler2D;

  uniform usampler2D sampler;

  in vec2 vUV;
  out vec4 color;

  void main()
  {
    uvec4 samplerUIntColor = texture(sampler, vUV);
    vec4 samplerFloatColor = vec4(samplerUIntColor) / 65535.0;
    color = samplerFloatColor;
  }`;
var effectPlane16UIVertexShaderSource =
 `#version 300 es

  in vec2 position;

  void main(void) {
    gl_Position = vec4(position, 1.0, 1.0);
  }`;
var effectPlane16UIFragmentShaderSource =
 `#version 300 es
  precision highp float;

  out uvec4 color;

  void main(void) {
    if (gl_FragCoord.x == 0.5) {
      if (gl_FragCoord.y == 0.5) {
        color = uvec4(65535u, 0.0, 0.0, 65535u);
      } else {
        color = uvec4(65535u, 65535u, 0.0, 65535u);
      }
    } else if (gl_FragCoord.x == 1.5) {
      if (gl_FragCoord.y == 0.5) {
        color = uvec4(0.0, 65535u, 0.0, 65535u);
      } else {
        color = uvec4(0.0, 65535u, 65535u, 65535u);
      }
    } else {
      if (gl_FragCoord.y == 0.5) {
        color = uvec4(0.0, 0.0, 65535u, 65535u);
      } else {
        color = uvec4(65535u, 65535u, 65535u, 65535u);
      }
    }
  }`;
var displayPlaneRTT16UIVertexShaderSource =
 `#version 300 es

  in vec2 position;
  in vec2 uv;
  out vec2 vUV;

  void main(void) {
    vUV = uv;
    gl_Position = vec4(position, 1.0, 1.0);
  }`;
var displayPlaneRTT16UIFragmentShaderSource =
 `#version 300 es
  precision highp float;
  precision highp usampler2D;

  uniform usampler2D sampler;

  in vec2 vUV;
  out vec4 color;

  void main(void) {
    uvec4 samplerUIntColor = texture(sampler, vUV);
    vec4 samplerFloatColor = vec4(samplerUIntColor) / 65535.0;
    color = samplerFloatColor;
  }`;
  
// Create and get context
var canvas16UI = document.getElementById('webgl2-opti-tests-16ui');
var gl16UI = canvas16UI.getContext('webgl2');
canvas16UI.width = 512;
canvas16UI.height = 512;

// Get extension
var color_buffer_float_16ui = gl16UI.getExtension('EXT_color_buffer_float');

// Clear canvas
gl16UI.clearColor(0.0, 0.0, 0.0, 1.0);
gl16UI.clear(gl16UI.COLOR_BUFFER_BIT);

var log;


/* DISPLAY PLANE */

// Create Program
var displayPlane16UIVertexShader = gl16UI.createShader(gl16UI.VERTEX_SHADER);
var displayPlane16UIFragmentShader = gl16UI.createShader(gl16UI.FRAGMENT_SHADER);
var displayPlane16UIProgram = gl16UI.createProgram();
gl16UI.shaderSource(displayPlane16UIVertexShader, displayPlane16UIVertexShaderSource);
gl16UI.compileShader(displayPlane16UIVertexShader);
gl16UI.attachShader(displayPlane16UIProgram, displayPlane16UIVertexShader);
gl16UI.shaderSource(displayPlane16UIFragmentShader, displayPlane16UIFragmentShaderSource);
gl16UI.compileShader(displayPlane16UIFragmentShader);
gl16UI.attachShader(displayPlane16UIProgram, displayPlane16UIFragmentShader);
gl16UI.linkProgram(displayPlane16UIProgram);
log = gl16UI.getProgramInfoLog(displayPlane16UIProgram);
if (log) {
    console.log(log);
}

log = gl16UI.getShaderInfoLog(displayPlane16UIVertexShader);
if (log) {
    console.log("Vertex Shader", log);
}

log = gl16UI.getShaderInfoLog(displayPlane16UIFragmentShader);
if (log) {
    console.log("Fragment Shader", log);
}
gl16UI.useProgram(displayPlane16UIProgram);

// Get attribute locations
var displayPlane16UIPositionAttributeLocation = gl16UI.getAttribLocation(displayPlane16UIProgram, "position");
var displayPlane16UIUVAttributeLocation = gl16UI.getAttribLocation(displayPlane16UIProgram, "uv");

// Get uniform locations
var displayPlane16UISamplerLocation = gl16UI.getUniformLocation(displayPlane16UIProgram, "sampler");

// Create and bind VAO
var displayPlane16UIVAO = gl16UI.createVertexArray();
gl16UI.bindVertexArray(displayPlane16UIVAO);

// Create and bind Position Buffer
var displayPlane16UIPositionBuffer = gl16UI.createBuffer();
gl16UI.bindBuffer(gl16UI.ARRAY_BUFFER, displayPlane16UIPositionBuffer);
gl16UI.bufferData(gl16UI.ARRAY_BUFFER, displayPlanePositions, gl16UI.STATIC_DRAW);
gl16UI.enableVertexAttribArray(displayPlane16UIPositionAttributeLocation);
gl16UI.vertexAttribPointer(displayPlane16UIPositionAttributeLocation, 2, gl16UI.FLOAT, false, 0, 0);

// Create and bind UV Buffer
var displayPlane16UIUVBuffer = gl16UI.createBuffer();
gl16UI.bindBuffer(gl16UI.ARRAY_BUFFER, displayPlane16UIUVBuffer);
gl16UI.bufferData(gl16UI.ARRAY_BUFFER, displayPlaneUVs, gl16UI.STATIC_DRAW);
gl16UI.enableVertexAttribArray(displayPlane16UIUVAttributeLocation);
gl16UI.vertexAttribPointer(displayPlane16UIUVAttributeLocation, 2, gl16UI.FLOAT, true, 0, 0);

// Create and bind texture to display
var displayPlane16UITexture = gl16UI.createTexture();
gl16UI.activeTexture(gl16UI.TEXTURE0 + 0);
gl16UI.bindTexture(gl16UI.TEXTURE_2D, displayPlane16UITexture);

gl16UI.pixelStorei(gl16UI.UNPACK_ALIGNMENT, 1);
gl16UI.texImage2D(gl16UI.TEXTURE_2D, 0, gl16UI.RGBA16UI, 3, 2, 0, gl16UI.RGBA_INTEGER, gl16UI.UNSIGNED_SHORT, pixelsRGBA16UI);

gl16UI.texParameteri(gl16UI.TEXTURE_2D, gl16UI.TEXTURE_MIN_FILTER, gl16UI.NEAREST);
gl16UI.texParameteri(gl16UI.TEXTURE_2D, gl16UI.TEXTURE_MAG_FILTER, gl16UI.NEAREST);
gl16UI.texParameteri(gl16UI.TEXTURE_2D, gl16UI.TEXTURE_WRAP_S, gl16UI.CLAMP_TO_EDGE);
gl16UI.texParameteri(gl16UI.TEXTURE_2D, gl16UI.TEXTURE_WRAP_T, gl16UI.CLAMP_TO_EDGE);

// Bind uniforms
gl16UI.uniform1i(displayPlane16UISamplerLocation, 0);

// Execute program
gl16UI.viewport(0, 0, gl16UI.canvas.width, gl16UI.canvas.height);
gl16UI.drawArrays(gl16UI.TRIANGLES, 0, 6);


/* EFFECT PLANE */

// Create and link Program
var effectPlane16UIVertexShader = gl16UI.createShader(gl16UI.VERTEX_SHADER);
var effectPlane16UIFragmentShader = gl16UI.createShader(gl16UI.FRAGMENT_SHADER);
var effectPlane16UIProgram = gl16UI.createProgram();
gl16UI.shaderSource(effectPlane16UIVertexShader, effectPlane16UIVertexShaderSource);
gl16UI.compileShader(effectPlane16UIVertexShader);
gl16UI.attachShader(effectPlane16UIProgram, effectPlane16UIVertexShader);
gl16UI.shaderSource(effectPlane16UIFragmentShader, effectPlane16UIFragmentShaderSource);
gl16UI.compileShader(effectPlane16UIFragmentShader);
gl16UI.attachShader(effectPlane16UIProgram, effectPlane16UIFragmentShader);
gl16UI.linkProgram(effectPlane16UIProgram);
log = gl16UI.getProgramInfoLog(effectPlane16UIProgram);
if (log) {
    console.log(log);
}

log = gl16UI.getShaderInfoLog(effectPlane16UIVertexShader);
if (log) {
    console.log("VERTEX SHADER", log);
}

log = gl16UI.getShaderInfoLog(effectPlane16UIFragmentShader);
if (log) {
    console.log("FRAGMENT SHADER", log);
}
gl16UI.useProgram(effectPlane16UIProgram);

// Get attribute locations
var effectPlane16UIPositionAttributeLocation = gl16UI.getAttribLocation(effectPlane16UIProgram, "position");

// Create and bind VAO
var effectPlane16UIVAO = gl16UI.createVertexArray();
gl16UI.bindVertexArray(effectPlane16UIVAO);

// Create and bind Position Buffer
var effectPlane16UIPositionBuffer = gl16UI.createBuffer();
gl16UI.bindBuffer(gl16UI.ARRAY_BUFFER, effectPlane16UIPositionBuffer);
gl16UI.bufferData(gl16UI.ARRAY_BUFFER, effectPlanePositions, gl16UI.STATIC_DRAW);
gl16UI.enableVertexAttribArray(effectPlane16UIPositionAttributeLocation);
gl16UI.vertexAttribPointer(effectPlane16UIPositionAttributeLocation, 2, gl16UI.FLOAT, false, 0, 0);

// Create and bind target texture
var effectPlane16UITexture = gl16UI.createTexture();
gl16UI.bindTexture(gl16UI.TEXTURE_2D, effectPlane16UITexture);

gl16UI.pixelStorei(gl16UI.UNPACK_ALIGNMENT, 1);
gl16UI.texImage2D(gl16UI.TEXTURE_2D, 0, gl16UI.RGBA16UI, 3, 2, 0, gl16UI.RGBA_INTEGER, gl16UI.UNSIGNED_SHORT, null);

gl16UI.texParameteri(gl16UI.TEXTURE_2D, gl16UI.TEXTURE_MIN_FILTER, gl16UI.NEAREST);
gl16UI.texParameteri(gl16UI.TEXTURE_2D, gl16UI.TEXTURE_MAG_FILTER, gl16UI.NEAREST);
gl16UI.texParameteri(gl16UI.TEXTURE_2D, gl16UI.TEXTURE_WRAP_S, gl16UI.CLAMP_TO_EDGE);
gl16UI.texParameteri(gl16UI.TEXTURE_2D, gl16UI.TEXTURE_WRAP_T, gl16UI.CLAMP_TO_EDGE);

// Create and bind the framebuffer
var framebuffer = gl16UI.createFramebuffer();
gl16UI.bindFramebuffer(gl16UI.FRAMEBUFFER, framebuffer);

// Attach the texture as the first color attachment
gl16UI.framebufferTexture2D(gl16UI.FRAMEBUFFER, gl16UI.COLOR_ATTACHMENT0, gl16UI.TEXTURE_2D, effectPlane16UITexture, 0);
console.log("Render to RGBA16UI Texture:", gl16UI.checkFramebufferStatus(gl16UI.FRAMEBUFFER) === 36053 ? "FRAMEBUFFER_COMPLETE" : "FRAMEBUFFER_INCOMPLETE");

// Execute program
gl16UI.viewport(0, 0, 3, 2);
gl16UI.drawArrays(gl16UI.TRIANGLES, 0, 6);

// Unbind framebuffer
gl16UI.bindFramebuffer(gl16UI.FRAMEBUFFER, null);


/* DISPLAY PLANE RTT */

// Create Program
var displayPlaneRTT16UIVertexShader = gl16UI.createShader(gl16UI.VERTEX_SHADER);
var displayPlaneRTT16UIFragmentShader = gl16UI.createShader(gl16UI.FRAGMENT_SHADER);
var displayPlaneRTT16UIProgram = gl16UI.createProgram();
gl16UI.shaderSource(displayPlaneRTT16UIVertexShader, displayPlaneRTT16UIVertexShaderSource);
gl16UI.compileShader(displayPlaneRTT16UIVertexShader);
gl16UI.attachShader(displayPlaneRTT16UIProgram, displayPlaneRTT16UIVertexShader);
gl16UI.shaderSource(displayPlaneRTT16UIFragmentShader, displayPlaneRTT16UIFragmentShaderSource);
gl16UI.compileShader(displayPlaneRTT16UIFragmentShader);
gl16UI.attachShader(displayPlaneRTT16UIProgram, displayPlaneRTT16UIFragmentShader);
gl16UI.linkProgram(displayPlaneRTT16UIProgram);
log = gl16UI.getProgramInfoLog(displayPlaneRTT16UIProgram);
if (log) {
    console.log(log);
}

log = gl16UI.getShaderInfoLog(displayPlaneRTT16UIVertexShader);
if (log) {
    console.log("VERTEX SHADER", log);
}

log = gl16UI.getShaderInfoLog(displayPlaneRTT16UIFragmentShader);
if (log) {
    console.log("FRAGMENT SHADER", log);
}
gl16UI.useProgram(displayPlaneRTT16UIProgram);

// Get attribute locations
var displayPlaneRTT16UIPositionAttributeLocation = gl16UI.getAttribLocation(displayPlaneRTT16UIProgram, "position");
var displayPlaneRTT16UIUVAttributeLocation = gl16UI.getAttribLocation(displayPlaneRTT16UIProgram, "uv");

// Get uniform locations
var displayPlaneRTT16UISamplerLocation = gl16UI.getUniformLocation(displayPlaneRTT16UIProgram, "sampler");

// Create and bind VAO
var displayPlaneRTT16UIVAO = gl16UI.createVertexArray();
gl16UI.bindVertexArray(displayPlaneRTT16UIVAO);

// Create and bind Position Buffer
var displayPlaneRTT16UIPositionBuffer = gl16UI.createBuffer();
gl16UI.bindBuffer(gl16UI.ARRAY_BUFFER, displayPlaneRTT16UIPositionBuffer);
gl16UI.bufferData(gl16UI.ARRAY_BUFFER, displayPlaneRTTPositions, gl16UI.STATIC_DRAW);
gl16UI.enableVertexAttribArray(displayPlaneRTT16UIPositionAttributeLocation);
gl16UI.vertexAttribPointer(displayPlaneRTT16UIPositionAttributeLocation, 2, gl16UI.FLOAT, false, 0, 0);

// Create and bind UV Buffer
var displayPlaneRTT16UIUVBuffer = gl16UI.createBuffer();
gl16UI.bindBuffer(gl16UI.ARRAY_BUFFER, displayPlaneRTT16UIUVBuffer);
gl16UI.bufferData(gl16UI.ARRAY_BUFFER, displayPlaneRTTUVs, gl16UI.STATIC_DRAW);
gl16UI.enableVertexAttribArray(displayPlaneRTT16UIUVAttributeLocation);
gl16UI.vertexAttribPointer(displayPlaneRTT16UIUVAttributeLocation, 2, gl16UI.FLOAT, true, 0, 0);

// Bind texture to display
gl16UI.activeTexture(gl16UI.TEXTURE0 + 0);
gl16UI.bindTexture(gl16UI.TEXTURE_2D, effectPlane16UITexture);

// Bind uniforms
gl16UI.uniform1i(displayPlaneRTT16UISamplerLocation, 0);

// Execute program
gl16UI.viewport(0, 0, gl16UI.canvas.width, gl16UI.canvas.height);
gl16UI.drawArrays(gl16UI.TRIANGLES, 0, 6);
<!DOCTYPE html>

<html>
<head>
  <meta charset="UTF-8" />
  <title>RGBA16UI RenderTarget</title>
</head>

<body>
  <canvas id="webgl2-opti-tests-16ui" width="512" height="512" style="position: absolute; z-index: 1000;"></canvas>
</body>
</html>

Спасибо, что читаете меня.

1 Ответ

0 голосов
/ 29 июня 2018

Извините, но мне было трудно читать ваш код. Может быть сделать в следующий раз mcve ?

В любом случае вот рабочий образец. Когда вы просто пытаетесь отладить текстуру или рендеринг, проще всего нарисовать одну точку. Тогда вам не нужны никакие атрибуты, объекты массива вершин или буферы. Поскольку существует только одна текстура, вам также не нужно задавать форму сэмплера.

function main() {
  const gl = document.querySelector("canvas").getContext("webgl2");
  if (!gl) {
    return alert("need webgl2");
  }
  
  const vs = `
  #version 300 es
  void main() {
    // use a point as it's easier
    gl_PointSize = 300.0;   // because the canvas is 300x150
    gl_Position = vec4(0, 0, 0, 1);
  }
  `;
  
  const uintFS = `
  #version 300 es
  precision highp float;
  out uvec4 color;
  void main() {
    // will fill texture with values from 0 to 30000
    // if the texture is 300x100 and we're rendering
    // to the entire texture
    color = uvec4(gl_FragCoord.xy, 0, 300) * 100u;
  }
  `;
  
  const uintToFloatFS = `
  #version 300 es
  precision highp float;
  uniform highp usampler2D tex;
  out vec4 color;
  void main() {
    uvec4 data = texture(tex, gl_PointCoord.xy);
    color = vec4(data) / 30000.0;
  }
  `;
  
  // compile shaders 
  const renderUintPrg = twgl.createProgram(gl, [vs, uintFS]);
  const uintToFloatPrg = twgl.createProgram(gl, [vs, uintToFloatFS]);

  // make an 300x150 RGBA16UI texture and attach to framebuffer
  const fbi = twgl.createFramebufferInfo(gl, [
    {internalFormat: gl.RGBA16UI, minMag: gl.NEAREST, },
  ], 300, 150);
  
  // bind framebuffer
  gl.bindFramebuffer(gl.FRAMEBUFFER, fbi.framebuffer);
  
  gl.useProgram(renderUintPrg);
  
  gl.drawArrays(gl.POINTS, 0, 1);
  
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);

  gl.useProgram(uintToFloatPrg);
  
  gl.drawArrays(gl.POINTS, 0, 1);
}
main();
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
...