WebGL 传递数组着色器
我是 WebGL 的新手,我面临着着色器的一些问题。我想在场景中使用多个光源。我在网上搜索了一下,知道在WebGL中,你不能将数组传递到片段着色器中,所以唯一的方法就是使用纹理。这是我无法弄清楚的问题。
首先,我使用以下代码创建一个 32x32 纹理:
var pix = [];
for(var i=0;i<32;i++)
{
for(var j=0;j<32;j++)
pix.push(0.8,0.8,0.1);
}
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, lightMap);
gl.pixelStorei(gl.UNPACK_ALIGNMENT,1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 32,32,0, gl.RGB, gl.UNSIGNED_BYTE,new Float32Array(pix));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.uniform1i(g_loader.program.set_uniform["u_texture2"],0);
但是,当我尝试访问着色器中的纹理时:
[Fragment Shader]
varying vec2 v_texcoord;
uniform sampler2D u_texture2;
void main(void)
{
vec3 lightLoc = texture2D(u_texture, v_texcoord).rgb;
gl_FragData[0] = vec4(lightLoc,1.0);
}
结果是全黑的。有谁知道如何正确访问或创建纹理?
I'm new to WebGL and I'm facing some problems of the shaders. I wanna do multiple light sources in the scene. I searched online and knew that in WebGL, you can't pass an array into the fragment shader, so the only way is use the texture. Here is the problem I can't figure out.
First, I create a 32x32 texture using the following code:
var pix = [];
for(var i=0;i<32;i++)
{
for(var j=0;j<32;j++)
pix.push(0.8,0.8,0.1);
}
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, lightMap);
gl.pixelStorei(gl.UNPACK_ALIGNMENT,1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 32,32,0, gl.RGB, gl.UNSIGNED_BYTE,new Float32Array(pix));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.uniform1i(g_loader.program.set_uniform["u_texture2"],0);
But however, when I tried to access the texture in the shader:
[Fragment Shader]
varying vec2 v_texcoord;
uniform sampler2D u_texture2;
void main(void)
{
vec3 lightLoc = texture2D(u_texture, v_texcoord).rgb;
gl_FragData[0] = vec4(lightLoc,1.0);
}
The result is totally black. Is there anyone knows how to acces or create the texture correctly?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
直观上,人们会想要实现多个光源,执行如下操作:
但 WebGL 会给出如下错误:
尽管如此,您实际上可以将统一数组传递给片段着色器来表示多个光源。唯一需要注意的是,您需要事先知道这些数组的大小。例如:
是正确的。此外,您还需要确保在 JavaScript 端映射平面数组。因此,不要这样做:
这样做:
然后你做:
一旦你设置了预定义大小的数组,你可以做这样的事情:
我希望这会有所帮助
Intuitively, one would be tempted to implement multiple light sources doing something like this:
But WebGL gives you an error like this:
Nonetheless, you actually can pass uniform arrays to the Fragment Shader to represent multiple light sources. The only caveat is that you need to know beforehand the size that these arrays will have. For example:
Is correct. Also you need to make sure that you map a flat array on the JavaScript side. So instead of doing this:
do this:
Then you do:
Once you set up your arrays with a predefined size you can do things like this:
I hope this can be helpful
您使用
GL_UNSIGNED_BYTE
类型调用glTexImage2D
,但随后给它一个浮点数组 (Float32Array
)。根据规范,这会导致GL_INVALID_OPERATION< /代码> 错误。
您应该将位置从 [0,1] 浮点数转换为 [0,255] 范围内的整数,并使用
Uint8Array
。不幸的是,这会失去一些精度,并且所有位置都需要在 [0,1] 范围内(或者至少在某个固定范围内,稍后您将从纹理中获得的 [0,1] 值转换为该范围)。但我确信 WebGL 目前不支持浮点纹理。编辑:由于您评论中的链接,WebGL 似乎确实支持浮点纹理。因此,使用
GL_FLOAT
类型和Float32Array
也应该可以。但在这种情况下,您必须确保您的硬件也支持浮点纹理(自 ~GeForce 6 起),并且您的 WebGL 实现支持OES_texture_float
扩展。您还可以尝试将过滤器模式设置为
GL_NEAREST
,因为较旧的硬件可能不支持线性过滤的浮点纹理。无论如何,由于您想将纹理用作简单数组,因此您不需要任何插值。You are calling
glTexImage2D
with a type ofGL_UNSIGNED_BYTE
, but then you give it an array of floats (Float32Array
). According to the specification This causes aGL_INVALID_OPERATION
error.You should rather transform your positions from [0,1] floats to integers in the [0,255] range and use a
Uint8Array
. Unfortunately this looses you some precision and all your positions need to be in the [0,1] range (or at least some fixed range, which you later transform the [0,1] values you get from the texture into). But I'm sure to remember that WebGL doesn't support floating point textures at the moment.EDIT: Due to the link in your comment WebGL seems indeed to support floating point textures. So using a type of
GL_FLOAT
and aFloat32Array
should work, too. But in this case you have to make sure your hardware also supports floating point textures (since ~GeForce 6) and your WebGL implementation supports theOES_texture_float
extension.You may also try to set the filter modes to
GL_NEAREST
, as older hardware may not support linearly filtered floating point textures. And as you want to use the texture as a simple array anyway, you shouldn't need any interpolation.请注意,在 WebGL 中,与 OpenGL 相反,您必须显式调用 getExtension,然后才能使用扩展,例如 OES_texture_float。然后你想将 gl.FLOAT 作为类型参数传递给 texImage2D。
Note that in WebGL, contrary to OpenGL, you have to explicitly call getExtension before you can use an extension, like OES_texture_float. And then you want to pass gl.FLOAT as the type parameter to texImage2D.
texImage2D 函数需要图像作为参数,而不是数组。您应该将纹理写入 Canvas,然后使用画布图像作为 texImage2D 参数。
查看此链接:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#pixel-manipulation
The texImage2D function expects and image as parameter, not an array. You should write your texture to a Canvas and then use the canvas image as the texImage2D parameter.
Check out this link:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#pixel-manipulation