Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Three.js ShaderMaterial lighting not working

I'm experimenting with Three.js ShaderMaterial and trying to implement lighting. I have working code for r70 but the same code (with minor changes - the MAX_POINT_LIGHTS constant has been renamed NUM_POINT_LIGHTS) doesn't work for r76.

Looking at a trace in WebGL Inspector it's clear that no light data is being sent to the shader. So, has lighting broken or do I need to set up something else to get it to work?

Using r70 (working)

http://codepen.io/anon/pen/KzjXNr?editors=1010

Fragment Shader

uniform vec3 diffuse;
varying vec3 vPos;
varying vec3 vNormal;
uniform vec3 pointLightColor[MAX_POINT_LIGHTS];
uniform vec3 pointLightPosition[MAX_POINT_LIGHTS];
uniform float pointLightDistance[MAX_POINT_LIGHTS];

void main() {
  vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
  for(int l = 0; l < MAX_POINT_LIGHTS; l++) {
    vec3 lightDirection = normalize(vPos - pointLightPosition[l]);
    addedLights.rgb += clamp(dot(-lightDirection, vNormal), 0.0, 1.0) * pointLightColor[l];
  }
  gl_FragColor = addedLights;
}

JavaScript - setting up the Shadermaterial with UniformsUtils and UniformsLib

var uniforms = THREE.UniformsUtils.merge([
    THREE.UniformsLib['lights'],
    { diffuse: { type: 'c', value: new THREE.Color(0xff00ff) } }
]);
var vertexShader = document.getElementById('vertexShader').text;
var fragmentShader = document.getElementById('fragmentShader').text;
material = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vertexShader,
      fragmentShader: fragmentShader,
      lights: true
    });

var geometry = new THREE.BoxGeometry(200, 200, 200);
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

Using r76 (futzed)

http://codepen.io/anon/pen/ZWdXLZ?editors=1010

Fragment Shader

uniform vec3 diffuse;
varying vec3 vPos;
varying vec3 vNormal;
uniform vec3 pointLightColor[NUM_POINT_LIGHTS];
uniform vec3 pointLightPosition[NUM_POINT_LIGHTS];
uniform float pointLightDistance[NUM_POINT_LIGHTS];

void main() {
  vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
  for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
    vec3 lightDirection = normalize(vPos - pointLightPosition[l]);
    addedLights.rgb += clamp(dot(-lightDirection, vNormal), 0.0, 1.0) * pointLightColor[l];
  }
  gl_FragColor = addedLights;
}

JavaScript

Unchanged

like image 620
CarlBateman Avatar asked Jan 06 '23 01:01

CarlBateman


1 Answers

The light uniforms have been changed to structs in r74 (Specifically in #7324). Note that though the change to structs happened in r74, the following works r75 and later.

A single array of structs is given for each light type. Each struct has the position and color properties you need.

Fragment Shader

uniform vec3 diffuse;
varying vec3 vPos;
varying vec3 vNormal;

struct PointLight {
  vec3 position;
  vec3 color;
};
uniform PointLight pointLights[ NUM_POINT_LIGHTS ];

void main() {
  vec4 addedLights = vec4(0.1, 0.1, 0.1, 1.0);
  for(int l = 0; l < NUM_POINT_LIGHTS; l++) {
    vec3 adjustedLight = pointLights[l].position + cameraPosition;
    vec3 lightDirection = normalize(vPos - adjustedLight);
    addedLights.rgb += clamp(dot(-lightDirection, vNormal), 0.0, 1.0) * pointLights[l].color;
  }
  gl_FragColor = addedLights;//mix(vec4(diffuse.x, diffuse.y, diffuse.z, 1.0), addedLights, addedLights);
}

Note that the light position is now relative to the camera so you offset the light position with the camera position.

Working Fiddle

like image 191
Le Jeune Renard Avatar answered Mar 19 '23 06:03

Le Jeune Renard