First off, set up your scene with some lights:
Define the lights:
var light1, light2;
Add the lights to your scene:
// Add lights.
//color, strength, max distance, decay power
light1 = new THREE.PointLight(0x2596be, 1, 100.0, 2.0);
light1.position.set( 30, 10, -20 );
this.scene_.add(light1);
//color, strength, max distance, decay power
light2 = new THREE.PointLight(0xf1bb75, 1, 100.0, 2.0);
light2.position.set( -40,-2, 20 );
this.scene_.add(light2);
Then, add the light data to your shader uniforms using the Three.UniformsUtils.merge function
// setup material uniforms
var uniforms = THREE.UniformsUtils.merge(
[THREE.UniformsLib['lights'],
{
time : {value: time},
}
]
)
Pass the uniforms to the materials, along with Lights: true
const material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: await vsh.text(),
fragmentShader: await fsh.text(),
lights: true
});
In your vertex shader, transform the normal by the normalMatrix, export viewPosition
varying vec3 vNormal;
varying vec3 vViewPosition;
void main() {
vec4 ViewPosition4 = modelViewMatrix * vec4(position, 1.0);
vViewPosition = ViewPosition4.xyz;
gl_Position = projectionMatrix * ViewPosition4;
vNormal = normalMatrix * normal;
}
Then, in your fragment shader bring in this struct and this uniform (for point lights, anyway)
struct PointLight {
vec3 position;
vec3 color;
float distance;
float decay;
};
uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
Then do whatever you want to do with the lights in a loop that goes through all of them:
vec3 normal = normalize(vNormal);
vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
vec3 lightVector = pointLights[l].position - vViewPosition;
vec3 lightDirection = normalize(lightVector );
vec3 lightColor = pointLights[l].color;
addedLights.rgb += clamp(dot(lightDirection, normal), 0.0, 1.0) * lightColor ;
}
The complete fragment shader:
varying vec3 vPos;
varying vec3 vNormal;
varying vec3 vViewPosition;
struct PointLight {
vec3 position;
vec3 color;
float distance;
float decay;
};
uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
void main() {
vec3 normal = normalize(vNormal);
vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
vec3 lightVector = pointLights[l].position - vViewPosition;
vec3 lightDirection = normalize(lightVector );
vec3 lightColor = pointLights[l].color;
addedLights.rgb += clamp(dot(lightDirection, normal), 0.0, 1.0) * lightColor ;
}
gl_FragColor = addedLights;
}
If you want to incorporate distance based falloff:
varying vec3 vPos;
varying vec3 vNormal;
varying vec3 vViewPosition;
struct PointLight {
vec3 position;
vec3 color;
float distance;
float decay;
};
uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
float lightingFalloff(float lightDistance, float cutoffDistance, float decayExponent ) {
if( cutoffDistance > 0.0 && decayExponent > 0.0 ) {
return pow( clamp( -lightDistance / cutoffDistance + 1.0, .0, 1.0 ), decayExponent );
}
else {
return 1.0;
}
}
void main() {
vec3 normal = normalize(vNormal);
vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
vec3 lightVector = pointLights[l].position - vViewPosition;
vec3 lightDirection = normalize(lightVector );
float lightDistance = length(lightVector);
vec3 lightColor = pointLights[l].color;
addedLights.rgb += clamp(dot(lightDirection, normal), 0.0, 1.0) * lightColor ;
addedLights.rgb *= lightingFalloff(lightDistance, pointLights[l].distance, pointLights[l].decay );
}
gl_FragColor = addedLights;
}
No comments:
Post a Comment