Added AoVolumePassContext;
Added AoVolumePassBuffer; Changed center of each OBB in FrustumCullingJob from world position to camera-relative world position; Changed outputVolumeData and outputVolumeBounds from NativeList to NativeArray;
This commit is contained in:
@@ -1,120 +0,0 @@
|
||||
#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
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afe7ff9488a706a4591d7d9b59aa8c94
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,10 +1,11 @@
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.HighDefinition;
|
||||
|
||||
namespace Misaki.AoVolume
|
||||
{
|
||||
[GenerateHLSL(PackingRules.Exact, false)]
|
||||
internal struct GPUFrustum
|
||||
internal struct NativeFrustum
|
||||
{
|
||||
// The data of the 6 planes of the frustum
|
||||
public float3 normal0;
|
||||
@@ -21,14 +22,42 @@ namespace Misaki.AoVolume
|
||||
public float dist5;
|
||||
|
||||
// The data of the 8 corners of the frustum
|
||||
public float4 corner0;
|
||||
public float4 corner1;
|
||||
public float4 corner2;
|
||||
public float4 corner3;
|
||||
public float4 corner4;
|
||||
public float4 corner5;
|
||||
public float4 corner6;
|
||||
public float4 corner7;
|
||||
public float3 corner0;
|
||||
public float3 corner1;
|
||||
public float3 corner2;
|
||||
public float3 corner3;
|
||||
public float3 corner4;
|
||||
public float3 corner5;
|
||||
public float3 corner6;
|
||||
public float3 corner7;
|
||||
|
||||
public static NativeFrustum Create(in Frustum cameraFrustum)
|
||||
{
|
||||
return new NativeFrustum
|
||||
{
|
||||
normal0 = cameraFrustum.planes[0].normal,
|
||||
dist0 = cameraFrustum.planes[0].distance,
|
||||
normal1 = cameraFrustum.planes[1].normal,
|
||||
dist1 = cameraFrustum.planes[1].distance,
|
||||
normal2 = cameraFrustum.planes[2].normal,
|
||||
dist2 = cameraFrustum.planes[2].distance,
|
||||
normal3 = cameraFrustum.planes[3].normal,
|
||||
dist3 = cameraFrustum.planes[3].distance,
|
||||
normal4 = cameraFrustum.planes[4].normal,
|
||||
dist4 = cameraFrustum.planes[4].distance,
|
||||
normal5 = cameraFrustum.planes[5].normal,
|
||||
dist5 = cameraFrustum.planes[5].distance,
|
||||
|
||||
corner1 = cameraFrustum.corners[1],
|
||||
corner2 = cameraFrustum.corners[2],
|
||||
corner3 = cameraFrustum.corners[3],
|
||||
corner4 = cameraFrustum.corners[4],
|
||||
corner5 = cameraFrustum.corners[5],
|
||||
corner0 = cameraFrustum.corners[0],
|
||||
corner6 = cameraFrustum.corners[6],
|
||||
corner7 = cameraFrustum.corners[7]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[GenerateHLSL(PackingRules.Exact, false)]
|
||||
@@ -36,11 +65,12 @@ namespace Misaki.AoVolume
|
||||
{
|
||||
// 4 x float3 = 48 bytes.
|
||||
// TODO: pack the axes into 16-bit UNORM per channel, and consider a quaternionic representation.
|
||||
public float3 center;
|
||||
public float3 right;
|
||||
public float3 up;
|
||||
|
||||
public float3 extent;
|
||||
public Vector3 center;
|
||||
public float extentX;
|
||||
public Vector3 right;
|
||||
public float extentY;
|
||||
public Vector3 up;
|
||||
public float extentZ;
|
||||
|
||||
//public ushort quatX;
|
||||
//public ushort quatY;
|
||||
@@ -51,24 +81,21 @@ namespace Misaki.AoVolume
|
||||
|
||||
public OrientedBoundingBox(float4x4 trs)
|
||||
{
|
||||
float3 vecX = trs.c0.xyz;
|
||||
float3 vecY = trs.c1.xyz;
|
||||
float3 vecZ = trs.c2.xyz;
|
||||
var vecX = trs.c0.xyz;
|
||||
var vecY = trs.c1.xyz;
|
||||
var vecZ = trs.c2.xyz;
|
||||
|
||||
center = trs.c3.xyz;
|
||||
right = vecX * (1.0f / math.length(vecX));
|
||||
up = vecY * (1.0f / math.length(vecY));
|
||||
|
||||
extent.x = 0.5f * math.length(vecX);
|
||||
extent.y = 0.5f * math.length(vecY);
|
||||
extent.z = 0.5f * math.length(vecZ);
|
||||
extentX = 0.5f * math.length(vecX);
|
||||
extentY = 0.5f * math.length(vecY);
|
||||
extentZ = 0.5f * math.length(vecZ);
|
||||
}
|
||||
|
||||
public OrientedBoundingBox(Matrix4x4 trs) : this((float4x4)trs)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[GenerateHLSL(PackingRules.Exact, false)]
|
||||
internal struct CullingData
|
||||
{
|
||||
public float fadeStart;
|
||||
public float fadeEnd;
|
||||
}
|
||||
}
|
||||
@@ -4,48 +4,16 @@
|
||||
|
||||
#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.GPUFrustum
|
||||
// PackingRules = Exact
|
||||
struct GPUFrustum
|
||||
{
|
||||
float4 normal0;
|
||||
float dist0;
|
||||
float4 normal1;
|
||||
float dist1;
|
||||
float4 normal2;
|
||||
float dist2;
|
||||
float4 normal3;
|
||||
float dist3;
|
||||
float4 normal4;
|
||||
float dist4;
|
||||
float4 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
|
||||
{
|
||||
float4 center;
|
||||
float4 right;
|
||||
float4 up;
|
||||
float4 extent;
|
||||
float3 center;
|
||||
float extentX;
|
||||
float3 right;
|
||||
float extentY;
|
||||
float3 up;
|
||||
float extentZ;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
@@ -11,12 +10,12 @@ namespace Misaki.AoVolume
|
||||
{
|
||||
[HideInInspector]
|
||||
[NonSerialized]
|
||||
public float4x4 worldMatrix;
|
||||
public Matrix4x4 worldMatrix;
|
||||
[HideInInspector]
|
||||
[NonSerialized]
|
||||
public float4x4 inverseWorldMatrix;
|
||||
public Matrix4x4 inverseWorldMatrix;
|
||||
|
||||
public float3 size;
|
||||
public Vector3 size;
|
||||
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float intensity;
|
||||
@@ -24,13 +23,15 @@ namespace Misaki.AoVolume
|
||||
public float falloff;
|
||||
[Range(0.0f, 1.0f)]
|
||||
public float normalFalloff;
|
||||
public float cullDistance;
|
||||
|
||||
public static VolumeData Default => new()
|
||||
{
|
||||
size = new float3(1f),
|
||||
size = Vector3.one,
|
||||
intensity = 1.0f,
|
||||
falloff = 0.25f,
|
||||
normalFalloff = 0.0f
|
||||
normalFalloff = 0.0f,
|
||||
cullDistance = 100.0f
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ struct VolumeData
|
||||
float intensity;
|
||||
float falloff;
|
||||
float normalFalloff;
|
||||
float cullDistance;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#ifndef VOLUME_SDF
|
||||
#define VOLUME_SDF
|
||||
|
||||
float3 GetPositionOS(float4x4 inverseWorldMatrix, float3 positionWS)
|
||||
{
|
||||
// To handle camera relative rendering we need to apply translation before converting to object space
|
||||
return mul(ApplyCameraTranslationToInverseMatrix(inverseWorldMatrix), float4(positionWS, 1.0)).xyz;
|
||||
}
|
||||
|
||||
float BoxSDF(float3 positionWS, VolumeData data)
|
||||
{
|
||||
float3 halfDim = data.size * 0.5;
|
||||
|
||||
float3 positionLS = GetPositionOS(data.inverseWorldMatrix, positionWS);
|
||||
|
||||
float3 d = halfDim - abs(positionLS);
|
||||
float distToFace = min(d.x, min(d.y, d.z));
|
||||
float maxDist = min(halfDim.x, min(halfDim.y, halfDim.z));
|
||||
|
||||
return saturate(distToFace / maxDist);
|
||||
}
|
||||
|
||||
float CapsuleSDF(float3 positionWS, VolumeData data)
|
||||
{
|
||||
float3 positionLS = GetPositionOS(data.inverseWorldMatrix, positionWS);
|
||||
|
||||
float radius = data.size.x;
|
||||
float length = data.size.y;
|
||||
|
||||
// Define capsule along Y-axis in local space
|
||||
float3 capsuleStart = float3(0, -length * 0.5, 0);
|
||||
float3 capsuleEnd = float3(0, length * 0.5, 0);
|
||||
|
||||
// Compute SDF in local space
|
||||
float3 dir = capsuleEnd - capsuleStart;
|
||||
float lengthSq = dot(dir, dir);
|
||||
float3 toPoint = positionLS - capsuleStart;
|
||||
float projection = saturate(dot(toPoint, dir) / lengthSq);
|
||||
float3 closestPoint = capsuleStart + projection * dir;
|
||||
return distance(positionLS, closestPoint) - radius;
|
||||
}
|
||||
|
||||
float EvaluateAOVolumeMask(VolumeData data, float3 positionWS, float3 normalWS)
|
||||
{
|
||||
return BoxSDF(positionWS, data);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 415aa9e4981653147803fb5036c79f4c
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user