WebGL传递数组着色器

时间:2011-10-10 07:27:13

标签: arrays textures shader 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);

但是,当我尝试访问着色器中的纹理时:

[片段着色器]

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);

}

结果是全黑的。有没有人知道如何正确访问或创建纹理?

4 个答案:

答案 0 :(得分:3)

直观地说,人们很想实现多个这样的光源:

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);

我希望这会有所帮助

答案 1 :(得分:1)

您正在使用glTexImage2D类型调用GL_UNSIGNED_BYTE,但随后您会为其提供一系列浮点数(Float32Array)。根据{{​​3}},这会导致GL_INVALID_OPERATION错误。

您应该将[0,1]浮点数的位置转换为[0,255]范围内的整数,并使用Uint8Array。不幸的是,这会使您失去一些精度,并且您的所有位置都需要在[0,1]范围内(或至少某个固定范围,您稍后将从纹理中获得的[0,1]值转换为)。但我肯定记得WebGL目前不支持浮点纹理。

编辑:由于评论中的链接,WebGL似乎确实支持浮点纹理。因此,使用GL_FLOATFloat32Array类型也应该有用。但在这种情况下,您必须确保您的硬件也支持浮点纹理(因为~GeForce 6),并且您的WebGL实现支持OES_texture_float扩展。

您也可以尝试将过滤器模式设置为GL_NEAREST,因为较旧的硬件可能不支持线性过滤的浮点纹理。而且,无论如何你想要将纹理用作一个简单的数组,你不需要任何插值。

答案 2 :(得分:1)

请注意,在WebGL中,与OpenGL相反,您必须在使用扩展名之前显式调用getExtension,例如OES_texture_float。然后你想把gl.FLOAT作为类型参数传递给texImage2D。

答案 3 :(得分:-1)

texImage2D函数需要和image作为参数,而不是数组。您应该将纹理写入Canvas,然后使用画布图像作为texImage2D参数。

点击此链接:

http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#pixel-manipulation