You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

117 lines
4.5 KiB

#ifndef FRUSTUM_CULLING_H
#define FRUSTUM_CULLING_H
float3 GetForward(OrientedBBox value)
{
return cross(value.up, value.right);
}
struct FrustumPlane
{
float3 normal;
float dist;
};
struct Frustum
{
FrustumPlane planes[6];
// Needs to be aligned on a float4, a bit of waste here
float4 corners[8];
};
bool CheckOverlap(OrientedBBox obb, float3 planeNormal, float planeDistance)
{
// Max projection of the half-diagonal onto the normal (always positive).
float maxHalfDiagProj = obb.extentX * abs(dot(planeNormal, obb.right))
+ obb.extentY * abs(dot(planeNormal, obb.up))
+ obb.extentZ * abs(dot(planeNormal, GetForward(obb)));
// Positive distance -> center in front of the plane.
// Negative distance -> center behind the plane (outside).
float centerToPlaneDist = dot(planeNormal, obb.center) + planeDistance;
// outside = maxHalfDiagProj < -centerToPlaneDist
// outside = maxHalfDiagProj + centerToPlaneDist < 0
// overlap = overlap && !outside
return (maxHalfDiagProj + centerToPlaneDist >= 0);
}
int FrustumOBBIntersection(OrientedBBox obb, FrustumGPU frustum)
{
// Test the OBB against frustum planes. Frustum planes are inward-facing.
// The OBB is outside if it's entirely behind one of the frustum planes.
// See "Real-Time Rendering", 3rd Edition, 16.10.2.
bool overlap = CheckOverlap(obb, frustum.normal0, frustum.dist0);
overlap = overlap && CheckOverlap(obb, frustum.normal1, frustum.dist1);
overlap = overlap && CheckOverlap(obb, frustum.normal2, frustum.dist2);
overlap = overlap && CheckOverlap(obb, frustum.normal3, frustum.dist3);
overlap = overlap && CheckOverlap(obb, frustum.normal4, frustum.dist4);
overlap = overlap && CheckOverlap(obb, frustum.normal5, frustum.dist5);
// Test the frustum corners against OBB planes. The OBB planes are outward-facing.
// The frustum is outside if all of its corners are entirely in front of one of the OBB planes.
// See "Correct Frustum Culling" by Inigo Quilez.
// We can exploit the symmetry of the box by only testing against 3 planes rather than 6.
FrustumPlane planes[3];
planes[0].normal = obb.right;
planes[0].dist = obb.extentX;
planes[1].normal = obb.up;
planes[1].dist = obb.extentY;
planes[2].normal = GetForward(obb);
planes[2].dist = obb.extentZ;
for (int i = 0; overlap && i < 3; i++)
{
// We need a separate counter for the "box fully inside frustum" case.
bool outsidePos = true; // Positive normal
bool outsideNeg = true; // Reversed normal
float proj = 0.0;
// Merge 2 loops. Continue as long as all points are outside either plane.
// Corner 0
proj = dot(planes[i].normal, frustum.corner0.xyz - obb.center);
outsidePos = outsidePos && (proj > planes[i].dist);
outsideNeg = outsideNeg && (-proj > planes[i].dist);
// Corner 1
proj = dot(planes[i].normal, frustum.corner1.xyz - obb.center);
outsidePos = outsidePos && (proj > planes[i].dist);
outsideNeg = outsideNeg && (-proj > planes[i].dist);
// Corner 2
proj = dot(planes[i].normal, frustum.corner2.xyz - obb.center);
outsidePos = outsidePos && (proj > planes[i].dist);
outsideNeg = outsideNeg && (-proj > planes[i].dist);
// Corner 3
proj = dot(planes[i].normal, frustum.corner3.xyz - obb.center);
outsidePos = outsidePos && (proj > planes[i].dist);
outsideNeg = outsideNeg && (-proj > planes[i].dist);
// Corner 4
proj = dot(planes[i].normal, frustum.corner4.xyz - obb.center);
outsidePos = outsidePos && (proj > planes[i].dist);
outsideNeg = outsideNeg && (-proj > planes[i].dist);
// Corner 5
proj = dot(planes[i].normal, frustum.corner5.xyz - obb.center);
outsidePos = outsidePos && (proj > planes[i].dist);
outsideNeg = outsideNeg && (-proj > planes[i].dist);
// Corner 6
proj = dot(planes[i].normal, frustum.corner6.xyz - obb.center);
outsidePos = outsidePos && (proj > planes[i].dist);
outsideNeg = outsideNeg && (-proj > planes[i].dist);
// Corner 7
proj = dot(planes[i].normal, frustum.corner7.xyz - obb.center);
outsidePos = outsidePos && (proj > planes[i].dist);
outsideNeg = outsideNeg && (-proj > planes[i].dist);
// Combine data of the previous plane
overlap = overlap && !(outsidePos || outsideNeg);
}
return overlap ? 1 : 0;
}
#endif // FRUSTUM_CULLING_H