我目前正在使用WebGL开发3D引擎,我遇到了灯光着色器的问题。我正在使用一个结构数组,以便将光参数传递给顶点和片段着色器(相同的数组传递为“uniform”)。它实际上适用于Firefox 35,但完全不适用于Google Chrome,我不知道这段代码有什么问题。
以下是顶点着色器的代码:
precision mediump float;
precision mediump int;
struct light{
vec3 ambient;
vec3 specular;
vec3 diffuse;
vec3 vector;
};
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
attribute vec3 aVertexNormal;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat4 uNormalMatrix;
varying vec4 vMaterialColor;
varying vec3 N;
varying vec3 V;
const int MAX_LIGHT = 3;
uniform light lights[MAX_LIGHT];
varying vec3 L[MAX_LIGHT];
uniform int lightCount;
void main(void) {
vec4 position4 = uMVMatrix * vec4(aVertexPosition, 1.0);
vec3 position = position4.xyz / position4.w;
V = normalize(-position);
for(int i = 0 ; i < MAX_LIGHT ; i++){
if (i < lightCount){
L[i] = normalize(lights[i].vector - position);
}
}
N = normalize(vec3(uNormalMatrix * vec4(aVertexNormal,0.0)));
gl_Position = uPMatrix * position4;
vMaterialColor = aVertexColor;
}
片段着色器的代码是:
precision mediump float;
precision mediump int;
varying vec3 N;
varying vec3 V;
struct materialProperties {
vec3 ambient;
vec3 diffuse;
vec3 specular;
vec3 emissive;
float shininess;
};
struct light{
vec3 ambient;
vec3 specular;
vec3 diffuse;
vec3 vector;
};
// Material
varying vec4 vMaterialColor;
uniform materialProperties uMaterial;
// Light
const int MAX_LIGHT = 3;
uniform light lights[MAX_LIGHT];
varying vec3 L[MAX_LIGHT];
uniform int lightCount;
void main(void) {
vec3 color = vec3(0.0);
for(int i = 0; i < MAX_LIGHT ; i++){
if(i < lightCount){
float dot_LN = max(dot(N,L[i]), 0.0);
float specular = 0.0;
if(dot_LN > 0.0){
vec3 H = normalize(L[i]+V);
float dot_HN = max(dot(H, N), 0.0);
specular = pow(dot_HN, uMaterial.shininess);
}
vec3 ambiantComponent = uMaterial.ambient * lights[i].ambient;
vec3 diffuseComponent = uMaterial.diffuse * vMaterialColor.xyz * dot_LN * lights[i].diffuse;
vec3 specularComponent = uMaterial.specular * specular * lights[i].specular;
color += ambiantComponent + diffuseComponent + specularComponent;
}
}
gl_FragColor = vec4(color, vMaterialColor.w);
}
我发送gl.uniformxx的光信息:
for(var i = 0 ; i < light.length ; i++){
gl.uniform3fv(shaderProgram.light[i].vector, light[i]._lightVector);
gl.uniform3fv(shaderProgram.light[i].ambient, light[i].ambient);
gl.uniform3fv(shaderProgram.light[i].specular, light[i].specular);
gl.uniform3fv(shaderProgram.light[i].diffuse, light[i].diffuse);
}
gl.uniform1i(shaderProgram.lightCount, light.length);
使用以下代码声明shaderProgram:
shaderProgram.light = [];
for(var i = 0 ; i < 3 ; i++){
var l = {};
l.ambient = gl.getUniformLocation(shaderProgram,"lights["+i+"].ambient");
l.specular = gl.getUniformLocation(shaderProgram,"lights["+i+"].specular");
l.vector = gl.getUniformLocation(shaderProgram,"lights["+i+"].vector");
l.diffuse = gl.getUniformLocation(shaderProgram,"lights["+i+"].diffuse");
shaderProgram.light.push(l);
}
shaderProgram.lightCount = gl.getUniformLocation(shaderProgram,"lightCount");
Google Chrome渲染的场景是黑色图像,而不是Firefox,可以按预期渲染场景。
您知道此代码中的问题在哪里吗?
修改 以下最小代码提供了相同的错误:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Fail</title>
</head>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
precision mediump int;
struct test_t{
vec3 a;
vec3 b;
vec3 c;
vec3 d;
};
uniform test_t test;
varying vec3 sum;
void main(void) {
gl_FragColor = vec4(test.a+test.b+test.c-sum, 1.0);
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
precision mediump float;
precision mediump int;
struct test_t{
vec3 a;
vec3 b;
vec3 c;
vec3 d;
};
attribute vec3 aVertexPosition;
uniform test_t test;
varying vec3 sum;
void main(void) {
sum = test.a + test.b;
gl_Position = vec4(aVertexPosition,1.0);
}
</script>
<script type="application/javascript">
var canvas, gl, shaderProgram, triangleVertexPositionBuffer;
function start() {
canvas = document.getElementById("webgl-canvas");
initWebGL(canvas); // Initialize the GL context
if (gl) {
gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
gl.clearDepth(1.0); // Clear everything
gl.enable(gl.DEPTH_TEST); // Enable depth testing
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
initShaders();
triangleVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
var vertices = [
0.0, 0.5, -0.5,
-0.5, -0.5, -0.5,
0.5, -0.5, -0.5
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
triangleVertexPositionBuffer.itemSize = 3;
triangleVertexPositionBuffer.numItems = 3;
setInterval(drawScene, 15);
}
}
function initWebGL() {
gl = null;
try {
gl = canvas.getContext("experimental-webgl");
}
catch(e) {
}
if (!gl)
alert("Unable to initialize WebGL");
}
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Unable to initialize the shader program.");
}
gl.useProgram(shaderProgram);
vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(vertexPositionAttribute);
shaderProgram.test = {}
shaderProgram.test.a = gl.getUniformLocation(shaderProgram,"test.a");
shaderProgram.test.b = gl.getUniformLocation(shaderProgram,"test.b");
shaderProgram.test.c = gl.getUniformLocation(shaderProgram,"test.c");
shaderProgram.test.d = gl.getUniformLocation(shaderProgram,"test.d");
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var theSource = "";
var currentChild = shaderScript.firstChild;
while(currentChild) {
if (currentChild.nodeType == 3) {
theSource += currentChild.textContent;
}
currentChild = currentChild.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null; // Unknown shader type
}
gl.shaderSource(shader, theSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
function drawScene() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniform3fv(shaderProgram.test.a, [1.0,0.0,0.0]);
gl.uniform3fv(shaderProgram.test.b, [0.0,1.0,0.0]);
gl.uniform3fv(shaderProgram.test.c, [0.0,0.0,1.0]);
gl.uniform3fv(shaderProgram.test.d, [1.0,1.0,1.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);
}
</script>
<body onload="start()">
<canvas id="webgl-canvas" width="500" height="500"></canvas>
</body>
</html>
三角形为黄色/白色,在Google Chrome上闪烁,在Mozilla Firefox上为蓝色。问题似乎是Windows平台特有的(使用Windows 8.1 x64测试)。
修改:Chrome团队的问题已经reported,应尽快制定解决方案。
答案 0 :(得分:3)
我使用win7 Chrome和IE11以及win8 Chrome和IE11测试了您的最小代码。正如你所说,它不适用于win8 Chrome(但适用于win7 Chrome)。
我做了一些修改以找出问题所在。在顶点和片段着色器中,我看到uniform test_t test
只有属性a = [1,0,0]
,但属性b, c, d
似乎是[0,0,0]
,(或者没有被初始化,所以无论什么值)。
有两个测试:
但两者都在我的Chrome中传递。这可能是因为它们没有涵盖所有可能的设置,而它们的目标仅为vec4。
您可以执行(并且正在为我工作)的临时解决方案是使用vec4
而不是vec3
。或者等到Chrome团队修复它。