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
|
||||
7
Runtime/Shader/Includes/FrustumCulling.hlsl.meta
Normal file
7
Runtime/Shader/Includes/FrustumCulling.hlsl.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afe7ff9488a706a4591d7d9b59aa8c94
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
74
Runtime/Shader/Includes/GeometryData.cs
Normal file
74
Runtime/Shader/Includes/GeometryData.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Misaki.AoVolume
|
||||
{
|
||||
[GenerateHLSL(PackingRules.Exact, false)]
|
||||
internal struct FrustumGPU
|
||||
{
|
||||
// The data of the 6 planes of the frustum
|
||||
public Vector3 normal0;
|
||||
public float dist0;
|
||||
public Vector3 normal1;
|
||||
public float dist1;
|
||||
public Vector3 normal2;
|
||||
public float dist2;
|
||||
public Vector3 normal3;
|
||||
public float dist3;
|
||||
public Vector3 normal4;
|
||||
public float dist4;
|
||||
public Vector3 normal5;
|
||||
public float dist5;
|
||||
|
||||
// The data of the 8 corners of the frustum
|
||||
public Vector4 corner0;
|
||||
public Vector4 corner1;
|
||||
public Vector4 corner2;
|
||||
public Vector4 corner3;
|
||||
public Vector4 corner4;
|
||||
public Vector4 corner5;
|
||||
public Vector4 corner6;
|
||||
public Vector4 corner7;
|
||||
}
|
||||
|
||||
[GenerateHLSL(PackingRules.Exact, false)]
|
||||
internal struct OrientedBoundingBox
|
||||
{
|
||||
// 4 x float3 = 48 bytes.
|
||||
// TODO: pack the axes into 16-bit UNORM per channel, and consider a quaternionic representation.
|
||||
public Vector3 center;
|
||||
public Vector3 right;
|
||||
public Vector3 up;
|
||||
|
||||
public Vector3 extent;
|
||||
|
||||
//public ushort quatX;
|
||||
//public ushort quatY;
|
||||
//public ushort quatZ;
|
||||
//public ushort quatW;
|
||||
|
||||
public readonly Vector3 Forward => Vector3.Cross(up, right);
|
||||
|
||||
public OrientedBoundingBox(Matrix4x4 trs)
|
||||
{
|
||||
var vecX = (Vector3)trs.GetColumn(0);
|
||||
var vecY = (Vector3)trs.GetColumn(1);
|
||||
var vecZ = (Vector3)trs.GetColumn(2);
|
||||
|
||||
center = trs.GetColumn(3);
|
||||
right = vecX * (1.0f / vecX.magnitude);
|
||||
up = vecY * (1.0f / vecY.magnitude);
|
||||
|
||||
extent.x = 0.5f * vecX.magnitude;
|
||||
extent.y = 0.5f * vecY.magnitude;
|
||||
extent.z = 0.5f * vecZ.magnitude;
|
||||
}
|
||||
}
|
||||
|
||||
[GenerateHLSL(PackingRules.Exact, false)]
|
||||
internal struct CullingData
|
||||
{
|
||||
public float fadeStart;
|
||||
public float fadeEnd;
|
||||
}
|
||||
}
|
||||
52
Runtime/Shader/Includes/GeometryData.cs.hlsl
Normal file
52
Runtime/Shader/Includes/GeometryData.cs.hlsl
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
|
||||
//
|
||||
|
||||
#ifndef GEOMETRYDATA_CS_HLSL
|
||||
#define GEOMETRYDATA_CS_HLSL
|
||||
// Generated from Misaki.AoVolume.CullingData
|
||||
// PackingRules = Exact
|
||||
struct CullingData
|
||||
{
|
||||
float fadeStart;
|
||||
float fadeEnd;
|
||||
};
|
||||
|
||||
// Generated from Misaki.AoVolume.FrustumGPU
|
||||
// PackingRules = Exact
|
||||
struct FrustumGPU
|
||||
{
|
||||
float3 normal0;
|
||||
float dist0;
|
||||
float3 normal1;
|
||||
float dist1;
|
||||
float3 normal2;
|
||||
float dist2;
|
||||
float3 normal3;
|
||||
float dist3;
|
||||
float3 normal4;
|
||||
float dist4;
|
||||
float3 normal5;
|
||||
float dist5;
|
||||
float4 corner0;
|
||||
float4 corner1;
|
||||
float4 corner2;
|
||||
float4 corner3;
|
||||
float4 corner4;
|
||||
float4 corner5;
|
||||
float4 corner6;
|
||||
float4 corner7;
|
||||
};
|
||||
|
||||
// Generated from Misaki.AoVolume.OrientedBoundingBox
|
||||
// PackingRules = Exact
|
||||
struct OrientedBoundingBox
|
||||
{
|
||||
float3 center;
|
||||
float3 right;
|
||||
float3 up;
|
||||
float3 extent;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
7
Runtime/Shader/Includes/GeometryData.cs.hlsl.meta
Normal file
7
Runtime/Shader/Includes/GeometryData.cs.hlsl.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2573ddb62fa31574e95e916fafd36e09
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2
Runtime/Shader/Includes/GeometryData.cs.meta
Normal file
2
Runtime/Shader/Includes/GeometryData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57d4b8b0df999734f9ba0a8d7aa29a4c
|
||||
@@ -4,20 +4,13 @@ using UnityEngine.Rendering;
|
||||
|
||||
namespace Misaki.AoVolume
|
||||
{
|
||||
[GenerateHLSL]
|
||||
internal enum VolumeType
|
||||
{
|
||||
Capsule,
|
||||
Box
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[GenerateHLSL(needAccessors = false)]
|
||||
[GenerateHLSL(PackingRules.Exact, false)]
|
||||
internal struct VolumeData
|
||||
{
|
||||
public VolumeType volumeType;
|
||||
|
||||
[HideInInspector]
|
||||
public Matrix4x4 worldMatrix;
|
||||
[HideInInspector]
|
||||
public Matrix4x4 inverseWorldMatrix;
|
||||
public Vector3 size;
|
||||
|
||||
|
||||
@@ -4,17 +4,10 @@
|
||||
|
||||
#ifndef VOLUMEDATA_CS_HLSL
|
||||
#define VOLUMEDATA_CS_HLSL
|
||||
//
|
||||
// Misaki.AoVolume.VolumeType: static fields
|
||||
//
|
||||
#define VOLUMETYPE_CAPSULE (0)
|
||||
#define VOLUMETYPE_BOX (1)
|
||||
|
||||
// Generated from Misaki.AoVolume.VolumeData
|
||||
// PackingRules = Exact
|
||||
struct VolumeData
|
||||
{
|
||||
int volumeType;
|
||||
float4x4 worldMatrix;
|
||||
float4x4 inverseWorldMatrix;
|
||||
float3 size;
|
||||
|
||||
@@ -43,18 +43,7 @@ float CapsuleSDF(float3 positionWS, VolumeData data)
|
||||
|
||||
float EvaluateAOVolumeMask(VolumeData data, float3 positionWS, float3 normalWS)
|
||||
{
|
||||
float volumeSDF = 1.0;
|
||||
switch (data.volumeType)
|
||||
{
|
||||
case VOLUMETYPE_CAPSULE:
|
||||
volumeSDF = CapsuleSDF(positionWS, data);
|
||||
break;
|
||||
case VOLUMETYPE_BOX:
|
||||
volumeSDF = BoxSDF(positionWS, data);
|
||||
break;
|
||||
}
|
||||
|
||||
return volumeSDF;
|
||||
return BoxSDF(positionWS, data);
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user