Disk Area Light

Started by
5 comments, last by Willywill 8 years, 10 months ago

Hello everyone,

I have just a quick question. I wanted to make sure I ask so I don't forget as it's on my to do list. I can't seem to find out how to get the closest point on a disk. I have tried to find papers that cover this topic but to no avail.

If someone could guide me in the right direction it would help a lot! I already have Sphere, Tube, and Rectangle area lights.

I have a great set of math skills but I don't know how to apply it in this scenario, or have any tools that can help me calculate the closest point.

Thank you for your time!

Advertisement

Here's what I would do: First project your point onto the plane of the disk. Then check if the distance from the projected point to the center of the disk is less than the disk's radius. If if is, voila, closest point. If it is not, scale this distance to the radius of the disk, which will give you the point on it's perimeter that is closest to your original point.

Actually, I think this should be pretty close to what you have do with your rectangle light.

Here's what I would do: First project your point onto the plane of the disk. Then check if the distance from the projected point to the center of the disk is less than the disk's radius. If if is, voila, closest point. If it is not, scale this distance to the radius of the disk, which will give you the point on it's perimeter that is closest to your original point.

Actually, I think this should be pretty close to what you have do with your rectangle light.

Thank you for the very speedy reply smile.png is it really that simple? I guess I have a hard time following the terms and what exactly they mean. I have the rectangle closest point here based from the latest Frostbites PBR slides. I never went to school for graphics programming and I taught myself tongue.png I'm assuming the projected a point onto a plane is the planeIntersect variable that I have there? As for the distance check that was clearly understood. Thanks again for your help!


half3 dir = pos - lightPos;
half3 planeIntersect = (pos - dot(dir, _LightNormal) * _LightNormal) - lightPos;
half halfWidth = _LightWidth; halfWidth *= 0.5f;
half halfHeight = _LightHeight; halfHeight *= 0.5f;

half2 dist2D = half2( dot(dir, _LightRight), dot(dir, _LightUp) );
half2 rectHalf = half2(halfWidth, halfHeight);
dist2D = clamp(dist2D, -rectHalf, rectHalf);

half3 closestPoint = (lightPos + (_LightRight * dist2D.x + _LightUp * dist2D.y)) - pos;

I'm not sure about the last minus lightPos. If I'm not mistaken, pos - dot(dir, _LightNormal) * _LightNormal should already be the point on the plane. Minus lightPos makes it a vector pointing from the center of the light to the point on the plane closest to pos (which is actually what you need in the end, but the name planeIntersect is a bit misleading here).

is it really that simple?

Not really, but it's the fastest approximation and nobody usually notices issues with it, anyway. It will look slightly wrong for surfaces near the light due to normals being shaded from just one direction, not the whole volume.

Ideally you'd want to sample the lighting from multiple (as many as possible) points in the light (or use more advanced equations to account for light direction "cone") to get accurate shading but I'm sure you can see why it's rarely practical.

P.S. For more accuracy, you might want to try raycasting the plane using the normal as ray direction.

is it really that simple?

Not really, but it's the fastest approximation and nobody usually notices issues with it, anyway. It will look slightly wrong for surfaces near the light due to normals being shaded from just one direction, not the whole volume.

Ideally you'd want to sample the lighting from multiple (as many as possible) points in the light (or use more advanced equations to account for light direction "cone") to get accurate shading but I'm sure you can see why it's rarely practical.

P.S. For more accuracy, you might want to try raycasting the plane using the normal as ray direction.

Thanks for the heads up, that approach sounds similar to what I saw with what DICE was doing. I avoided it because I thought it was cost prohibitive and they showed lots of ugly overlapping in their screenshots from the different light sources. Is there anyway to get better blended results from that?

Their example using multiple sources:

oLMB9X2.png

I'm not sure about the last minus lightPos. If I'm not mistaken, pos - dot(dir, _LightNormal) * _LightNormal should already be the point on the plane. Minus lightPos makes it a vector pointing from the center of the light to the point on the plane closest to pos (which is actually what you need in the end, but the name planeIntersect is a bit misleading here).

Sorry for the misleading variables, If there are two thing I absolutely suck at, its matrices and converting math to code, I had just used some older code for the projection math. And surprisingly it worked just fine my first try. I removed the lightPos and it had no effect, I'm not sure why it was there in the first place.

Are there any tools graphics programmers use to help aid them with calculations such as these? I've seen someone mention MatLab but I have no idea how that works, and other visualizers.

Sorry for the double post,

I have this here but I'm still confused on how I can scale the distance to the radius of the disk


Center = lightPos
Projected point = P
Disk radius = R

float3 P = projectOntoPlane();

float3 closestPoint = distance(P, lightPos) < R ? P : (Scale distance to the radius);

My assumption is, if we are looking for the distance to be less than the radius, the failure case is saying we are greater or equal to the radius, so we need to subtract it by the amount that we overshoot?

EDIT: I solved the problem! Thank you everyone for your help!

n9HRkr0.png

From left to right: Tube, Disk, Rectangle, Sphere

For a solution just see DICE's frosbite PBR slides, I took the approximation from there and combined it with the rectangular light code.

This topic is closed to new replies.

Advertisement