ocl*_*yke 4 shader textures webgl
我一直在学习像webglfundamentals这样的 WebGL 教程,但遇到了一个绊脚石 - 我相信我需要使用我创建的纹理将信息直接传递到片段着色器,但我似乎无法正确索引纹理。
目标是传递有关光源(位置和颜色)的信息,这些信息将被纳入片段颜色中。理想情况下,该信息的值和长度都是动态的。
我在这个小提琴中创建了问题的简化版本:WebGL - 数据纹理测试
这是一些代码。
在一次性设置中,我们创建一个纹理,用数据填充它,并在该纹理上应用似乎最简单的设置(没有 mips,没有字节打包问题[?])
// lookup uniforms
var textureLocation = gl.getUniformLocation(program, "u_texture");
// Create a texture.
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// fill texture with 1x3 pixels
const level = 0;
const internalFormat = gl.RGBA; // I've also tried to work with gl.LUMINANCE
// but it feels harder to debug
const width = 1;
const height = 3;
const border = 0;
const type = gl.UNSIGNED_BYTE;
const data = new Uint8Array([
// R, G, B, A (unused) // : 'texel' index (?)
64, 0, 0, 0, // : 0
0, 128, 0, 0, // : 1
0, 0, 255, 0, // : 2
]);
const alignment = 1; // should be uneccessary for this texture, but
gl.pixelStorei(gl.UNPACK_ALIGNMENT, alignment); // I don't think this is hurting
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border,
internalFormat, type, data);
// set the filtering so we don't need mips and it's not filtered
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);
Run Code Online (Sandbox Code Playgroud)
在绘制序列中(只发生一次,但可以想象可以重复),我们强调程序应该使用我们的纹理
// Tell the shader to use texture unit 0 for u_texture
gl.activeTexture(gl.TEXTURE0); // added this and following line to be extra sure which texture is being used...
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(textureLocation, 0);
Run Code Online (Sandbox Code Playgroud)
最后,在片段着色器中,我们尝试可靠地使用一个“纹理元素”作为传达信息的一种方式。我似乎不知道如何可靠地检索我存储在纹理中的值。
precision mediump float;
// The texture.
uniform sampler2D u_texture;
void main() {
vec4 sample_00 = texture2D(u_texture, vec2(0, 0));
// This sample generally appears to be correct.
// Changing the provided data for the B channel of texel
// index 0 seems to add blue as expected
vec4 sample_01 = texture2D(u_texture, vec2(0, 1));
vec4 sample_02 = texture2D(u_texture, vec2(0, 2));
// These samples are how I expected this to work since
// the width of the texture is set to 1
// For some reason 01 and 02 both show the same color
vec4 sample_10 = texture2D(u_texture, vec2(1, 0));
vec4 sample_20 = texture2D(u_texture, vec2(2, 0));
// These samples are just there for testing - I don't think
// that they should work
// choose which sample to display
vec4 sample = sample_00;
gl_FragColor = vec4(sample.x, sample.y, sample.z, 1);
}
Run Code Online (Sandbox Code Playgroud)
使用纹理是实现此目的的最佳方法吗?我也听说过传递向量数组的能力,但纹理似乎更常见。
你应该如何创建纹理?(特别是当我指定“宽度”和“高度”时,我应该指的是生成的纹理元素尺寸还是我将用来构造纹理的 gl.UNSIGNED_BYTE 元素的数量??texImage2D 文档)
当不使用“变化”类型时,您应该如何索引片段着色器中的纹理?(即我只想要一个或多个特定纹理像素的值 - 没有插值[与顶点几乎没有关系])
我暂时已经尽可能多地阅读了这方面的内容。这是一个非详尽的列表:
编辑这是我刚刚找到的另一个资源:Hassles with array access in WebGL, and a Couple of workarounds。让我充满希望。
这真的很困扰我。
提前致谢!
在 WebGL1 中寻址纹理中的各个像素使用以下公式
vec2 pixelCoord = vec2(x, y);
vec2 textureDimension = vec2(textureWidth, textureHeight)
vec2 texcoord = (pixelCoord + 0.5) / textureDimensions;
vec4 pixelValue = texture2D(someSamplerUniform, texcoord);
Run Code Online (Sandbox Code Playgroud)
因为纹理坐标是按边缘计算的。如果您有 2x1 纹理
1.0+-------+-------+
| | |
| A | B |
| | |
0.0+-------+-------+
0.0 0.5 1.0
Run Code Online (Sandbox Code Playgroud)
像素 A 中心的纹理坐标 = 0.25, 0.5。像素B中心的纹理坐标为0.75,0.5
如果您不遵循上面的论坛,而仅使用pixelCoord/textureDimensions,那么您将指向像素之间,并且数学错误将为您带来一个像素或另一个像素。
当然,如果您使用纹理作为数据,您可能还需要设置gl.NEAREST过滤。
在WebGL2中你可以使用texelFetch
ivec2 pixelCoord = ivec2(x, y);
int mipLevel = 0;
vec4 pixelValue = texelFetch(someSamplerUniform, texcoord, mipLevel);
Run Code Online (Sandbox Code Playgroud)
使用数据纹理的工作示例在这里
使用纹理是实现此目的的最佳方法吗?我也听说过传递向量数组的能力,但纹理似乎更常见。
做什么?目前尚不清楚你想做什么。每个像素都会有不同的光源吗?
你应该如何创建纹理?(特别是当我指定“宽度”和“高度”时,我应该指的是生成的纹理元素尺寸还是我将用来构造纹理的 gl.UNSIGNED_BYTE 元素的数量??texImage2D 文档)
做最简单或最需要的事情。例如,如果您想要提取的每项数据有 5 条数据,我可能会将每条数据放在纹理中的单独行上。然后我可以做
vec4 datum1 = texture2D(dataTexture, vec2(indexTexCoordX, rowTexCoordY0);
vec4 datum2 = texture2D(dataTexture, vec2(indexTexCoordX, rowTexCoordY1);
vec4 datum3 = texture2D(dataTexture, vec2(indexTexCoordX, rowTexCoordY2);
vec4 datum4 = texture2D(dataTexture, vec2(indexTexCoordX, rowTexCoordY3);
Run Code Online (Sandbox Code Playgroud)
其中indexTexCoordX和rowTexCoordY0-3是根据上面的forumla计算出来的。rowTexCoordY0-3 甚至可能是常量。
不过,纹理在维度上有限制,因此,如果您有更多数据,那么将适合一维,那么您必须将数据打包得更紧,并进行更多数学运算才能将其拉出来。
请注意,纹理具有缓存,因此理想情况下,您希望提取的数据接近之前提取的数据。如果你每次都跳过纹理来获取下一个值,你的性能就会下降。(当然,它可能仍然比替代解决方案更快,具体取决于您正在做什么)
当不使用“变化”类型时,您应该如何索引片段着色器中的纹理?(即我只想要一个或多个特定纹理像素的值 - 没有插值[与顶点几乎没有关系])
片段着色器唯一变化的输入是变量gl_FragCoord(写入的坐标像素)和gl_PointCoord,仅在绘制时可用POINTS。因此,您必须使用其中之一,否则所有其他值对于所有像素都是恒定的。