WebGL 传递数组着色器

发布于 2024-12-09 03:29:51 字数 965 浏览 1 评论 0原文

我是 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鸵鸟症 2024-12-16 03:29:51

直观上,人们会想要实现多个光源,执行如下操作:

uniform int NUM_LIGHTS;
uniform vec3 uLa[NUM_LIGHTS]; 

但 WebGL 会给出如下错误:

ERROR: 0:12: ":constant expression required
ERROR: 0:12: ":array size must be a constant integer expression"

尽管如此,您实际上可以将统一数组传递给片段着色器来表示多个光源。唯一需要注意的是,您需要事先知道这些数组的大小。例如:

const int NUM_LIGHTS = 5;
uniform vec3  uLa[NUM_LIGHTS];   //ambient
uniform vec3  uLd[NUM_LIGHTS];   //diffuse
uniform vec3  uLs[NUM_LIGHTS];   //specular

是正确的。此外,您还需要确保在 JavaScript 端映射平面数组。因此,不要这样做:

var ambientLightArray = [[0.1,0.1,0.1][0.1,0.1,0.1],...]

这样做:

var ambientLightArray = [0.1,0.1,0.1,0.1,0.1,0.1,..]

然后你做:

var location = gl.getUniformLocation(prg,"uLa");
gl.uniform3fv(location, ambientLightArray);

一旦你设置了预定义大小的数组,你可以做这样的事情:

//Example: Calculate diffuse contribution from all lights to the current fragment
//vLightRay[] and vNormal are varyings calculated in the Vertex Shader
//uKa and uKd are material properties (ambient and diffuse)

vec3 COLOR = vec3(0.0,0.0,0.0);
vec3 N = normalize(vNormal);
for(int i = 0; i < NUM_LIGHTS; i++){    
   L = normalize(vLightRay[i]);     
   COLOR += (uLa[i] * uKa) + (uLd[i] * uKd * clamp(dot(N, -L),0.0,1.0));
}   
gl_FragColor =  vec4(COLOR,1.0);

我希望这会有所帮助

Intuitively, one would be tempted to implement multiple light sources doing something like this:

uniform int NUM_LIGHTS;
uniform vec3 uLa[NUM_LIGHTS]; 

But WebGL gives you an error like this:

ERROR: 0:12: ":constant expression required
ERROR: 0:12: ":array size must be a constant integer expression"

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:

const int NUM_LIGHTS = 5;
uniform vec3  uLa[NUM_LIGHTS];   //ambient
uniform vec3  uLd[NUM_LIGHTS];   //diffuse
uniform vec3  uLs[NUM_LIGHTS];   //specular

Is correct. Also you need to make sure that you map a flat array on the JavaScript side. So instead of doing this:

var ambientLightArray = [[0.1,0.1,0.1][0.1,0.1,0.1],...]

do this:

var ambientLightArray = [0.1,0.1,0.1,0.1,0.1,0.1,..]

Then you do:

var location = gl.getUniformLocation(prg,"uLa");
gl.uniform3fv(location, ambientLightArray);

Once you set up your arrays with a predefined size you can do things like this:

//Example: Calculate diffuse contribution from all lights to the current fragment
//vLightRay[] and vNormal are varyings calculated in the Vertex Shader
//uKa and uKd are material properties (ambient and diffuse)

vec3 COLOR = vec3(0.0,0.0,0.0);
vec3 N = normalize(vNormal);
for(int i = 0; i < NUM_LIGHTS; i++){    
   L = normalize(vLightRay[i]);     
   COLOR += (uLa[i] * uKa) + (uLd[i] * uKd * clamp(dot(N, -L),0.0,1.0));
}   
gl_FragColor =  vec4(COLOR,1.0);

I hope this can be helpful

久伴你 2024-12-16 03:29:51

您使用 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 of GL_UNSIGNED_BYTE, but then you give it an array of floats (Float32Array). According to the specification This causes a GL_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 a Float32Array 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 the OES_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.

漫漫岁月 2024-12-16 03:29:51

请注意,在 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.

久而酒知 2024-12-16 03:29:51

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文