Passing PointLight Info to a custom Shader with three.js

It's very straightforward to do what you are asking with three.js

I'm not sure where it falls in your Q[]

Q1

  1. You are still using the shaders, someone else wrote them for you. You only have access to the interface. Under the hood, calling something like MeshBasicMaterial can actually compile a different shader based on what you feed into it. Like, it may not process any UVS and not include them in the shader if there is no map called etc. You still have the power to impact the GPU depending on what you call.
  2. If you are referring to the shader chunks, it's possible to hack stuff here, but it's pretty cumbersome. My advice is to study the code, for example the phong shading and start building your own piece by piece, using the chunks. Look at what goes in, what goes out.
  3. No need to pass attributes. THREE.ShaderMaterial is not entirely built from scratch. It still provides you with quite a bit of stuff, and has a bunch of properties that you can set to get more. The basic attributes for one, are setup for you ie. you don't declare "attribute vec3 position". You can get an array containing all the lights in the scene if you tick the lighting flag as West illustrated, but you can ignore this if for example, you are building a particle shader, or some screen effect. Pretty much every shader is set up to read some basic attributes like 'position' 'uv' 'normal'. You can easily add your own on a procedural mesh, but on an actual model it's not trivial. You get some uniforms by default, you get the entire set of MVP matrices, 'cameraPosition' etc. Writing a phong shader from there is straightforward.

Now for how would you do this. Say that you are following this tutorial and you have this shader:

// same name and type as VS
varying vec3 vNormal;

void main() {


//this is hardcoded you want to pass it from your environment
vec3 light = vec3(0.5, 0.2, 1.0);//it needs to be a uniform

// ensure it's normalized
light = normalize(light);//you can normalize it outside of the shader, since it's a directional light

// calculate the dot product of
// the light to the vertex normal
float dProd = max(0.0,
                dot(vNormal, light));

// feed into our frag colour
gl_FragColor = vec4(dProd, // R
                  dProd, // G
                  dProd, // B
                  1.0);  // A

}

Here's what you need to do:

GLSL

uniform vec3 myLightPos;//comes in
void main(){
    vec3 light = normalize(myLightPos);//but you better do this in javascript and just pass the normalized vec3
}

Javascript

new THREE.ShaderMaterial({
   uniforms:{
      myLightPos:{
         type:"v3",
         value: new THREE.Vector3()
      }
   },
   vertexShader: yourVertShader,
   fragmentShader: yourFragmentShader

});

Q1: Correct. Although, some users on this board have posted work-arounds for hacking MeshPhongMaterial, but that is not the original intent.

Q2 and Q3: Look at ShaderLib.js and you will see the "Normal Map Shader". This is a perfect template for you. Yes, you can duplicate/rename it and modify it to your liking.

It uses a Phong-based lighting model, and even accesses the scene lights for you. You call it like so:

var shader = THREE.ShaderLib[ "normalmap" ];

var uniforms = THREE.UniformsUtils.clone( shader.uniforms );

. . .

var parameters = {
    fragmentShader: shader.fragmentShader,
    vertexShader: shader.vertexShader,
    uniforms: uniforms,
    lights: true // set this flag and you have access to scene lights
};

var material = new THREE.ShaderMaterial( parameters );

See these examples: http://threejs.org/examples/webgl_materials_normalmap.html and http://threejs.org/examples/webgl_materials_normalmap2.html.

For coding patterns to follow, see ShaderLib.js and ShaderChunk.js.

three.js r.67