webgl照明着色器使用firefox而不是chrome

时间:2015-02-28 13:36:51

标签: google-chrome firefox glsl webgl shader

我目前正在使用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,应尽快制定解决方案。

1 个答案:

答案 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],(或者没有被初始化,所以无论什么值)。

有两个测试:

https://www.khronos.org/registry/webgl/sdk/tests/conformance/glsl/misc/shader-with-array-of-structs-uniform.html

https://www.khronos.org/registry/webgl/sdk/tests/conformance/glsl/misc/shader-with-array-of-structs-containing-arrays.html

但两者都在我的Chrome中传递。这可能是因为它们没有涵盖所有可能的设置,而它们的目标仅为vec4。

您可以执行(并且正在为我工​​作)的临时解决方案是使用vec4而不是vec3。或者等到Chrome团队修复它。