0

我正在尝试从ArrayBuffer包含 1 个组件的图像创建 2D 纹理。而且我想这样做而不将其复制到 4 个组件图像中。我想知道两者是否可行webglwebgl2对 webgl2 有更多希望)。

webgl 1

我试过这个

gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width, height, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, pixelData);

正如文档所说,我尝试了两个gl.LUMINANCEansgl.LUMINANCE_ALPHA

每个颜色分量都是...

gl.ALPHA例如它说的相反:

丢弃红色、绿色和蓝色分量并读取 alpha 分量

由此看来,很明显gl.ALPHA会期望一个 4 个组件的图像,而gl.LUMINANCE只会gl.LUMINANCE_ALPHA期望 1 个组件。
但是当我执行以下操作时,我收到一个错误,告诉我缓冲区太小。如果我传入一个大小为 4 倍的缓冲区,则不会出现错误,因此它似乎也期待一个 4 分量图像。

我还尝试将宽度和高度除以 4,以为我可以在我的着色器上超越纹理坐标,但得出的结论是,这对于插值来说可能是个坏主意,或者我必须自己做。

webgl 2

所以我对 webgl 1 没有太多期望,但我很确定使用 webgl2 会很容易。但不幸的是,以下方法不起作用:

gl.texImage2D(gl.TEXTURE_2D, 0, gl.R8, this.image.width, this.image.height, 0, gl.RED, gl.UNSIGNED_BYTE, pixelData);

它正在做同样的抱怨缓冲区太小并且不会在缓冲区大 4 倍时抛出任何错误。

那么是否有可能使用任何(或两个)版本,或者我注定要创建一个包含 4 个组件的临时图像?

4

1 回答 1

1

你在读什么样的文档?您提供的所有引用ArrayBuffers都不是真实的,并且在 WebGL(1) 规范中找不到它们。 ALPHA并且LUMINANCE都是单通道格式,每个像素只需要一个值,它们之间唯一有效的区别是您可以在着色器中访问哪些组件。LUMINANCE_ALHPA然而是通道格式(第一个通道映射到rgb,第二个映射到a)。

现在对于您的实际问题,WebGL 1 和 2 都允许通过 提交单个组件数据texImage2D,但是两者都默认为UNPACK_ALIGNMENT4(字节)。

指定内存中每个像素行开头的对齐要求。允许的值为 1(字节对齐)、2(与偶数字节对齐的行)、4(字对齐)和 8(行从双字边界开始)。

OpenGL ES 3.0 手册页

通过该方法将设置UNPACK_ALIGNMENT为 1(字节)可以pixelStorei解决该问题。

ctx.pixelStorei(ctx.UNPACK_ALIGNMENT,1);

但请注意:这是一个全局设置(未绑定到活动纹理),可能会导致纹理数据的性能损失,这些数据可以通过更好的对齐方式解包。因此,您应该确定每个纹理案例的最佳解包对齐方式(考虑格式和数据类型)并相应地设置对齐方式。

var ctx=canvas.getContext('webgl');
// Create alpha texture
var tex = ctx.createTexture();
ctx.bindTexture(ctx.TEXTURE_2D, tex);
ctx.pixelStorei(ctx.UNPACK_ALIGNMENT,1);
ctx.texImage2D(ctx.TEXTURE_2D,0,ctx.ALPHA,2,2,0,ctx.ALPHA,ctx.UNSIGNED_BYTE,new Uint8Array([0,128,128,0]));
ctx.texParameteri(ctx.TEXTURE_2D,ctx.TEXTURE_MIN_FILTER,ctx.NEAREST);
ctx.texParameteri(ctx.TEXTURE_2D,ctx.TEXTURE_MAG_FILTER,ctx.NEAREST);

// Create screenspace shader program
var
  vshader=ctx.createShader(ctx.VERTEX_SHADER),
  fshader=ctx.createShader(ctx.FRAGMENT_SHADER),
  program=ctx.createProgram()
;
ctx.shaderSource(vshader,`
  attribute vec2 vPosition;
  void main() {
    gl_Position=vec4(vPosition,0,1);
  }
`);
ctx.compileShader(vshader);
ctx.attachShader(program,vshader);
ctx.shaderSource(fshader,`
  precision mediump float;
  uniform sampler2D tex;
  void main(){
    gl_FragColor=vec4(texture2D(tex,gl_FragCoord.xy*.05));
  }
`);
ctx.compileShader(fshader);
ctx.attachShader(program,fshader);
ctx.linkProgram(program);

// Create and bind screenspace geometry
ctx.bindBuffer(ctx.ARRAY_BUFFER, ctx.createBuffer());
ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array([
  -1,1, 1,1, 1,-1, -1,-1,
  -1,1, -1,-1, 1,-1, 1,1
]), ctx.STATIC_DRAW);
ctx.enableVertexAttribArray(0);
ctx.vertexAttribPointer(0,2,ctx.FLOAT,false,0,0);

// Render
ctx.useProgram(program);
ctx.drawArrays(ctx.TRIANGLE_FAN,0,4);
canvas {outline:1px solid red;position:absolute;left:50%;transform:translateX(-50%);}
html{background:#aaa;}
<canvas id="canvas"></canvas>

于 2017-07-10T00:48:30.100 回答