Jump to content

  • Log In with Google      Sign In   
  • Create Account


Improved Area Lighting Algorithm


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
2 replies to this topic

#1 wagerfield   Members   -  Reputation: 108

Like
1Likes
Like

Posted 13 June 2013 - 02:15 PM

Hello Everyone,
 
I have been working on an area lighting implementation in WebGL similar to this demo:
 
 
The above implementation in three.js was ported from the work of ArKano22 over on gamedev.net:
 
 
Though these solutions are very impressive, they both have a few limitations. The primary issue with ArKano22's original implementation is that the calculation of the diffuse term does not account for surface normals.
 
I have been augmenting this solution for some weeks now, working with the improvements by redPlant to address this problem. Currently I have normal calculations incorporated into the solution, BUT the result is also flawed.
 
Here is a sneak preview of my current implementation:
 
area-lighting-teaser.png
 
Introduction
 
The steps for calculating the diffuse term for each fragment is as follows:
 
1. Project the vertex onto the plane that the area light sits on, so that the projected vector is coincident with the light's normal/direction.
2. Check that the vertex is on the correct side of the area light plane by comparing the projection vector with the light's normal.
3. Calculate the 2D offset of this projected point on the plane from the light's center/position.
4. Clamp this 2D offset vector so that it sits inside the light's area (defined by its width and height).
5. Derive the 3D world position of the projected and clamped 2D point. This is the nearest point on the area light to the vertex.
6. Perform the usual diffuse calculations that you would for a point light by taking the dot product between the the vertex-to-nearest-point vector (normalised) and the vertex normal.
 
Problem
 
The issue with this solution is that the lighting calculations are done from the nearest point and do not account for other points on the lights surface that could be illuminating the fragment even more so. Let me try and explain why…
 
Consider the following diagram:
 
lighting-problem-1.png
 
The area light is both perpendicular to the surface and intersects it. Each of the fragments on the surface will always return a nearest point on the area light where the surface and the light intersect. Since the surface normal and the vertex-to-light vectors are always perpendicular, the dot product between them is zero. Subsequently, the calculation of the diffuse contribution is zero despite there being a large area of light looming over the surface.
 
Potential Solution
 
I propose that rather than calculate the light from the nearest point on the area light, we calculate it from a point on the area light that yields the greatest dot product between the vertex-to-light vector (normalised) and the vertex normal. In the diagram above, this would be the purple dot, rather than the blue dot.
 
Help!
 
And so, this is where I need your help. In my head, I have a pretty good idea of how this point can be derived, but don't have the mathematical competence to arrive at the solution.
 
Currently I have the following information available in my fragment shader:
 
* vertex position
* vertex normal (unit vector)
* light position, width and height
* light normal (unit vector)
* light right (unit vector)
* light up (unit vector)
* projected point from the vertex onto the lights plane (3D)
* projected point offset from the lights center (2D)
* clamped offset (2D)
* world position of this clamped offset – the **nearest point** (3D)
 
To put all this information into a visual context, I created this diagram (hope it helps):
 
lighting-problem-2.png
 
To test my proposal, I need the casting point on the area light – represented by the red dots, so that I can perform the dot product between the vertex-to-casting-point (normalised) and the vertex normal. Again, this should yield the maximum possible contribution value.
 
Interactive Demo
 
I have created an interactive sketch over on CodePen that visualises the mathematics that I currently have implemented:
 
 
Screen Shot 2013-06-12 at 16.24.02.png
 
The relavent code that you should focus on is line 317.
 
castingPoint.location is an instance of THREE.Vector3 and is the missing piece of the puzzle. You should also notice that there are 2 values at the lower left of the sketch – these are dynamically updated to display the dot product between the relevant vectors.
 
Anyway, I hope that some compassionate genius out there can help me solve this!
 
Many thanks in advance biggrin.png
 


Sponsor:

#2 Waterlimon   Crossbones+   -  Reputation: 2515

Like
0Likes
Like

Posted 13 June 2013 - 02:42 PM

Would this not cause problems if the area lights farthest point is far away?

Or are you still using the distance to the clamped point as the intensity?

o3o


#3 Waterlimon   Crossbones+   -  Reputation: 2515

Like
0Likes
Like

Posted 13 June 2013 - 02:48 PM

If you find the farthest point from the surface point to the direction of the surface normal (move surface point to the direction of urface normal by way too many units, do usual projection and clamp) you will find the point you want. I think.

o3o





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS