Bounding box frustum culling

Shadow flickering is occurring whenever the camera is looking exactly 90 degrees down at a shadow of an out of view object.

Which led me to this function:

Adding a break statement after the highlighted condition solved the problem.

But why there isn’t a break statement after the condition there ? I mean if one plane is not outside, then it must be at least intersecting, right?

2 Likes

I assume what you did is:

if (dist < -absDist)
    return OUTSIDE;
break; // this doesn't end up doing what you think it will

// and not something super terrible like:

if (dist < -absDist)
    break; // if did this, slap yourself

No. Because the entire box could be on the backside of 1 plane without any other corners on the backside of any other plane.

In that case the box would be out of view off to one side, or behind the nearplane, etc. Your change fixes your problem because you’ve broken the test to return false-positives very liberally, so virtually everything will pass containment tests.


Which type of light is having the shadow flicker? For instance directional light’s have an extrusion (GetShadowMaxExtrusion SetShadowMaxExtrusion) move back the light from it’s bounded fit so that offscreen things cast shadows. Default for that is 1000, if you’re using a tiny unit (like 1.0 == 1cm) then you only have 10m of peeling back.

If other lights are doing it then there’s a containment test problem somewhere either in selecting the light or selecting the shadowcasters to render (more likely the former). You’ll have to step through passing and failing frames. I’d use Renderdoc to capture both cases to see what the shadowmap passes are doing (ie. are the shadowmaps differing between the two) first to make some determinations of where to go next.


If you need more help then post scene files or at least pictures so we can see what’s going on.

2 Likes

I assume what you did is:

if (dist < -absDist)
    return OUTSIDE;
break; // this doesn't end up doing what you think it will

Yes.

Which type of light is having the shadow flicker?

All light types.

If other lights are doing it then there’s a containment test problem somewhere either in selecting the light or selecting the shadowcasters to render (more likely the former). You’ll have to step through passing and failing frames.

I’ve checked the frames and it seems the model is being culled.

If you need more help then post scene files or at least pictures so we can see what’s going on.

Uploaded a short video:
https://youtu.be/U9XF9XFV2TY

Can you reproduce this bug on unmodified Urho samples?
I’m 90% certain you messed up with scene setup.

Can you reproduce this bug on unmodified Urho samples?

Yes, sample 15-Navigation:
https://youtu.be/Xv1-ghnCOm8

I used the 1.8 Alpha.

Oh shit. Thank you. I think I saw this bug before and I investigated it. Lemme re-check.

Okay, I have good news.
This bug happens only if you literally have just flat plane perpendicular to the look direction and nothing else.
The difference between minZ_ and maxZ_ is too small and something breaks.

Just do something like maxZ_ += 1 if minZ_ and maxZ_ are too close around here:

The bad news is that I’m too lazy to commit this fix upstream. DIY if you wish.

2 Likes

Something like this?

    if (Equals(minZ_, maxZ_))
        maxZ_ += 1.0f;

Seems to work.

Flickering is gone.
Thank you.

Floor it or use a large epsilon. The numeric_limits epsilon used in Equals is really tiny. I was still able to reproduce the flicker (less atrociously) using just Equals. Flooring or using M_LARGE_EPSILON both worked for me in the case where you nail your look angle to the floor and spin around until you get the flicker.

if (Equals(Floor(minZ_), Floor(maxZ_)))
    maxZ_ += 1.0f;
1 Like

It amazes me how many people use numeric_limits epsilon. Whereas I believe that if you use numeric_limits epsilon, you are doing something wrong. So far I have never encountered legitimate use of this constant, only mis-uses. Have you ever seen legitimate use?

How’s this then?

if (Equals(minZ_, maxZ_, M_LARGE_EPSILON))
    maxZ_ += 1.0f;
template <class T> inline bool Equals(T lhs, T rhs, T margin = std::numeric_limits<T>::epsilon())
{ return lhs + margin >= rhs && lhs - margin <= rhs; }
1 Like

Complete integration over every single possible value in a floating point range.