New infinite plane light type

Hi,

I was wondering how feasible a new light type would be. Specifically, a light consisting of an infinite plane with a direction and falloff.

It would be defined with a position and direction and would have a falloff in the same way as a point light.

The lighting generated would be similar to that of a direction light (normal of the lit item vs normal of the light direction). However in addition, the lighting intensity would be based on the distance from the lit item to an infinite plane perpendicular to the light normal that intersects the light’s position.

Maybe this just isn’t possible, or it would be too slow, but I was interested in the opinions of people that know more than myself.

Thanks.

1 Like

I tried asking chatGPT and it came up with this typescript code, but I have no idea if this is correct:

type SimpleVector3 = {
  x: number;
  y: number;
  z: number;
};

class InfinitePlaneLight {
  position: SimpleVector3;
  direction: SimpleVector3;
  falloff: number;

  constructor(position: SimpleVector3, direction: SimpleVector3, falloff: number) {
    this.position = position;
    this.direction = direction;
    this.falloff = falloff;
  }

  calculateLightingIntensity(litItemPosition: SimpleVector3, litItemNormal: SimpleVector3): number {
    // Calculate the distance from the lit item to the infinite plane
    const planeNormal = this.direction;
    const planePoint = this.position;
    const itemToPlaneVector = {
      x: litItemPosition.x - planePoint.x,
      y: litItemPosition.y - planePoint.y,
      z: litItemPosition.z - planePoint.z,
    };
    const distance = Math.abs(
      itemToPlaneVector.x * planeNormal.x +
      itemToPlaneVector.y * planeNormal.y +
      itemToPlaneVector.z * planeNormal.z
    ) / Math.sqrt(
      planeNormal.x * planeNormal.x +
      planeNormal.y * planeNormal.y +
      planeNormal.z * planeNormal.z
    );

    // Calculate the intensity based on the distance and falloff
    const intensity = Math.max(0, 1 - (distance / this.falloff));

    // Calculate the dot product of the lit item normal and the light direction
    const dotProduct = Math.max(0, 
      litItemNormal.x * planeNormal.x +
      litItemNormal.y * planeNormal.y +
      litItemNormal.z * planeNormal.z
    );

    // Combine the intensity with the dot product
    return intensity * dotProduct;
  }
}

and then this GLSL code:

#version 330 core

in vec3 FragPos;  // Fragment position
in vec3 Normal;   // Fragment normal

out vec4 FragColor;

uniform vec3 lightPos;      // Light position
uniform vec3 lightDir;      // Light direction
uniform float lightFalloff; // Light falloff

void main() {
    // Normalize the light direction
    vec3 normLightDir = normalize(lightDir);

    // Calculate the vector from the fragment to the light position
    vec3 fragToLight = FragPos - lightPos;

    // Calculate the distance from the fragment to the infinite plane
    float distance = abs(dot(fragToLight, normLightDir)) / length(normLightDir);

    // Calculate the intensity based on the distance and falloff
    float intensity = max(0.0, 1.0 - (distance / lightFalloff));

    // Calculate the dot product of the fragment normal and the light direction
    float dotProduct = max(0.0, dot(normalize(Normal), normLightDir));

    // Combine the intensity with the dot product
    float lighting = intensity * dotProduct;

    // Set the fragment color (assuming white light for simplicity)
    FragColor = vec4(vec3(lighting), 1.0);
}
1 Like

We don’t have a clean way to inject code in the lighting block computation, but you could do it with a material plugin and use a regexp to inject code:

=> you can set false on line 42 to see the difference when the plugin is disabled

This could serve as a starting point for a more complete implementation.

3 Likes

Wow thanks, that’s fantastic! I was just hoping for a bit of advice and you actually implemented it. Really appreciate that.
I wish I didn’t have to wait until Monday before I can play around with it.