Planet Engine - Frustrum Culling and Horizon Culling

Published August 23, 2016
Advertisement

I decided to take a step back from the noise and terrain generation and move back towards the actual generation of the mesh at varying levels of detail. Something that needs work anyway and might hopefully make some of the other stuff make a bit more sense.

I discovered pretty quickly that just a very basic frustrum check works really well in this context, as the video hopefully shows. I'm toggling updating the camera position by pressing a key, so when it is switched off, the planet thinks the camera just stays were it was last, so you can look around and visualise what parts of the mesh are being skipped.

I am using the noise here just to provide a consistent shade to each of the triangles, just to make it a bit more interesting to look at. Actually working mainly in wire frame mode but that tends to make for rubbish looking videos so out of concern for you, dear reader, I switched to this display for the sake of this example :)

Otherwise, there is nothing particularly clever here. My frustrum class is made from various bits of code I've found scattered around the internet, with a special case method here for checking a triangle.

Frustrum::Frustrum(float depth, const Matrix &view, const Matrix &proj){ Matrix localProj = proj; float zMin = -proj._43 / proj._33; float r = depth / (depth - zMin); localProj._33 = r; localProj._43 = -r * zMin; Matrix matrix = view * localProj; // near p[0].a = matrix._14 + matrix._13; p[0].b = matrix._24 + matrix._23; p[0].c = matrix._34 + matrix._33; p[0].d = matrix._44 + matrix._43; // far p[1].a = matrix._14 - matrix._13; p[1].b = matrix._24 - matrix._23; p[1].c = matrix._34 - matrix._33; p[1].d = matrix._44 - matrix._43; // left p[2].a = matrix._14 + matrix._11; p[2].b = matrix._24 + matrix._21; p[2].c = matrix._34 + matrix._31; p[2].d = matrix._44 + matrix._41; // right p[3].a = matrix._14 - matrix._11; p[3].b = matrix._24 - matrix._21; p[3].c = matrix._34 - matrix._31; p[3].d = matrix._44 - matrix._41; // top p[4].a = matrix._14 - matrix._12; p[4].b = matrix._24 - matrix._22; p[4].c = matrix._34 - matrix._32; p[4].d = matrix._44 - matrix._42; // bottom p[5].a = matrix._14 + matrix._12; p[5].b = matrix._24 + matrix._22; p[5].c = matrix._34 + matrix._32; p[5].d = matrix._44 + matrix._42; for(uint i = 0; i < 6; ++i) { D3DXPlaneNormalize(&p, &p); }}bool Frustrum::contains(const Vec3 &a, const Vec3 &b, const Vec3 &c) const{ for(uint i = 0; i < 6; ++i) { const float e = -0.05f; if(D3DXPlaneDotCoord(&p, &a) < e && D3DXPlaneDotCoord(&p, &b) < e && D3DXPlaneDotCoord(&p, &c) < e) { return false; } } return true;}Then, in my recursive triangle add method in the planet builder, I just start the method with a check to see if the triangle is outside the frustrum and return if so.


Its nice because it will early out very quickly when building the icosahedron. The first twenty calls to the addRecursive method are for the twenty base icoshedron faces and in the majority of near-surface cases, most of these will be outside the frustrum so the entire face will be skipped without any subdivision required.

At the moment, because it has no concept of a horizon, the faces on both the near side and the far side are being generated, the far side technically falling inside the frustrum, so I guess I need to look at some kind of horizon culling next. I've seen this discussed and implemented on my travels around planet rendering papers and websites but have no idea yet how it works or how to implement it.

This silly little step forward has made me feel a lot more positive about getting the level of detail working now. Hopefully more interesting progress to follow.

[A little later]

Wow. Was reading this article about horizon culling and, as is usual for me, was getting completely lost with all the alien (to me) math notation. Then I focused on the following bit of English.

[quote]
So there it is. To determine if the target point is behind the horizon plane, take the dot product of the vector from the viewer to the target with the vector from the viewer to the center of the ellipsoid. If that's larger than the magnitude squared of the vector from the viewer to the center of the ellipsoid, minus one, then the target is behind the plane. No square roots or trigonometric functions required.[/quote]
So I then ignored all of the rest of the page and all the notation, and just pasted that into my code as a comment, then translated it into code using my Maths wrapper methods:

/*Take the dot product of the vector from the viewer to the target with the vector from the viewer to the center of the ellipsoid.If that's larger than the magnitude squared of the vector from the viewer to the center of the ellipsoid, minus one, then the target is behind the plane.*/bool beyondHorizon(const Vec3 &p, const Vec3 &camera, const Vec3 &center){ Vec3 vt = p - camera; Vec3 vc = center - camera; float d = dotVectors(vt, vc); return d > vectorLengthSq(vc) - 1.0f;}Not feeling very optimistic, I then just added a very simple check against this for all three points of the triangle in my recursive method, returning doing nothing if all three are beyond the horizon according to this beasty.

And, to my amazement, it appears to work perfectly :) I'm rendering with culling disabled and wireframe at the moment so very easy to see if the backward faces are being rendered or not, and it seems they are not.

Excellent and unexpectedly simple result. We now have horizon culling appearing to work, subject to some more testing. Happy me!

5 likes 3 comments

Comments

Aardvajk
I've also found that like my introduction of the 'e' in the frustrum cull, I can change the - 1.0f to - 0.9f etc in the horizon method to introduce some tolerance. Was clipping triangles it shouldn't but very easy to the control the method :)
August 24, 2016 04:25 PM
ErnieDingo
Ignore. Read the piece of code i was querying on. You are doing a dot test.

It looks like you are doing a per triangle test on your planet surface?
August 28, 2016 09:08 PM
piluve

Hello! What is the "depth" variable? I've seen some articles about frustrum culling and it's the first time I see it.

February 12, 2017 06:00 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement