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.
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);
}
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.
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.