我一直在尝试使用基于整数的纹理(见这个问题的上下文),但我无法设法从基于浮点数的纹理gl.RGBA/gl.RGBA过渡到gl.RGBA8UI/gl.RGBA_INTEGER。
我已经将sampler2D替换为usampler2D,vec4改为uvec4 (用于fragColor),重写了纹理格式,但没有绘制任何内容。我也不能使用glClear,并显示了错误:glClear: can't be called on integer buffers。在使用基于整数的纹理时,有什么需要考虑的特性吗?
编辑:它似乎是在谷歌Chrome上工作,而不是在Firefox上?
const baseImage = new Image();
baseImage.src = 'https://i.imgur.com/O6aW2Tg.png';
baseImage.crossOrigin = 'anonymous';
baseImage.onload = function() {
render(baseImage);
};
const vertexShaderSource = `#version 300 es
precision mediump float;
in vec2 position;
out vec2 textureCoordinate;
void main() {
textureCoordinate = vec2(1.0 - position.x, 1.0 - position.y);
gl_Position = vec4((1.0 - 2.0 * position), 0, 1);
}`;
const fragmentShaderSource = `#version 300 es
precision mediump float;
precision highp usampler2D;
uniform usampler2D inputTexture;
in vec2 textureCoordinate;
out uvec4 fragColor;
void main() {
fragColor = texture(inputTexture, textureCoordinate);
}`;
function render(image) {
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl2');
if (!gl) {
return;
}
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1]),
gl.STATIC_DRAW
);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
const program = webglUtils.createProgramFromSources(gl, [
vertexShaderSource,
fragmentShaderSource,
]);
const positionAttributeLocation = gl.getAttribLocation(
program,
'position'
);
const inputTextureUniformLocation = gl.getUniformLocation(
program,
'inputTexture'
);
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(
positionAttributeLocation,
2,
gl.FLOAT,
false,
0,
0
);
gl.bindVertexArray(null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
const rawTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, rawTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8UI, gl.RGBA_INTEGER, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 0);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 0);
const outputTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, outputTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8UI, image.width,
image.height,
0, gl.RGBA_INTEGER, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 0);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 0);
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
outputTexture,
0
);
gl.viewport(0, 0, image.width, image.height);
gl.clearColor(0, 0, 0, 1.0);
// gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.useProgram(program);
gl.uniform1i(inputTextureUniformLocation, 0);
gl.bindVertexArray(vao);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, rawTexture);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.bindVertexArray(null);
const pixels = new Uint8Array(4 * image.width * image.height);
gl.readPixels(
0,
0,
image.width,
image.height,
gl.RGBA_INTEGER,
gl.UNSIGNED_BYTE,
pixels
);
console.log(pixels);
}<canvas id="canvas"></canvas>
<script src="https://webgl2fundamentals.org/webgl/resources/webgl-utils.js"></script>
发布于 2019-01-25 00:57:14
你的代码显示得很好。它在readPixels上失败了,我们可以在JavaScript控制台上看到,火狐打印了错误
Error: WebGL warning: readPixels: Incompatible format or type.这是一个不幸的规范的一部分。
规范列出了您可以创建的所有内部纹理格式,以及可以传递给texImage2D的数据的格式/类型组合,以便将数据上传到每个纹理。但是,反其道而行之,这并不是说你可以使用哪种格式/类型组合来读取像素。
它是这样说的,第4.3.2节
在大多数情况下,只接受两种格式和类型的组合。第一种情况取决于当前绑定呈现面的格式。对于归一化定点渲染曲面,采用组合格式
RGBA和类型UNSIGNED_BYTE.对于有符号整数绘制曲面,接受组合格式RGBA_INTEGER和类型INT。对于无符号整数绘制曲面,接受组合格式RGBA_INTEGER和类型UNSIGNED_INT。 第二种是从表3.2中定义的格式中选择的实现格式,不包括DEPTH_COMPONENT和DEPTH_STENCIL格式。这种格式的格式和类型的值可以通过分别使用符号常量GetIntegervIMPLEMENTATION_COLOR_READ_FORMAT和IMPLEMENTATION_COLOR_READ_TYPE来确定。..。实现选择的格式可以根据当前绑定的读帧缓冲区的选定读取缓冲区的格式而有所不同。 另外,当呈现面的内部格式为RGB10_A2时,可以接受格式RGBA和类型UNSIGNED_INT_2_10_10_10_REV的第三种组合。
表3.2 (您可以在页面上看到在这页上第4表的一个版本)列出了大量的格式/类型组合,需要注意的是,规范没有规定哪种格式/类型组合是有效的。换句话说,它做的是,而不是,比如从表3.2中选择与当前内部格式相对应的格式/类型组合体。相反,它只是说该表中的任何格式/类型组合都是有效的。是的,你读得对。根据规范,您可以上传RGBA/INT纹理,实现可能决定第二种格式是R/FLOAT¯\_(ツ)_/ to
下面是一些代码,用于打印第二个允许的readPixels格式/类型组合,用于RGBA8UI纹理
function main() {
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl2');
if (!gl) {
return alert('need webgl2');
}
const outputTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, outputTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8UI, 4, 4,
0, gl.RGBA_INTEGER, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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 framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
outputTexture,
0
);
console.log(
`format/type: ${
glEnumToString(gl, gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT))
}/${
glEnumToString(gl, gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE))
}`);
}
main();
function glEnumToString(gl, value) {
for (const key in gl) {
if (gl[key] === value) {
return key;
}
}
return `0x${value.toFixed(16)}`;
}<canvas id="canvas"></canvas>
如果我运行上面的代码,Chrome说
format/type: RGBA_INTEGER/UNSIGNED_BYTE但火狐说
format/type: RGBA_INTEGER/UNSIGNED_INT根据规范,两者都是有效的。
如果您想让它在任何地方工作,您需要读取数据,因为上面的规范的第一部分说,无符号整数格式始终支持RGBA_INTEGER/UNSIGNED_INT格式。
更改代码使其在两种浏览器上都能工作。
const baseImage = new Image();
baseImage.src = 'https://i.imgur.com/O6aW2Tg.png';
baseImage.crossOrigin = 'anonymous';
baseImage.onload = function() {
render(baseImage);
};
const vertexShaderSource = `#version 300 es
precision mediump float;
in vec2 position;
out vec2 textureCoordinate;
void main() {
textureCoordinate = vec2(1.0 - position.x, 1.0 - position.y);
gl_Position = vec4((1.0 - 2.0 * position), 0, 1);
}`;
const fragmentShaderSource = `#version 300 es
precision mediump float;
precision highp usampler2D;
uniform usampler2D inputTexture;
in vec2 textureCoordinate;
out uvec4 fragColor;
void main() {
fragColor = texture(inputTexture, textureCoordinate);
}`;
function render(image) {
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl2');
if (!gl) {
return;
}
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1]),
gl.STATIC_DRAW
);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
const program = webglUtils.createProgramFromSources(gl, [
vertexShaderSource,
fragmentShaderSource,
]);
const positionAttributeLocation = gl.getAttribLocation(
program,
'position'
);
const inputTextureUniformLocation = gl.getUniformLocation(
program,
'inputTexture'
);
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(
positionAttributeLocation,
2,
gl.FLOAT,
false,
0,
0
);
gl.bindVertexArray(null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
const rawTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, rawTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8UI, gl.RGBA_INTEGER, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 0);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 0);
const outputTexture = gl.createTexture();
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, outputTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8UI, image.width,
image.height,
0, gl.RGBA_INTEGER, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_BASE_LEVEL, 0);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 0);
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
outputTexture,
0
);
gl.viewport(0, 0, image.width, image.height);
gl.clearColor(0, 0, 0, 1.0);
// gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.useProgram(program);
gl.uniform1i(inputTextureUniformLocation, 0);
gl.bindVertexArray(vao);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, rawTexture);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.bindVertexArray(null);
const pixels = new Uint32Array(4 * image.width * image.height);
gl.readPixels(
0,
0,
image.width,
image.height,
gl.RGBA_INTEGER,
gl.UNSIGNED_INT,
pixels
);
console.log(pixels.slice(0, 40));
}<canvas id="canvas"></canvas>
<script src="https://webgl2fundamentals.org/webgl/resources/webgl-utils.js"></script>
https://stackoverflow.com/questions/54337658
复制相似问题