I have made a simple custom shader using THREE.ShaderMaterial that only changes a plane's shape with a heightmap.
Does anyone know the proper way of using the scene's directional light source with a very simple custom shader?
EDIT
Vertex shader
uniform sampler2D heightTexture;
varying float displacement;
varying vec2 vUv;
varying vec3 vPosition;
varying vec3 vNormal;
void main() {
vUv = uv;
vec4 data = texture2D(heightTexture, uv);
displacement = data.b;
vec3 height = position + normal * displacement;
vPosition = (modelMatrix * vec4(position, 1.0)).xyz;
vNormal = (modelMatrix * vec4(normal, 0.0)).xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(height, 1.0);
}
Fragment shader
uniform sampler2D texture;
uniform vec3 pointLightColor[MAX_POINT_LIGHTS];
uniform vec3 pointLightPosition[MAX_POINT_LIGHTS];
uniform float pointLightDistance[MAX_POINT_LIGHTS];
varying vec2 vUv;
varying vec3 vPosition;
varying vec3 vNormal;
void main() {
vec4 texture = texture2D(texture, vUv);
vec4 lights = vec4(0.0, 0.0, 0.0, 1.0);
for(int i = 0; i < MAX_POINT_LIGHTS; i++) {
vec3 lightVector = normalize(vPosition - pointLightPosition[i]);
lights.rgb += clamp(dot(-lightVector, vNormal), 0.0, 1.0) * pointLightColor[i];
}
gl_FragColor = texture * lights;
}
I tried with point lights because i couldn't use directional at all, even though I need to use directional. In the fragment shader, if i write gl_FragColor = lights;
the light is visible, but if i try something like gl_FragColor = texture * lights;
the plane becomes black. If I use a color instead of the texture, it also works but I need to use textures.
The second problem is that while lights are set as true and the uniforms are merged with THREE.UniformsLib['lights']
, the heightmap doesn't affect the plane at all.
Include the needed light uniforms by merging `THREE.UniformsLib['lights'] with your uniforms. eg.
var uniforms = THREE.UniformsUtils.merge(
[THREE.UniformsLib['lights'],
{
diffuse: {type: 'c', value: new THREE.Color(0x0000ff)}
}
]
)
Set the ShaderMaterial light parameter to true. eg.
material = new THREE.ShaderMaterial(
{
uniforms : uniforms,
vertexShader : vertexShader,
fragmentShader : fragmentShader,
lights: true
});
Now in your shader you will have access to the light uniforms:
uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];
uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];
HERE is an example I did with point lights.
Here are some other experiments I have been doing with shaders in three.js.
UPDATE
I have a vertex displacement demo HERE. You can easily view the shader code by clicking "source" in the dat.gui. It uses noise for the displacement, you can ignore it and just use your texture value.
If you are testing in the Chrome browser, it actually gives quite good error messages in the console.
UPDATE
There seems to be a problem merging the light uniforms and using textures, outlined HERE
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