Difference between directionalLight() and pointLight() on basic 3D shapes and P5.Geometry shapes

Hi.
When using directionalLight() I need to give a negative z value to actually see the light.
If I understand it well the z value is positive towards the ‘viewer’, and that’s what happens when I use a positive z value with PointLight() Isn’t that a bug?

function setup() {
  createCanvas(200, 200, WEBGL);
  noStroke()
}

function draw() {
  background(200);
  orbitControl(5, 5, .05)
  //pointLight(255, 255, 0, 0, 0, 20)
  directionalLight(255, 255, 0, 0, 0, -20)
  plane(100, 100);
}

I believe the x/y/z components of directionalLight are the direction that the light is shining in, so negative Z is “into” the screen (or away from the viewer). Whereas the x/y/z components of the pointLight function are the position of the point light (where it is shining from, and it shines in all directions). So in order to have the point light illuminate objects from the perspective of the default camera, it must be positioned toward the viewer.

1 Like

Thank you. This seems to be a beginner question, but still, I do not understand why you need a negative z value when using directionalLight() on a plane, but a positive z value when using the same directionalLight() on a P5.Geometric triangle.

let m;
let nextTriagleId = 0;

function setup() {
  createCanvas(400, 200, WEBGL);
  m = createTriangle();
}

function draw() {
  background(100);
  orbitControl(2, 1, 0.05);
  ambientLight(50);
  push();
  directionalLight(240, 240, 240, 0, 0, -1);
  translate(-50, 0, 0);
  plane(50, 50);
  pop();
  push();
  translate(50, 0, 0);
  directionalLight(240, 240, 240, 0, 0, 1);
  model(m);
  pop();
}

function createTriangle() {
  return new p5.Geometry(1, 1, function createGeometry() {
    this.gid = `triangle-${nextTriagleId++}`;
    let v0 = new p5.Vector(0, -25, 0);
    let v1 = new p5.Vector(-50, 25, 0);
    let v2 = new p5.Vector(50, 25, 0);
    this.vertices.push(v0, v1, v2);
    let n = p5.Vector.sub(v1, v0).cross(p5.Vector.sub(v2, v0));
    this.vertexNormals.push(n, n, n);
    this.faces.push([0, 1, 2]);
  });
}

I’m a bit pressed for time, but here’s a quick explanation. Directional lights don’t have a point of origin, they just have a direction in which the emit light and the light that they shine is everywhere in the space, shining in that direction. The illumination of a given face will depend on the angle between its normal and the direction of light

Point lights on the other hand do have a point of origin and don’t have a constant direction. The illumination of faces will still depend on the angle between the face normal and light direction, but the actual direction will depend on distance and relative position of the light.

So it is because the X/Y/Z parameters for these lights mean completely different things that one Z has to be negative and the other has to be positive to get similar illumination with these two types of lights.

1 Like

Thank you once more for the effort. I do understand that a pointLight() radiates light in all directions like the sun lights the planets and that directionalLight() will light the planets from one direction as if it came from far outside our solar system from a strong bright light-emitting source, let’s say a quasar. What I do not understand is why it has to be negative. It could as well be reversed to positive. I posted this topic because in my current sketch I have a great amount of P5.Geometric polygon shapes mixed with other basic shapes. And now, Instead of just using directionalLight() once, I need to place it between push() and pop() with a reversed z (from -1 to 1) sign for all the different types of shapes. I still believe there is something wrong.

In the course at learnopengl.com here is explained where the light position is made negative in the shader code, and I think the reason why becomes more clear in this blog (+links).
But why then, in your P5.Geometric examples, the light position sign has to be positive?

Just to complete. To make the lighting work correctly on P5.Geometric polygons, you need to keep track of the rotation. When passed 180 degrees, the z value of the light functions (poinLight() as well) takes/needs the same sign as basic 3D shapes.

let m;
let rotX = 0; 
let rotY = 0; 

function setup() {
  createCanvas(400, 300, WEBGL);
  background(0);
  let v0 = new p5.Vector(-30, -50, 0);
  let v1 = new p5.Vector(-50, 50, 0);
  let v2 = new p5.Vector(50, 50, 0);
  let v3 = new p5.Vector(30, -50, 0);
  m = createQuadrilateral(v0, v1, v2, v3);
  stroke(180, 0, 0);
  fill(255, 0, 0);
  rotateX(rotX);
  rotateY(-rotY);
}

function draw() {
  background(0);
  directionalLight(255, 255, 255, 0, 0, -1);
  //pointLight(255, 255, 255, 0, 0, 200);
  rotateX(rotX);
  rotateY(-rotY);
  push();
  translate(75, 0, 0);
  box(50);
  pop();
  push();
  if(rotX > -PI) directionalLight(255, 255, 255, 0, 0, 1);
  //if(rotX > -PI) pointLight(255, 255, 255, 0, 0, -200);
  translate(-75, 0, 0);
  model(m);
  pop();
}

function createQuadrilateral(v0, v1, v2, v3) {
  return new p5.Geometry(1, 1, function createGeometry() {
    this.vertices.push(v0, v1, v2, v3);
    this.faces.push([0, 1, 2], [0, 2, 3]);
    let n1 = p5.Vector.sub(v1, v0).cross(p5.Vector.sub(v2, v0));
    let n2 = p5.Vector.sub(v2, v3).cross(p5.Vector.sub(v3, v0));
    this.vertexNormals.push(n1, n1, n1, n2, n2, n2);
  });
}

function mouseDragged() {
  rotY -= (mouseX - pmouseX) * 0.01;
  rotX -= (mouseY - pmouseY) * 0.01;
}

The code above does work when the x and y directions are 0. But when you alter them the lighting goes wrong again. By the way, the same happens when you use the basic WEBGL ‘plane shape’. I am trying to follow the thread and learn to work with the P5.Geometric shapes, but if this is a beginner question and there is no further documentation or working examples, I guess I better give up.

True! The plane shape is just useless, (as well as the plane custom Geometric shape). If you want a ‘flat’ plane shape you can use the box shape and give a height of 0.5 pixels. That will give the correct lighting when you rotate. I was trying to build shapes by mounting flat geometric ‘walls’ together, but that’s not the way to go. So now I use one mesh as you can see in the code below. I tried to set the vertexNormals as @KumuPaul has shown in his tutorial, but that doesn’t give the right lighting either. But some time ago he gave an example using a shader on a ‘nut shape’ I made. That’s what I use in this sketch, where the ‘plane shape’ is compared to a ‘flat box’ and a polyhedron shape. If there is any way to do it without a shader I really would like to know.