2015-11-28 1 views
3

J'ai un problème avec un programme écrit en webgl et je ne sais pas comment le déboguer car la console du navigateur ne montre aucune erreur. Webgl ne dessine rien du tout.Changement de shaders dans webgl

J'ai l'ensemble des shaders suivants:

<script id="shader-fs" type="x-shader/x-fragment"> 
precision mediump float; 

uniform sampler2D uSampler; 

varying vec2 vTextureCoord;  
varying vec3 vEye; 
varying vec3 vNormal; 
uniform vec3 uLightDirection; // Vector direccion de la luz 
uniform vec3 uDirectionalColor; // Color de la luz direcional 

uniform vec3 uColShadeless; 
uniform vec3 uAmbientColor; 
uniform float uKAmbiente; 
uniform vec3 uColDifuso; 
uniform float uKDifuso; 
uniform vec3 uColEspecular; 
uniform float uKEspecular; 
uniform float uGlossiness; 

void main(void) 
{ 
    vec3 normal = normalize(vNormal); 
    float mLambert = max(dot(normal, uLightDirection), 0.0); 
    vec3 vLuzLambert = uDirectionalColor * mLambert; 

    vec3 r = 2.0 * max(dot(normal, uLightDirection), 0.0) * normal - uLightDirection; 
    //vec3 r = reflect(uLightDirection, normal); // <- Da glossines del otro lado también 
    float specular = pow(max(dot(r, normalize(vEye)), 0.0), uGlossiness) ; 
    vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); 
    vec3 componenteShadeless = uColShadeless * textureColor.rgb * uColDifuso;    // luz autoiluminada * colores difusos 
    vec3 componenteAmbiente = uKAmbiente * uAmbientColor * textureColor.rgb * uColDifuso; // k% * luz ambiente * colores difusos 
    vec3 componenteDifusa = uKDifuso * textureColor.rgb * uColDifuso * vLuzLambert; 
    vec3 componenteEspecular = uKEspecular * specular * uColEspecular ; 
    gl_FragColor = vec4(componenteShadeless + componenteAmbiente + componenteDifusa + componenteEspecular, textureColor.a); 
} 
</script> 

<script id="shader-vs" type="x-shader/x-vertex"> 
attribute vec3 aVertexPosition; 
attribute vec3 aVertexNormal; 
attribute vec2 aTextureCoord; 

uniform mat4 uViewMatrix; 
uniform mat4 uModelMatrix; 
uniform mat4 uPMatrix; 
uniform mat3 uNMatrix; 

varying vec2 vTextureCoord; 
varying vec3 vEye; 
varying vec3 vNormal; 

uniform vec2 aUVOffset; 

void main(void) 
{ 

     // Transformamos al vértice al espacio de la cámara 
     vec4 pos_camera_view = uViewMatrix * uModelMatrix * vec4(aVertexPosition, 1.0); 
     // Transformamos al vértice al espacio de la proyección 
     gl_Position = uPMatrix * pos_camera_view; 
     // Coordenada de textura 
     vTextureCoord.x = aTextureCoord.x + aUVOffset.x; 
     vTextureCoord.y = aTextureCoord.y + aUVOffset.y; 

     // Para iluminación 
     vEye = -vec3(pos_camera_view.xyz); 
     vNormal = uNMatrix * aVertexNormal; 
} 
</script> 

<script id="vs" type="x-shader/x-vertex"> 
     attribute vec3 aPositionL; 
     attribute vec3 aNormalL; 
     attribute vec3 aTangentL; 
     attribute vec2 aTexCoord; 

     uniform mat4 uMatrixMVP; 
     uniform mat4 uMatrixMV; 

     varying vec4 vPositionV; 
     varying vec3 vNormalV; 
     varying vec3 vTangentV; 
     varying vec2 vTexCoord; 

     attribute vec3 aVertexPosition; 
     attribute vec3 aVertexNormal; 
     attribute vec2 aTextureCoord; 

     uniform mat4 uViewMatrix; 
     uniform mat4 uModelMatrix; 
     uniform mat4 uPMatrix; 
     uniform mat3 uNMatrix; 
     varying vec3 vNormal; 

     uniform vec2 aUVOffset; 
     void main(void) 
     { 

     // Transformamos al vértice al espacio de la cámara 
     vec4 pos_camera_view = uViewMatrix * uModelMatrix * vec4(aPositionL, 1.0); 
     // Transformamos al vértice al espacio de la proyección 
     gl_Position = uPMatrix * pos_camera_view; 

     vNormal = uNMatrix * aVertexNormal; 
     vPositionV = uMatrixMV * vec4(aPositionL, 1.0); 
     vNormalV = (uMatrixMV * vec4(aNormalL, 0.0)).xyz; 
     vTangentV = (uMatrixMV * vec4(aTangentL, 0.0)).xyz; 
     vTexCoord = aTexCoord; 
} 
</script> 

<script id="fs" type="x-shader/x-fragment"> 
     #ifdef GL_ES 
     precision highp float; 
     #endif 

     uniform sampler2D uColorSampler; 
     uniform sampler2D uNormalSampler; 
     uniform float uTime; 

     varying vec4 vPositionV; 
     varying vec3 vNormalV; 
     varying vec3 vTangentV; 
     varying vec2 vTexCoord; 

     void main(void) { 
      vec3 diffuse = texture2D(uColorSampler, vTexCoord).rgb; 
      vec3 normalT = texture2D(uNormalSampler, vTexCoord).xyz; 
      normalT.y = 1.0 - normalT.y; 
      normalT = 2.0 * normalT - vec3(1.0, 1.0, 1.0); 
      normalT.z *= 10.0; 

      vec3 binormalV = cross(vNormalV, vTangentV); 
      vec3 normalV = normalT.x * vTangentV + normalT.y * binormalV + normalT.z * vNormalV; 

      normalV = normalize(normalV); 
      vec3 lightV = normalize(vec3(10.0 * cos(uTime), 10.0, 10.0 * sin(uTime))); 

      float d = dot(normalV, lightV); 
      float s = dot(reflect(-lightV, normalV), normalize(-vPositionV.xyz)); 
      s = pow(s, 30.0); 

      vec3 color = diffuse * (0.1 + 0.5 * d + 0.4 * s); 

      gl_FragColor = vec4(color, 1.0); 
     } 

Alors vs et fs sont shaders utilisés pour dessiner une surface avec une texture de carte normale. J'utilise shader-fs et shader-vs pour le reste du code.

Le code suivant est utilisé pour initialiser les shaders et les changer:

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("Could not initialise shaders"); 
    } 

    initShaders2(); 
} 

function changeShaderBasic() 
{ 

    gl.useProgram(shaderProgramMap); 

    gl.disableVertexAttribArray(shaderProgramMap.aPositionL); 
    gl.disableVertexAttribArray(shaderProgramMap.aNormalL); 
    gl.disableVertexAttribArray(shaderProgramMap.aTangentL); 
    gl.disableVertexAttribArray(shaderProgramMap.aTexCoord); 

    gl.useProgram(shaderProgram); 

    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); 
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); 

    shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); 
    gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); 

    shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal"); 
gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute); 

    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix"); 
    shaderProgram.ViewMatrixUniform = gl.getUniformLocation(shaderProgram, "uViewMatrix"); 
    shaderProgram.ModelMatrixUniform = gl.getUniformLocation(shaderProgram, "uModelMatrix"); 
    shaderProgram.nMatrixUniform = gl.getUniformLocation(shaderProgram, "uNMatrix"); 
    shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler"); 

    shaderProgram.ambientColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientColor"); // Color ambiente 
    shaderProgram.lightingDirectionUniform = gl.getUniformLocation(shaderProgram, "uLightDirection"); // Direccion de la luz 
    shaderProgram.directionalColorUniform = gl.getUniformLocation(shaderProgram, "uDirectionalColor"); // Color de la luz 

    shaderProgram.shadelessColorUniform = gl.getUniformLocation(shaderProgram, "uColShadeless"); 
    shaderProgram.ambientKUniform = gl.getUniformLocation(shaderProgram, "uKAmbiente"); 
    shaderProgram.diffuseColorUniform = gl.getUniformLocation(shaderProgram, "uColDifuso"); 
    shaderProgram.diffuseKUniform = gl.getUniformLocation(shaderProgram, "uKDifuso"); 
    shaderProgram.specularColorUniform = gl.getUniformLocation(shaderProgram, "uColEspecular"); 
    shaderProgram.specularKUniform = gl.getUniformLocation(shaderProgram, "uKEspecular"); 
    shaderProgram.specularGlossiness = gl.getUniformLocation(shaderProgram, "uGlossiness");  

    shaderProgram.uvOffsetUniform = gl.getUniformLocation(shaderProgram, "aUVOffset"); 

} 



function initShaders2() { 

      var vs = getShader(gl,'vs'); 
      var fs = getShader(gl,'fs'); 

      shaderProgramMap = gl.createProgram(); 
      gl.attachShader(shaderProgramMap, vs); 
      gl.attachShader(shaderProgramMap, fs); 
      gl.linkProgram(shaderProgramMap); 

      if (!gl.getProgramParameter(shaderProgramMap, gl.LINK_STATUS)) { 
       alert('Could not link the shader normal program.'); 
       return; 
      } 
} 


function changeShaderNormal() 
{ 
    gl.useProgram(shaderProgram); 
    gl.disableVertexAttribArray(shaderProgram.vertexPositionAttribute); 
    gl.disableVertexAttribArray(shaderProgram.textureCoordAttribute); 
    gl.disableVertexAttribArray(shaderProgram.vertexNormalAttribute); 

    gl.useProgram(shaderProgramMap); 

    shaderProgramMap.ViewMatrixUniform = gl.getUniformLocation(shaderProgramMap, "uViewMatrix"); 
    shaderProgramMap.ModelMatrixUniform = gl.getUniformLocation(shaderProgramMap, "uModelMatrix"); 
    shaderProgramMap.aPositionL = gl.getAttribLocation(shaderProgramMap, 'aPositionL'); 
    gl.enableVertexAttribArray(shaderProgramMap.aPositionL); 
    shaderProgramMap.aNormalL = gl.getAttribLocation(shaderProgramMap, 'aNormalL'); 
    gl.enableVertexAttribArray(shaderProgramMap.aNormalL); 
    shaderProgramMap.aTangentL = gl.getAttribLocation(shaderProgramMap, 'aTangentL'); 
    gl.enableVertexAttribArray(shaderProgramMap.aTangentL); 
    shaderProgramMap.aTexCoord = gl.getAttribLocation(shaderProgramMap, 'aTexCoord'); 
    gl.enableVertexAttribArray(shaderProgramMap.aTexCoord); 
    shaderProgramMap.uMatrixMVP = gl.getUniformLocation(shaderProgramMap, 'uMatrixMVP'); 
    shaderProgramMap.uMatrixMV = gl.getUniformLocation(shaderProgramMap, 'uMatrixMV'); 
    shaderProgramMap.uColorSampler = gl.getUniformLocation(shaderProgramMap, 'uColorSampler'); 
    shaderProgramMap.uNormalSampler = gl.getUniformLocation(shaderProgramMap, 'uNormalSampler'); 
    shaderProgramMap.uTime = gl.getUniformLocation(shaderProgramMap, 'uTime'); 
} 

J'appelle la fonction « changeShaderBasic » d'abord, et quand je veux dessiner une surface avec une carte normale je fais quelque chose comme ça :

changeShaderNormal(); 
*Draw the surface* 
changeShaderBasic(); 

Si je supprime cette partie du code, il ŒUVRES donc shader-fs shaders et shaders vs semblent fonctionner très bien. Le problème semble être les autres shaders (vs et fs) ou la fonction qui bascule entre les shaders.

J'ai omis la partie du code que le programme utilise pour créer des textures.

Je ne sais pas ce que je fais mal et je ne sais pas comment trouver le problème.

+0

Vous devriez vraiment vérifier les valeurs de retour de 'getAttribLocation' pour' -1' et 'getUniformLocation' pour' null' dans le cas où ils ne sont pas trouvés. – Kenney

+0

Je viens de tous les vérifier et le problème persiste. Merci pour votre suggestion. – Kuranes

+0

Je vois que vous 'disableVertexAttribArray (shaderProgram.vertexPositionAttribute)', mais ne l'activez pas sur 'shaderProgramMap.vertexPositionAttribute'; vous ne l'avez pas initialisé non plus. Et la même chose pour les coords tex et normaux de vertex. – Kenney

Répondre

3

Le problème est que certains paramètres de shader de shaderProgramMap ne sont pas activés. Par exemple, il y a

shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); 
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); 

et

gl.disableVertexAttribArray(shaderProgram.vertexPositionAttribute); 

mais rien pour shaderProgramMap, qui » script a également l'attribut aVertexPosition.

Lorsque vous commencez à obtenir ce genre de problèmes, où vous ne peut pas trouver ce qui ne va pas avec le code que vous avez écrit , il est parce que le code n'est plus clair: la vue d'ensemble est perdu. Il y a du code en double: la même chose est faite deux fois, à savoir compiler, lier et configurer un Shader. Ensuite, il est temps de refactoriser: extraire tout le code dupliqué, et paramétrer ce qui est différent.

Il existe plusieurs étapes possibles. L'une consiste à extraire les paramètres du shader: attributes et uniforms.
Le code ci-dessous va produire un hashmap de paramètres avec des informations sur tous les paramètres de la source shader. Remarque, il peut ne pas couvrir toutes les possibilités, mais c'est simplement pour vous donner une idée.

function initShaderParams(gl, shaderProgram, vs, fs) 
{ 
    /** We'll be returning this: */ 
    var params = { 
     uniform:{}, 
     attribute:{}, 

     uniforms: function(arr) { 
      for (var a in arr) 
       if (params.uniform[a]) 
        params.uniform[ a ].set(arr[a]); 
       else throw new Error("unknown uniform '"+a+"' referenced in shader " + vs+"+"+fs 
        + ";\navailable uniforms: " + Object.keys(params.uniform) 
       ); 
     }, 

     enable: function() { 
      for (var a in this.attribute) 
       gl.disableVertexAttribArray(this.attribute[a]); 
     } 

     // disable: .... 
    }; 


    /** returns a function to set the value of a uniform given it's type */ 
    function getUniformFN(type) { 
     switch (type) { 
      case 'vec2': return function(v){gl.uniform2f(this.loc, false, v[0], v[1]);}; 
      case 'mat4': return function(v){gl.uniformMatrix4fv(this.loc, false, v);}; 
      default: 
       throw new Error("unknown uniform type " + type + " in shader " + vs+"+"+fs); 
     } 
    } 

    /** same, for attributes. */ 
    function getAttributeFN(type) { 
     switch (type) { 
      case 'vec2': return function(v){ gl.bindBuffer(gl.ARRAY_BUFFER, v); gl.vertexAttribPointer(this.loc, 2, gl.FLOAT, false, 0, 0); }; 
      case 'vec3': return function(v){ gl.bindBuffer(gl.ARRAY_BUFFER, v); gl.vertexAttribPointer(this.loc, 3, gl.FLOAT, false, 0, 0); }; 
      case 'vec4': return function(v){ gl.bindBuffer(gl.ARRAY_BUFFER, v); gl.vertexAttribPointer(this.loc, 4, gl.FLOAT, false, 0, 0); }; 
      default: 
       throw new Error("unknown uniform type " + type + " in shader " + vs+"+"+fs); 
     } 
    } 

    /** Utility method to map a regex callback */ 
    function regexMap(regex, text, callback) { 
     while ((result = regex.exec(text)) != null) 
      callback(result); 
    } 

    // extract parameters: 

    var src = vs + fs; 

    regexMap(/(uniform)\s+(\w+)\s+(\w+)(\[\d+\])?\s*;/g, src, function(groups) { 
     var loc = gl.getUniformLocation(shaderProgram, groups[3]); 
     if (loc == null) { 
      console.warn("declared ", groups[0], " not used"); 
      return; 
     } 

     params.uniform[ groups[3] ] = { 
      type: groups[2], 
      loc: loc, 
      set: getUniformFN(groups[2]) 
     }; 
    }); 

    regexMap(/(attribute)\s+(\w+)\s+(\w+)\s*;/g, src, function(groups) { 
     var loc = gl.getAttribLocation (shaderProgram, groups[3]); 
     if (loc == -1) { 
      console.warn("declared ", groups[0], " not used"); 
      return; 
     } 
     params.attribute[ groups[3] ] = { 
      type: groups[2], 
      loc: loc, 
      set: getAttributeFN(groups[2]) 
     }; 
    }); 

    return params; 
} 

L'appel de cette méthode aurez accès aux paramètres de shaders, et vous pouvez itérer sur eux, ou les mettre à la fois:

var params = initShaderParams(gl, shaderProgram, vsSource, fsSource); 

params.uniforms({ 
    uViewMatrix: ..., 
    uModelMatrix: ..., 
    ... 
}); 

De cette façon, le code devient plus clair , et il sera plus facile de repérer ce qui manque. Vous pouvez même écrire une fonction pour le faire pour vous: calculate the intersection des clés params.uniforms et les paramètres donnés pour voir si tous sont spécifiés, ou garder une trace de s'ils sont définis en utilisant une fonction de réglage. Bien sûr, il y a beaucoup d'autres façons; vous pouvez également créer une classe Shader et remplacer les méthodes.

Le codage copier-coller conduit à un code non supportable. En règle générale, chaque fois que vous devez programmer deux fois, vous le faites une fois trop souvent.