A vertex shader:
//WebGL Vertex Shader
uniform mat4 uMVMatrix; // Model-view matrix
uniform mat4 uPMatrix; // Projection matrix
uniform mat4 uNMatrix; // Normal matrix
attribute vec3 aVertexPosition; // Vertex position in object space
attribute vec3 aVertexNormal; // Vertex normal in object space
varying vec3 vPosition; // Vertex position (camera space)
varying vec3 vNormal; // Vertex normal (camera space)
void main(void) {
vec4 camSpacePosition = uMVMatrix * vec4(aVertexPosition, 1.0);
vPosition = vec3(camSpacePosition);
gl_Position = uPMatrix * camSpacePosition;
vec4 camSpaceNormal = uNMatrix * vec4(aVertexNormal, 0.0);
vNormal = vec3(camSpaceNormal);
}
Three.js has built-in attributes, so:
//Three.js Vertex Shader
/*
built-in attributes and uniforms
===============================
uMVMatrix -> modelViewMatrix
uPMatrix -> projectionMatrix
uNMatrix -> normalMatrix
aVertexPosition -> position
aVertexNormal -> normal
===============================
*/
varying vec3 vPosition; // Vertex position (camera space)
varying vec3 vNormal; // Vertex normal (camera space)
void main(void) {
vec4 camSpacePosition = modelViewMatrix * vec4(position, 1.0);
vPosition = vec3(camSpacePosition);
gl_Position = projectionMatrix * camSpacePosition;
vec4 camSpaceNormal = normalMatrix * vec4(normal, 1.0);
vNormal = vec3(camSpaceNormal)
}
Example: Phong Shading
viewing: $\hat{o}= \frac{p}{|p|}$
reflected direction: $\hat{r} = 2 \hat{n} \langle \hat{n}, \hat{i} \rangle - \hat{i}$
fragColor=
\left
{
\begin{array}{ll}
k_{d} ( I \cdot \langle \hat{n} , \hat{i} \rangle) + I \cdot max(\langle \hat{o}, \hat{r} \rangle, 0)^{\alpha} , \qquad \langle \hat{n}, \hat{i}\rangle > 0 \
k_{d}c_{0}\
\end{array}
\right
//WebGL Fragment Shader (or Three.js)
precision mediump float;
// the uniform can be defined in custome shaderMaterial
uniform vec3 uLightPos; // Light position in camera space
uniform float uLightPower; // Light power
uniform vec3 uDiffuseColor; // Diffuse color
uniform float uExponent; // Phong exponent
uniform float uAmbient; // Ambient
varying vec3 vPosition; // Fragment position (camera space)
varying vec3 vNormal; // Fragment normal (camera space)
void main(void) {
vec3 L = normalize(uLightPos - vPosition); // i, light direction
vec3 N = normalize(vNormal); // n, normalized normal vector
vec3 V = -normalize(vPosition); // o, viewing direction
vec3 R = normalize(-reflect(L, N)); // r, reflected direction
float intensity = uLightPower/(pow(length(uLightPos - vPosition), 2.0)/5.0+5.0);
vec3 color;
if (dot(N, L) > 0.0)
{
color = uDiffuseColor * (intensity * dot(N, L) + uAmbient);
color += intensity * pow(max(dot(V, R), 0.0), uExponent);
}
else
{
color = uDiffuseColor * uAmbient;
}
gl_FragColor = vec4(color, 1.0);
}