我是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);
}
结果是全黑的。有没有人知道如何正确访问或创建纹理?
答案 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_FLOAT
和Float32Array
类型也应该有用。但在这种情况下,您必须确保您的硬件也支持浮点纹理(因为~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参数。
点击此链接: