Added frustum culling;
Added geometry data; Changed name of VolumeObject to AoVolume; Removed the capsule type in VolumeType, all volumes are box volume now;
This commit is contained in:
120
Runtime/Shader/Includes/FrustumCulling.hlsl
Normal file
120
Runtime/Shader/Includes/FrustumCulling.hlsl
Normal file
@@ -0,0 +1,120 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user