Added geometry data; Changed name of VolumeObject to AoVolume; Removed the capsule type in VolumeType, all volumes are box volume now;
120 lines
4.6 KiB
HLSL
120 lines
4.6 KiB
HLSL
#ifndef FRUSTUM_CULLING
|
|
#define FRUSTUM_CULLING
|
|
|
|
#include "Packages/com.misaki.ao-volume/Runtime/Shader/Includes/GeometryData.cs.hlsl"
|
|
|
|
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];
|
|
};
|
|
|
|
float3 GetForward(OrientedBoundingBox value)
|
|
{
|
|
return cross(value.up, value.right);
|
|
}
|
|
|
|
bool CheckOverlap(OrientedBoundingBox obb, float3 planeNormal, float planeDistance)
|
|
{
|
|
// Max projection of the half-diagonal onto the normal (always positive).
|
|
float maxHalfDiagProj = obb.extent.x * abs(dot(planeNormal, obb.right))
|
|
+ obb.extent.y * abs(dot(planeNormal, obb.up))
|
|
+ obb.extent.z * 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);
|
|
}
|
|
|
|
bool FrustumOBBIntersection(OrientedBoundingBox 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.extent.x;
|
|
planes[1].normal = obb.up;
|
|
planes[1].dist = obb.extent.y;
|
|
planes[2].normal = GetForward(obb);
|
|
planes[2].dist = obb.extent.z;
|
|
|
|
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;
|
|
}
|
|
|
|
#endif |