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:
164
Runtime/Jobs/FrustumCullingJob.cs
Normal file
164
Runtime/Jobs/FrustumCullingJob.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
namespace Misaki.AoVolume
|
||||
{
|
||||
//[BurstCompile]
|
||||
internal struct FrustumCullingJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeArray<VolumeData> inputVolumeDatas;
|
||||
public NativeFrustum frustum;
|
||||
public float3 cameraPosition;
|
||||
public bool useCameraRelativeRendering;
|
||||
|
||||
[WriteOnly]
|
||||
public NativeArray<int> visibleCounter;
|
||||
[WriteOnly]
|
||||
public NativeArray<VolumeData> outputVolumeData;
|
||||
[WriteOnly]
|
||||
public NativeArray<OrientedBoundingBox> outputVolumeBounds;
|
||||
|
||||
private struct FrustumPlane
|
||||
{
|
||||
public float3 normal;
|
||||
public float distance;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static float3 GetForward(OrientedBoundingBox obb)
|
||||
{
|
||||
return cross(obb.up, obb.right);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool CheckOverlap(OrientedBoundingBox obb, float3 planeNormal, float planeDistance)
|
||||
{
|
||||
var maxHalfDiagonalProjection = obb.extentX * abs(dot(planeNormal, obb.right)) +
|
||||
obb.extentY * abs(dot(planeNormal, obb.up)) +
|
||||
obb.extentZ * abs(dot(planeNormal, GetForward(obb)));
|
||||
var centerProjection = dot(planeNormal, obb.center) + planeDistance;
|
||||
return maxHalfDiagonalProjection + centerProjection >= 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private readonly float4x4 ApplyCameraTranslationToMatrix(float4x4 modelMatrix)
|
||||
{
|
||||
if (useCameraRelativeRendering)
|
||||
{
|
||||
modelMatrix.c3.x -= cameraPosition.x;
|
||||
modelMatrix.c3.y -= cameraPosition.y;
|
||||
modelMatrix.c3.z -= cameraPosition.z;
|
||||
}
|
||||
return modelMatrix;
|
||||
}
|
||||
|
||||
private bool FrustumObbIntersection(OrientedBoundingBox obb)
|
||||
{
|
||||
var overlap = CheckOverlap(obb, frustum.normal0, frustum.dist0);
|
||||
overlap &= CheckOverlap(obb, frustum.normal1, frustum.dist1);
|
||||
overlap &= CheckOverlap(obb, frustum.normal2, frustum.dist2);
|
||||
overlap &= CheckOverlap(obb, frustum.normal3, frustum.dist3);
|
||||
overlap &= CheckOverlap(obb, frustum.normal4, frustum.dist4);
|
||||
overlap &= CheckOverlap(obb, frustum.normal5, frustum.dist5);
|
||||
|
||||
var planes = new NativeArray<FrustumPlane>(3, Allocator.Temp);
|
||||
planes[0] = new FrustumPlane
|
||||
{
|
||||
normal = obb.right,
|
||||
distance = obb.extentX
|
||||
};
|
||||
planes[1] = new FrustumPlane
|
||||
{
|
||||
normal = obb.up,
|
||||
distance = obb.extentY
|
||||
};
|
||||
planes[2] = new FrustumPlane
|
||||
{
|
||||
normal = GetForward(obb),
|
||||
distance = obb.extentZ
|
||||
};
|
||||
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
// We need a separate counter for the "box fully inside frustum" case.
|
||||
var outsidePos = true; // Positive normal
|
||||
var outsideNeg = true; // Reversed normal
|
||||
var center = new float3(obb.center);
|
||||
var proj = 0.0f;
|
||||
|
||||
// Merge 2 loops. Continue as long as all points are outside either plane.
|
||||
// Corner 0
|
||||
proj = dot(planes[i].normal, frustum.corner0.xyz - center);
|
||||
outsidePos = outsidePos && (proj > planes[i].distance);
|
||||
outsideNeg = outsideNeg && (-proj > planes[i].distance);
|
||||
|
||||
// Corner 1
|
||||
proj = dot(planes[i].normal, frustum.corner1.xyz - center);
|
||||
outsidePos = outsidePos && (proj > planes[i].distance);
|
||||
outsideNeg = outsideNeg && (-proj > planes[i].distance);
|
||||
|
||||
// Corner 2
|
||||
proj = dot(planes[i].normal, frustum.corner2.xyz - center);
|
||||
outsidePos = outsidePos && (proj > planes[i].distance);
|
||||
outsideNeg = outsideNeg && (-proj > planes[i].distance);
|
||||
|
||||
// Corner 3
|
||||
proj = dot(planes[i].normal, frustum.corner3.xyz - center);
|
||||
outsidePos = outsidePos && (proj > planes[i].distance);
|
||||
outsideNeg = outsideNeg && (-proj > planes[i].distance);
|
||||
|
||||
// Corner 4
|
||||
proj = dot(planes[i].normal, frustum.corner4.xyz - center);
|
||||
outsidePos = outsidePos && (proj > planes[i].distance);
|
||||
outsideNeg = outsideNeg && (-proj > planes[i].distance);
|
||||
|
||||
// Corner 5
|
||||
proj = dot(planes[i].normal, frustum.corner5.xyz - center);
|
||||
outsidePos = outsidePos && (proj > planes[i].distance);
|
||||
outsideNeg = outsideNeg && (-proj > planes[i].distance);
|
||||
|
||||
// Corner 6
|
||||
proj = dot(planes[i].normal, frustum.corner6.xyz - center);
|
||||
outsidePos = outsidePos && (proj > planes[i].distance);
|
||||
outsideNeg = outsideNeg && (-proj > planes[i].distance);
|
||||
|
||||
// Corner 7
|
||||
proj = dot(planes[i].normal, frustum.corner7.xyz - center);
|
||||
outsidePos = outsidePos && (proj > planes[i].distance);
|
||||
outsideNeg = outsideNeg && (-proj > planes[i].distance);
|
||||
|
||||
// Combine data of the previous plane
|
||||
overlap = overlap && !(outsidePos || outsideNeg);
|
||||
}
|
||||
|
||||
planes.Dispose();
|
||||
return overlap;
|
||||
}
|
||||
|
||||
public unsafe void Execute(int index)
|
||||
{
|
||||
var volumeData = inputVolumeDatas[index];
|
||||
|
||||
var obb = new OrientedBoundingBox(ApplyCameraTranslationToMatrix(volumeData.worldMatrix));
|
||||
|
||||
if (distance(cameraPosition, obb.center) > volumeData.cullDistance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (FrustumObbIntersection(obb))
|
||||
{
|
||||
var currentIndex = Interlocked.Increment(ref UnsafeUtility.AsRef<int>(visibleCounter.GetUnsafePtr())) - 1;
|
||||
|
||||
outputVolumeData[currentIndex] = volumeData;
|
||||
outputVolumeBounds[currentIndex] = obb;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user