Unreal Rect Light vs. Eevee Area Light

Hi there, I would like some help to know if i’m not doing something really wrong.

I cannot find a place on the internet that discuss this behavior of LTC (linearly transformed cosine) which is what Unreal (4.20), Unity (HDRP) and Eevee uses for area lights:


Notice the abnormal reflection at the bottom of the sphere and the Suzanne.

I don’t have the unreal engine installed to do the test myself so it would be nice if someone kindly do the experiment and post the result of a similar setup in Unreal or Unity (HDRP).

The setup is just a rather tiny area light (see screenshot) without shadows, and an object with a material 100% metallic and 2% rough.

In blender increasing roughness makes the artifact vanish progressively. Making the area light bigger also fade the artifact.

If anyone can confirm or infirm that the bug also appear in Unreal / Unity that would be nice.

Thanks

artifact confirmed on Unity HDRP 2018.3.0f

3 Likes

I’m not sure if I made this identical but I couldn’t see any weird reflections at Unreal 4.20.3.

Metallic material:
image

Something I forgot to mention! You need to disable shadows!

Also the light should be a bit larger. Lets say 10 cm in source width and height.

Thanks a lot to you! It reassure me to know they also have the same issue.

1 Like

Allright then, weird reflections appears when shadows disabled :upside_down_face: . Changing size or intensity doesn’t eliminate it.

1 Like

Much thanks!

So… It’s time to edit the manual to include this “corner” case as known limitation.

4 Likes

I did some testing and to me it seems like multiplying specular reflections by clamp(dot(N, L) + radius/l_vector.w, 0.0, 1.0) (radius is the radius of light source) is a rather decent mitigation. It doesn’t seem to tinker much with the actual reflection blob, only sometimes reducing tail length. It also prevents speculars from extending to places where normally you wouldn’t see them (thus reducing visibility of grazing angle artifacts when shadows are turned on). It’s not entirely physics based, but it’s rather cheap and does it job.

Comparsion immages (top spheres’ roughness is 0.033, bottom spheres’ - 0.35):


(implemented via nodes as I wasn’t willing to go into source code at this point)

NOTE: This mitigation doesn’t completely eliminate the artifacts, but it can help to seriously reduce their effect on scene.

1 Like

After more experimentation it seems like this is a better solution:

float alphaRad = radius / l_vector.w;
float NoL = dot(N, L);
float specular_artifact_mitigation(float NoL, float alphaRad) {
    float k = 1.0; // A value that controls the strength of mitigation, 0 = no mitigation
    return clamp(NoL + alphaRad / (alphaRad + k), 0.0, 1.0);
}

This also allows to fine-tune the mitigation. k could even be exposed to the user per-material to allow reducing artifacts for certain materials without affecting others (although this means additional uniform) . I still believe this is far from a perfect solution, but it may be just good enough.