WebGL drawBuffer 输出黑色纹理
WebGL drawBuffer outputs black textures
我正在尝试借助 drawBuffers 编写简单的 webgl multipass 程序。我创建了 2 个 drawBuffer 纹理并在 fragmentShaderPass1 中为它们分配颜色。 Texture1 应该是绿色,Texture2 应该是棕色。然后我将这些纹理作为统一传递给 fragmentShaderPass2,它使用 Texture1 的颜色来渲染矩形。问题是矩形总是黑色而不是绿色!我在这里做错了什么?
// STAGE 1
let fragmentShaderPass1 = `
#extension GL_EXT_draw_buffers : require
precision highp float;
precision highp int;
precision highp sampler2D;
void main( void )
{
gl_FragData[0] = vec4(.2, .8, .0, 1); // green
gl_FragData[1] = vec4(.6, .5, .4, .3); // brown
}
`;
let pass1_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass1);
let firstStageFrameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, firstStageFrameBuffer);
gl.useProgram(pass1_prog);
for (let i = 0; i < 2; i++)
{
let tex = gl.createTexture();
textures.push(tex);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
// attach texture to framebuffer
gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT0_WEBGL + i, gl.TEXTURE_2D, tex, 0);
}
gl.disable(gl.DEPTH_TEST); // framebuffer doesn't even have a depth buffer!
gl.viewport(0, 0, _this.canvas.width, _this.canvas.height);
ext.drawBuffersWEBGL([
ext.COLOR_ATTACHMENT0_WEBGL,
ext.COLOR_ATTACHMENT1_WEBGL
]);
gl.drawArrays(gl.POINTS, 0, 1);
// STAGE 2
let fragmentShaderPass2 = `
precision highp float;
precision highp int;
precision highp sampler2D;
uniform sampler2D inColor0;
uniform sampler2D inColor1;
void main( void )
{
gl_FragColor = texture2D(inColor0, vec2(0.5));
}
`;
let pass2_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass2);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.useProgram(pass2_prog);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, textures[0]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor0"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, textures[1]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor1"), 1);
gl.drawArrays(gl.POINTS, 0, 1);
您在上面发布的代码不会使您的纹理可渲染并在 the JavaScript console
中出现此错误
RENDER WARNING: texture bound to texture unit 0 is not renderable. It might be non-power-of-2 or have incompatible texture filtering (maybe)?
它们不可渲染,因为它们没有 mips 但设置为使用 mips(默认)。它们也可能不是二维的幂,尽管您没有显示 canvas 的大小,但只是猜测它不是 2 的幂。
使它们可渲染
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
使它们渲染
const canvas = document.querySelector('canvas');
const _this = {canvas};
const textures = [];
const gl = _this.canvas.getContext('webgl');
const ext = gl.getExtension('WEBGL_draw_buffers');
if (!ext) { alert('need WEBGL_draw_buffers'); }
const globals = {
vertexShader: `
void main() {
gl_Position = vec4(0, 0, 0, 1);
gl_PointSize = 100.0;
}
`,
}
// STAGE 1
let fragmentShaderPass1 = `
#extension GL_EXT_draw_buffers : require
precision highp float;
precision highp int;
precision highp sampler2D;
void main( void )
{
gl_FragData[0] = vec4(.2, .8, .0, 1); // green
gl_FragData[1] = vec4(.6, .5, .4, 1); // brown
}
`;
let pass1_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass1);
let firstStageFrameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, firstStageFrameBuffer);
gl.useProgram(pass1_prog);
for (let i = 0; i < 2; i++) {
let tex = gl.createTexture();
textures.push(tex);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// attach texture to framebuffer
gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT0_WEBGL + i, gl.TEXTURE_2D, tex, 0);
}
gl.disable(gl.DEPTH_TEST); // framebuffer doesn't even have a depth buffer!
gl.viewport(0, 0, _this.canvas.width, _this.canvas.height);
ext.drawBuffersWEBGL([
ext.COLOR_ATTACHMENT0_WEBGL,
ext.COLOR_ATTACHMENT1_WEBGL
]);
gl.drawArrays(gl.POINTS, 0, 1);
// STAGE 2
let fragmentShaderPass2 = `
precision highp float;
precision highp int;
precision highp sampler2D;
uniform sampler2D inColor0;
uniform sampler2D inColor1;
void main( void )
{
gl_FragColor = texture2D(inColor0, vec2(0.5));
}
`;
let pass2_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass2);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.useProgram(pass2_prog);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, textures[0]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor0"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, textures[1]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor1"), 1);
gl.drawArrays(gl.POINTS, 0, 1);
// ---
function createProgram(gl, vSrc, fSrc) {
return twgl.createProgram(gl, [vSrc, fSrc]);
}
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
请注意,我将 "brown" 颜色从 vec4(.6, .5, .4, .3)
更改为 vec4(.6, .5, .4, 1)
。 vec4(.6, .5, .4, .3)
是 canvas 的无效颜色,除非您对输出进行更多数学运算或将 canvas 设置为不排除预乘 alpha 颜色。您的输出着色器没有做任何额外的数学运算,也没有显示设置 canvas 的代码。默认情况下,浏览器希望您将预乘颜色值放在 canvas 中。 vec4(.6, .5, .4, .3)
不是预乘 alpha,因为如果它是 r、g 和 b 则不能 > a.
我正在尝试借助 drawBuffers 编写简单的 webgl multipass 程序。我创建了 2 个 drawBuffer 纹理并在 fragmentShaderPass1 中为它们分配颜色。 Texture1 应该是绿色,Texture2 应该是棕色。然后我将这些纹理作为统一传递给 fragmentShaderPass2,它使用 Texture1 的颜色来渲染矩形。问题是矩形总是黑色而不是绿色!我在这里做错了什么?
// STAGE 1
let fragmentShaderPass1 = `
#extension GL_EXT_draw_buffers : require
precision highp float;
precision highp int;
precision highp sampler2D;
void main( void )
{
gl_FragData[0] = vec4(.2, .8, .0, 1); // green
gl_FragData[1] = vec4(.6, .5, .4, .3); // brown
}
`;
let pass1_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass1);
let firstStageFrameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, firstStageFrameBuffer);
gl.useProgram(pass1_prog);
for (let i = 0; i < 2; i++)
{
let tex = gl.createTexture();
textures.push(tex);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
// attach texture to framebuffer
gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT0_WEBGL + i, gl.TEXTURE_2D, tex, 0);
}
gl.disable(gl.DEPTH_TEST); // framebuffer doesn't even have a depth buffer!
gl.viewport(0, 0, _this.canvas.width, _this.canvas.height);
ext.drawBuffersWEBGL([
ext.COLOR_ATTACHMENT0_WEBGL,
ext.COLOR_ATTACHMENT1_WEBGL
]);
gl.drawArrays(gl.POINTS, 0, 1);
// STAGE 2
let fragmentShaderPass2 = `
precision highp float;
precision highp int;
precision highp sampler2D;
uniform sampler2D inColor0;
uniform sampler2D inColor1;
void main( void )
{
gl_FragColor = texture2D(inColor0, vec2(0.5));
}
`;
let pass2_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass2);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.useProgram(pass2_prog);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, textures[0]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor0"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, textures[1]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor1"), 1);
gl.drawArrays(gl.POINTS, 0, 1);
您在上面发布的代码不会使您的纹理可渲染并在 the JavaScript console
中出现此错误RENDER WARNING: texture bound to texture unit 0 is not renderable. It might be non-power-of-2 or have incompatible texture filtering (maybe)?
它们不可渲染,因为它们没有 mips 但设置为使用 mips(默认)。它们也可能不是二维的幂,尽管您没有显示 canvas 的大小,但只是猜测它不是 2 的幂。
使它们可渲染
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
使它们渲染
const canvas = document.querySelector('canvas');
const _this = {canvas};
const textures = [];
const gl = _this.canvas.getContext('webgl');
const ext = gl.getExtension('WEBGL_draw_buffers');
if (!ext) { alert('need WEBGL_draw_buffers'); }
const globals = {
vertexShader: `
void main() {
gl_Position = vec4(0, 0, 0, 1);
gl_PointSize = 100.0;
}
`,
}
// STAGE 1
let fragmentShaderPass1 = `
#extension GL_EXT_draw_buffers : require
precision highp float;
precision highp int;
precision highp sampler2D;
void main( void )
{
gl_FragData[0] = vec4(.2, .8, .0, 1); // green
gl_FragData[1] = vec4(.6, .5, .4, 1); // brown
}
`;
let pass1_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass1);
let firstStageFrameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, firstStageFrameBuffer);
gl.useProgram(pass1_prog);
for (let i = 0; i < 2; i++) {
let tex = gl.createTexture();
textures.push(tex);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// attach texture to framebuffer
gl.framebufferTexture2D(gl.FRAMEBUFFER, ext.COLOR_ATTACHMENT0_WEBGL + i, gl.TEXTURE_2D, tex, 0);
}
gl.disable(gl.DEPTH_TEST); // framebuffer doesn't even have a depth buffer!
gl.viewport(0, 0, _this.canvas.width, _this.canvas.height);
ext.drawBuffersWEBGL([
ext.COLOR_ATTACHMENT0_WEBGL,
ext.COLOR_ATTACHMENT1_WEBGL
]);
gl.drawArrays(gl.POINTS, 0, 1);
// STAGE 2
let fragmentShaderPass2 = `
precision highp float;
precision highp int;
precision highp sampler2D;
uniform sampler2D inColor0;
uniform sampler2D inColor1;
void main( void )
{
gl_FragColor = texture2D(inColor0, vec2(0.5));
}
`;
let pass2_prog = createProgram(gl, globals.vertexShader, fragmentShaderPass2);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.useProgram(pass2_prog);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, textures[0]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor0"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, textures[1]);
gl.uniform1i(gl.getUniformLocation(pass2_prog, "inColor1"), 1);
gl.drawArrays(gl.POINTS, 0, 1);
// ---
function createProgram(gl, vSrc, fSrc) {
return twgl.createProgram(gl, [vSrc, fSrc]);
}
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
请注意,我将 "brown" 颜色从 vec4(.6, .5, .4, .3)
更改为 vec4(.6, .5, .4, 1)
。 vec4(.6, .5, .4, .3)
是 canvas 的无效颜色,除非您对输出进行更多数学运算或将 canvas 设置为不排除预乘 alpha 颜色。您的输出着色器没有做任何额外的数学运算,也没有显示设置 canvas 的代码。默认情况下,浏览器希望您将预乘颜色值放在 canvas 中。 vec4(.6, .5, .4, .3)
不是预乘 alpha,因为如果它是 r、g 和 b 则不能 > a.