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.
A uniform is a global Shader variable declared with the "uniform" storage qualifier. These act as parameters that the user of a shader program can pass to that program. Their values are stored in a program object.
Fragment shader reads a value from the same variable, automatically interpolated to that fragment. No need to declare these in the Java program.
Attributes are GLSL variables which are only available to the vertex shader (as variables) and the JavaScript code. Attributes are typically used to store color information, texture coordinates, and any other data calculated or retrieved that needs to be shared between the JavaScript code and the vertex shader.
The difference between vertex and fragment shaders is the process developed in the render pipeline. Vertex shaders could be define as the shader programs that modifies the geometry of the scene and made the 3D projection. Fragment shaders are related to the render window and define the color for each pixel.
For uniforms, the short answer is the following:
In the vertex shader
"uniform mat4 modelMatrix;",
"uniform mat4 modelViewMatrix;",
"uniform mat4 projectionMatrix;",
"uniform mat4 viewMatrix;",
"uniform mat3 normalMatrix;",
"uniform vec3 cameraPosition;",
and in the fragment shader
"uniform mat4 viewMatrix;",
"uniform vec3 cameraPosition;",
For the complete answer, involving uniforms and attributes, your custom shaders have the string variables prefixVertex
and prefixFragment
pre-appended.
var vertexGlsl = prefixVertex + vertexShader;
var fragmentGlsl = prefixFragment + fragmentShader;
var glVertexShader = THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
var glFragmentShader = THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
The prefixVertex
and prefixFragment
variable definitions can be found in WebGLProgram.js
or in the non-minified version of three.js
.
EDIT: Updated to three.js r.73
The uniforms you can use in your shaders all depend on how you setup your material: have you enable lights ? vertex colors ? skinning ? ...
Three JS creates a program that depends heavily on some defines (#ifdef in the code) that are injected at the top of the program depending on the parameters I have spoken about above.
I found the best way to know what is going on is to print the shaders that three JS generates: as you already know GLSL, you will understand easily what the code means and what uniforms you can use. Look for buildProgram
in three JS sources, then (r57):
var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );
After those lines, add:
console.log("fragment shader:", prefix_fragment + fragmentShader);
console.log("vertex shader:", prefix_vertex + vertexShader);
And you will be able to see the content of the shaders.
[EDIT] Rereading your question, I realize I answered a bit off, as you create your own shaders...
You can have a look at lines 6463 and 6490 of WebGLRenderer (https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L6463): you will see standard uniforms / attributes that three JS inject in your shaders. You can have a look to the Wiki where you have an entry about that (https://github.com/mrdoob/three.js/wiki - Which default attributes / uniforms / varyings are available in custom shaders?) but it directs you to the lines I outlined above.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With