initial commit

This commit is contained in:
Jo 2025-01-07 02:06:59 +01:00
parent 6715289efe
commit 788c3389af
37645 changed files with 2526849 additions and 80 deletions

View file

@ -0,0 +1,35 @@
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace UnityEngine.Rendering.Universal
{
[BurstCompile]
struct LightExtractionJob : IJobFor
{
[ReadOnly]
public NativeArray<VisibleLight> lights;
public NativeArray<LightType> lightTypes;
public NativeArray<float> radiuses;
public NativeArray<float3> directions;
public NativeArray<float3> positions;
public NativeArray<float> coneRadiuses;
public void Execute(int index)
{
var light = lights[index];
var localToWorldMatrix = (float4x4)light.localToWorldMatrix;
lightTypes[index] = light.lightType;
radiuses[index] = light.range;
directions[index] = localToWorldMatrix.c2.xyz;
positions[index] = localToWorldMatrix.c3.xyz;
coneRadiuses[index] = math.tan(math.radians(light.spotAngle * 0.5f)) * light.range;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7a39173dadb4c402d9d337545c6e8bd0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,65 @@
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace UnityEngine.Rendering.Universal
{
struct LightMinMaxZ
{
public float minZ;
public float maxZ;
}
[BurstCompile]
struct MinMaxZJob : IJobFor
{
public float4x4 worldToViewMatrix;
[ReadOnly]
public NativeArray<VisibleLight> lights;
public NativeArray<LightMinMaxZ> minMaxZs;
public NativeArray<float> meanZs;
public void Execute(int index)
{
var light = lights[index];
var lightToWorld = (float4x4)light.localToWorldMatrix;
var originWS = lightToWorld.c3.xyz;
var originVS = math.mul(worldToViewMatrix, math.float4(originWS, 1)).xyz;
originVS.z *= -1;
var minMax = new LightMinMaxZ
{
minZ = originVS.z - light.range,
maxZ = originVS.z + light.range
};
if (light.lightType == LightType.Spot)
{
// Based on https://iquilezles.org/www/articles/diskbbox/diskbbox.htm
var angleA = math.radians(light.spotAngle) * 0.5f;
float cosAngleA = math.cos(angleA);
float coneHeight = light.range * cosAngleA;
float3 spotDirectionWS = lightToWorld.c2.xyz;
var endPointWS = originWS + spotDirectionWS * coneHeight;
var endPointVS = math.mul(worldToViewMatrix, math.float4(endPointWS, 1)).xyz;
endPointVS.z *= -1;
var angleB = math.PI * 0.5f - angleA;
var coneRadius = light.range * cosAngleA * math.sin(angleA) / math.sin(angleB);
var a = endPointVS - originVS;
var e = math.sqrt(1.0f - a.z * a.z / math.dot(a, a));
// `-a.z` and `a.z` is `dot(a, {0, 0, -1}).z` and `dot(a, {0, 0, 1}).z` optimized
// `cosAngleA` is multiplied by `coneHeight` to avoid normalizing `a`, which we know has length `coneHeight`
if (-a.z < coneHeight * cosAngleA) minMax.minZ = math.min(originVS.z, endPointVS.z - e * coneRadius);
if (a.z < coneHeight * cosAngleA) minMax.maxZ = math.max(originVS.z, endPointVS.z + e * coneRadius);
}
minMax.minZ = math.max(minMax.minZ, 0);
minMax.maxZ = math.max(minMax.maxZ, 0);
minMaxZs[index] = minMax;
meanZs[index] = (minMax.minZ + minMax.maxZ) / 2.0f;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c7144b5b3e5194263a2f290811e97974
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,70 @@
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
namespace UnityEngine.Rendering.Universal
{
// This could be multi-threaded if profiling shows need
[BurstCompile]
unsafe struct RadixSortJob : IJob
{
public NativeArray<uint> keys;
public NativeArray<int> indices;
public void Execute()
{
var counts = new NativeArray<int>(256, Allocator.Temp);
var n = indices.Length / 2;
for (var i = 0; i < n; i++)
{
indices[i] = i;
}
for (var i = 0; i < 4; i++)
{
int currentOffset, nextOffset;
for (var j = 0; j < 256; j++)
{
counts[j] = 0;
}
if (i % 2 == 0)
{
currentOffset = 0;
nextOffset = n;
}
else
{
currentOffset = n;
nextOffset = 0;
}
for (var j = 0; j < n; j++)
{
var key = keys[currentOffset + j];
var bucket = (key >> (8 * i)) & 0xFF;
counts[(int)bucket]++;
}
for (var j = 1; j < 256; j++)
{
counts[j] += counts[j - 1];
}
for (var j = n - 1; j >= 0; j--)
{
var key = keys[currentOffset + j];
var bucket = (key >> (8 * i)) & 0xFF;
var newIndex = counts[(int)bucket] - 1;
counts[(int)bucket]--;
keys[nextOffset + newIndex] = key;
indices[nextOffset + newIndex] = indices[currentOffset + j];
}
}
counts.Dispose();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7d809dd521d214310bc148d1dc02f98f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,27 @@
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace UnityEngine.Rendering.Universal
{
[BurstCompile]
struct ReorderJob<T> : IJobFor
where T : struct
{
[ReadOnly]
public NativeArray<int> indices;
[ReadOnly]
public NativeArray<T> input;
[NativeDisableParallelForRestriction]
public NativeArray<T> output;
public void Execute(int index)
{
var newIndex = indices[index];
output[newIndex] = input[index];
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ff96ea8778cf84d659b1bd2c721e4819
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,39 @@
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace UnityEngine.Rendering.Universal
{
[BurstCompile]
unsafe struct SliceCombineJob : IJobFor
{
public int2 tileResolution;
public int wordsPerTile;
[ReadOnly]
public NativeArray<uint> sliceLightMasksH;
[ReadOnly]
public NativeArray<uint> sliceLightMasksV;
[NativeDisableParallelForRestriction]
public NativeArray<uint> lightMasks;
public void Execute(int idY)
{
var baseIndexH = idY * wordsPerTile;
var baseIndexRow = baseIndexH * tileResolution.x;
for (var idX = 0; idX < tileResolution.x; idX++)
{
var baseIndexV = idX * wordsPerTile;
var baseIndexTile = baseIndexRow + baseIndexV;
for (var wordIndex = 0; wordIndex < wordsPerTile; wordIndex++)
{
lightMasks[baseIndexTile + wordIndex] = sliceLightMasksH[baseIndexH + wordIndex] & sliceLightMasksV[baseIndexV + wordIndex];
}
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5df5478e52f204fdea0fbfc8ab3d22de
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,165 @@
using System.Runtime.CompilerServices;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace UnityEngine.Rendering.Universal
{
// Culls slices along one axis of the screen.
[BurstCompile]
unsafe struct SliceCullingJob : IJobFor
{
public float scale;
public float3 viewOrigin;
public float3 viewForward;
public float3 viewRight;
public float3 viewUp;
[ReadOnly]
public NativeArray<LightType> lightTypes;
[ReadOnly]
public NativeArray<float> radiuses;
[ReadOnly]
public NativeArray<float3> directions;
[ReadOnly]
public NativeArray<float3> positions;
[ReadOnly]
public NativeArray<float> coneRadiuses;
public int lightsPerTile;
[NativeDisableParallelForRestriction]
public NativeArray<uint> sliceLightMasks;
public void Execute(int index)
{
var leftX = (((float)index) * scale) * 2f - 1f;
var rightX = (((float)index + 1f) * scale) * 2f - 1f;
var leftPlane = ComputePlane(viewOrigin,
viewOrigin + viewForward + viewRight * leftX + viewUp,
viewOrigin + viewForward + viewRight * leftX - viewUp);
var rightPlane = ComputePlane(viewOrigin,
viewOrigin + viewForward + viewRight * rightX - viewUp,
viewOrigin + viewForward + viewRight * rightX + viewUp);
var lightCount = lightTypes.Length;
var lightWordCount = (lightCount + 31) / 32;
var sectionOffset = index * lightsPerTile / 32;
// Handle lights in multiples of 32
for (var lightWordIndex = 0; lightWordIndex < lightWordCount; lightWordIndex++)
{
var wordLightMask = 0u;
var lightsInWord = math.min(32, lightCount - lightWordIndex * 32);
for (var bitIndex = 0; bitIndex < lightsInWord; bitIndex++)
{
var lightIndex = lightWordIndex * 32 + bitIndex;
if (ContainsLight(leftPlane, rightPlane, lightIndex))
{
wordLightMask |= 1u << bitIndex;
}
}
var wordIndex = sectionOffset + lightWordIndex;
sliceLightMasks[wordIndex] = sliceLightMasks[wordIndex] | wordLightMask;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
bool ContainsLight(Plane leftPlane, Plane rightPlane, int lightIndex)
{
var hit = true;
var sphere = new Sphere
{
center = positions[lightIndex],
radius = radiuses[lightIndex]
};
if (SphereBehindPlane(sphere, leftPlane) || SphereBehindPlane(sphere, rightPlane))
{
hit = false;
}
if (hit && lightTypes[lightIndex] == LightType.Spot)
{
var cone = new Cone
{
tip = sphere.center,
direction = directions[lightIndex],
height = radiuses[lightIndex],
radius = coneRadiuses[lightIndex]
};
if (ConeBehindPlane(cone, leftPlane) || ConeBehindPlane(cone, rightPlane))
{
hit = false;
}
}
return hit;
}
struct Cone
{
public float3 tip;
public float3 direction;
public float height;
public float radius;
}
struct Sphere
{
public float3 center;
public float radius;
}
struct Plane
{
public float3 normal;
public float distanceToOrigin;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static Plane ComputePlane(float3 p0, float3 p1, float3 p2)
{
Plane plane;
float3 v0 = p1 - p0;
float3 v2 = p2 - p0;
plane.normal = math.normalize(math.cross(v0, v2));
// Compute the distance to the origin using p0.
plane.distanceToOrigin = math.dot(plane.normal, p0);
return plane;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool SphereBehindPlane(Sphere sphere, Plane plane)
{
float dist = math.dot(sphere.center, plane.normal) - plane.distanceToOrigin;
return dist < -sphere.radius;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool PointBehindPlane(float3 p, Plane plane)
{
return math.dot(plane.normal, p) - plane.distanceToOrigin < 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static bool ConeBehindPlane(Cone cone, Plane plane)
{
float3 furthestPointDirection = math.cross(math.cross(plane.normal, cone.direction), cone.direction);
float3 furthestPointOnCircle = cone.tip + cone.direction * cone.height - furthestPointDirection * cone.radius;
return PointBehindPlane(cone.tip, plane) && PointBehindPlane(furthestPointOnCircle, plane);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bc45902ab38cd4ebe8e33c7792204ded
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,18 @@
namespace UnityEngine.Rendering.Universal
{
internal enum TileSize
{
_8 = 8,
_16 = 16,
_32 = 32,
_64 = 64
}
static class TileSizeExtensions
{
public static bool IsValid(this TileSize tileSize)
{
return tileSize == TileSize._8 || tileSize == TileSize._16 || tileSize == TileSize._32 || tileSize == TileSize._64;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c7b4abc88bafe43ecb5380692ea7e4fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,61 @@
using System;
using System.Runtime.InteropServices;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
namespace UnityEngine.Rendering.Universal
{
[StructLayout(LayoutKind.Sequential)]
struct ZBin
{
public ushort minIndex;
public ushort maxIndex;
}
[BurstCompile]
unsafe struct ZBinningJob : IJobFor
{
// Do not use this for the innerloopBatchCount (use 1 for that). Use for dividing the arrayLength when scheduling.
public const int batchCount = 64;
[NativeDisableParallelForRestriction]
public NativeArray<ZBin> bins;
[ReadOnly]
public NativeArray<LightMinMaxZ> minMaxZs;
public int binOffset;
public float zFactor;
public void Execute(int index)
{
var binsStart = batchCount * index;
var binsEnd = math.min(binsStart + batchCount, bins.Length) - 1;
for (var i = binsStart; i <= binsEnd; i++)
{
bins[i] = new ZBin { minIndex = ushort.MaxValue, maxIndex = ushort.MaxValue };
}
for (var lightIndex = 0; lightIndex < minMaxZs.Length; lightIndex++)
{
var ushortLightIndex = (ushort)lightIndex;
var minMax = minMaxZs[lightIndex];
var minBin = math.max((int)(math.sqrt(minMax.minZ) * zFactor) - binOffset, binsStart);
var maxBin = math.min((int)(math.sqrt(minMax.maxZ) * zFactor) - binOffset, binsEnd);
for (var binIndex = minBin; binIndex <= maxBin; binIndex++)
{
var bin = bins[binIndex];
bin.minIndex = Math.Min(bin.minIndex, ushortLightIndex);
// This will always be the largest light index this bin has seen due to light iteration order.
bin.maxIndex = ushortLightIndex;
bins[binIndex] = bin;
}
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ddf10b9a46e641ae8ba73c89b46512c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: