在 WebGL2 中渲染为 16 位无符号整数 2D 纹理
Render to 16bits unsigned integer 2D texture in WebGL2
如 WebGL 2 官方规范或文档 (look here) 中所述,gl.RGBA16UI 内部尺寸格式是一种颜色可渲染格式。这意味着我应该能够渲染到 RGBA16UI 纹理。
我可以轻松地用 UInt16Array 填充纹理然后使用它。但是我无法使用着色器将纹理渲染填充到其中。然后,当我在下一个着色器中对值进行采样时,我只会得到零。
有没有人已经成功地使用 WebGL 2 渲染到无符号整数纹理?我将不胜感激,我已经玩了几个星期的纹理格式,但我不知道我在这里做错了什么......而且我没有在关于这个主题的其他 SO 问题中发现我的错误。
您可以在下面的代码片段中找到完整的代码。左侧打印的 6 种颜色是显示填充有 UInt16Array 的 RGBA16UI 纹理的结果。在右侧,如果渲染到 RGBA16UI 纹理成功,我们应该得到相同的结果。
[编辑] 那只是一个愚蠢的错字。我更新了我的代码并接受了 gman 答案作为如何在 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>
感谢阅读。
抱歉,我发现很难阅读您的代码。也许 make an mcve next time?
无论如何,这是一个工作示例。当您只是尝试调试纹理或渲染时,最简单的方法是只绘制一个点。然后你不需要任何属性或顶点数组对象或缓冲区。由于只有一种纹理,因此您也不需要设置采样器制服。
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>
如 WebGL 2 官方规范或文档 (look here) 中所述,gl.RGBA16UI 内部尺寸格式是一种颜色可渲染格式。这意味着我应该能够渲染到 RGBA16UI 纹理。
我可以轻松地用 UInt16Array 填充纹理然后使用它。但是我无法使用着色器将纹理渲染填充到其中。然后,当我在下一个着色器中对值进行采样时,我只会得到零。
有没有人已经成功地使用 WebGL 2 渲染到无符号整数纹理?我将不胜感激,我已经玩了几个星期的纹理格式,但我不知道我在这里做错了什么......而且我没有在关于这个主题的其他 SO 问题中发现我的错误。
您可以在下面的代码片段中找到完整的代码。左侧打印的 6 种颜色是显示填充有 UInt16Array 的 RGBA16UI 纹理的结果。在右侧,如果渲染到 RGBA16UI 纹理成功,我们应该得到相同的结果。
[编辑] 那只是一个愚蠢的错字。我更新了我的代码并接受了 gman 答案作为如何在 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>
感谢阅读。
抱歉,我发现很难阅读您的代码。也许 make an mcve next time?
无论如何,这是一个工作示例。当您只是尝试调试纹理或渲染时,最简单的方法是只绘制一个点。然后你不需要任何属性或顶点数组对象或缓冲区。由于只有一种纹理,因此您也不需要设置采样器制服。
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>