Search code examples
three.jsglslshader

ThreeJS predefined shader attributes / uniforms


I have started with ThreeJS's WebGL renderer after doing some "regular" WebGL with no additional libraries + GLSL shaders. I am trying to write custom shaders now in my ThreeJS program and I noticed that ThreeJS takes care of a lot of the standard stuff such as the projection and model / view matrices. My simple vertex shader now looks like this:

// All of these seem to be predefined:
// vec3 position;
// mat4 projectionMatrix;
// mat4 modelViewMatrix;
// mat3 normalMatrix;
// vec3 normal;

// I added this
varying vec3 vNormal;

void main() {
    vNormal = normalMatrix * vec3(normal);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

My question is: Which other variables (I'm assuming they're uniforms) are predefined for vertex and fragment shaders that I could use? Does ThreeJS help out with light vectors / light color for instance (of course assuming I've added one or more lights to my ThreeJS scene)?

Update (Oct. 9, 2014): This question has been getting quite a few views, and the user Killah mentioned that the existing answers did not lead to a solution anymore with the current version of three.js. I added and accepted my own answer, see it below.


Solution

  • This question has been getting quite a few views, and the user Killah mentioned that the existing answers did not lead to a solution anymore with the current version of three.js. This is why I tried solving the problem again, and I'd like to outline a couple of options that I found:

    • The quickest and easiest way (while not very elegant) is to just put a random error in your shader. You will get a console error with the entire shader code, including everything that three.js adds.

    • The better solution is to output the shader source from where it's compiled, namely THREE.WebGLShader (as of the current three.js version, r68). I've done a quick copy and paste that should output all shader sources before they're compiled.

      Add this after including three.js and before your own code:

      THREE.WebGLShader = ( function () {
          var addLineNumbers = function ( string ) {
              var lines = string.split( '\n' );
              for ( var i = 0; i < lines.length; i ++ ) {
                  lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
              }
              return lines.join( '\n' );
          };
          return function ( gl, type, string ) {
              var shader = gl.createShader( type ); 
              console.log(string);
              gl.shaderSource( shader, string );
              gl.compileShader( shader );
              if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {
                  console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
              }
              if ( gl.getShaderInfoLog( shader ) !== '' ) {
                  console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ) );
                  console.warn( addLineNumbers( string ) );
              }
              return shader;
          };
      } )();
      

      Note that this snippet is just copied (and very slightly changed) from the three.js sources and should be removed before actually using the code. Just for debugging!

    • There is one more option that is less invasive: you can inspect your ShaderMaterial after creating and rendering it at least once, like so:

      var material = new THREE.ShaderMaterial({
          uniforms: {
              uColorMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_colors.png') },
              uSpecularMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_spec.png') }, 
              uNormalMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_normal.png') }
          },
          vertexShader: document.getElementById('vShader').innerText,
          fragmentShader: document.getElementById('fShader').innerText
      });
      

      Then, after rendering the object at least once:

      console.log(material.program.attributes);
      console.log(material.program.uniforms);
      

    Hope this helps everyone! Feel free to add your comments if you know more and / or better ways to get your shader code.