vector_math.dart icon indicating copy to clipboard operation
vector_math.dart copied to clipboard

Why do frustum normals point outside?

Open LukasPoque opened this issue 2 years ago • 1 comments

I'm not so familiar with 3d graphics, so this is more a question than an actual bug.

When looking at this tutorial or this one the normals of the planes from the view frustum are pointing inward:

The planes are defined such that the normal points towards the inside of the view frustum.

For the near, the normal is the front vector of the camera. For the far plane, it's the opposite.

But inside this package, it seems like the normals need to point outwards of the frustum to get the containsVector3 working. I tried to create a small test case with a frustum (which is a cube around 0,0,0 with the size 2 in this case) to show why I think the normals need to point outwards.

The first one is with all normals pointing inside:

final frustum = Frustum();
frustum.plane0.setFromComponents(1, 0, 0, -1);
frustum.plane1.setFromComponents(-1, 0, 0, -1);
frustum.plane2.setFromComponents(0, 1, 0, -1);
frustum.plane3.setFromComponents(0, -1, 0, -1);
frustum.plane4.setFromComponents(0, 0, 1, -1);
frustum.plane5.setFromComponents(0, 0, -1, -1);

final pointInside = Vector3(0, 0, 0);
bool inside = frustum.containsVector3(pointInside);
final pointOutside = Vector3(2, 2, 2);
bool outside = frustum.containsVector3(pointOutside);

print(inside); //prints -> false
print(outside); //prints -> false

This one is with all pointing outwards:

final frustum = Frustum();
frustum.plane0.setFromComponents(-1, 0, 0, 1);
frustum.plane1.setFromComponents(1, 0, 0, 1);
frustum.plane2.setFromComponents(0, -1, 0, 1);
frustum.plane3.setFromComponents(0, 1, 0, 1);
frustum.plane4.setFromComponents(0, 0, -1, 1);
frustum.plane5.setFromComponents(0, 0, 1, 1);

final pointInside = Vector3(0, 0, 0);
bool inside = frustum.containsVector3(pointInside);
final pointOutside = Vector3(2, 2, 2);
bool outside = frustum.containsVector3(pointOutside);

print(inside); //prints -> true
print(outside); //prints -> false

So if anyone can give me a hint as to why this is implemented in this way (or why my tests are not correct), I would really appreciate this.

Maybe @Fox32 can help me out?

LukasPoque avatar Dec 28 '23 14:12 LukasPoque

I can try 😆. I didn't wrote the initial implementation myself, it actually comes from threejs which still uses the same code.

I dig a bit around and looked into Real-time Rendering - Third Edition by Tomas Akenine-Möller. There the equation also uses outward facing normals:

To make the normal of the plane point outwards from the frustum, the equation must be negated (as the original equation described the inside of the unit cube)

So I think the general idea of seeing the frustum as a geometric volume which has normals pointing outwards seems resonable.

I couldn't find a reference in Real-Time Collision Detection by Christer Ericson which is quite a common source, but I only took a quick look.

I'm not a big math expert myself, so that is what I can provide. In the end it shouldn't make a difference which method you choose, this library choose the normals to point outwards, while the articles you linked used outwards pointing normals. It's just important to know who uses what to accommodate your code.

Fox32 avatar Dec 28 '23 20:12 Fox32