227 lines
8.8 KiB
C#
227 lines
8.8 KiB
C#
using Unity.Collections;
|
|
using Unity.Jobs;
|
|
using Unity.Mathematics;
|
|
|
|
namespace UnityEngine.Rendering.Universal
|
|
{
|
|
internal struct DecalSubDrawCall
|
|
{
|
|
public int start;
|
|
public int end;
|
|
public int count { get => end - start; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Contains information about <see cref="DecalEntity"/> draw calls.
|
|
/// </summary>
|
|
internal class DecalDrawCallChunk : DecalChunk
|
|
{
|
|
public NativeArray<float4x4> decalToWorlds;
|
|
public NativeArray<float4x4> normalToDecals;
|
|
public NativeArray<DecalSubDrawCall> subCalls;
|
|
public NativeArray<int> subCallCounts;
|
|
|
|
public int subCallCount { set { subCallCounts[0] = value; } get => subCallCounts[0]; }
|
|
|
|
public override void RemoveAtSwapBack(int entityIndex)
|
|
{
|
|
RemoveAtSwapBack(ref decalToWorlds, entityIndex, count);
|
|
RemoveAtSwapBack(ref normalToDecals, entityIndex, count);
|
|
RemoveAtSwapBack(ref subCalls, entityIndex, count);
|
|
count--;
|
|
}
|
|
|
|
public override void SetCapacity(int newCapacity)
|
|
{
|
|
decalToWorlds.ResizeArray(newCapacity);
|
|
normalToDecals.ResizeArray(newCapacity);
|
|
subCalls.ResizeArray(newCapacity);
|
|
capacity = newCapacity;
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
subCallCounts.Dispose();
|
|
|
|
if (capacity == 0)
|
|
return;
|
|
|
|
decalToWorlds.Dispose();
|
|
normalToDecals.Dispose();
|
|
subCalls.Dispose();
|
|
count = 0;
|
|
capacity = 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Outputs draw calls into <see cref="DecalDrawCallChunk"/>.
|
|
/// </summary>
|
|
internal class DecalCreateDrawCallSystem
|
|
{
|
|
private DecalEntityManager m_EntityManager;
|
|
private ProfilingSampler m_Sampler;
|
|
private float m_MaxDrawDistance;
|
|
|
|
/// <summary>
|
|
/// Provides acces to the maximum draw distance.
|
|
/// </summary>
|
|
public float maxDrawDistance
|
|
{
|
|
get { return m_MaxDrawDistance; }
|
|
set { m_MaxDrawDistance = value; }
|
|
}
|
|
|
|
public DecalCreateDrawCallSystem(DecalEntityManager entityManager, float maxDrawDistance)
|
|
{
|
|
m_EntityManager = entityManager;
|
|
m_Sampler = new ProfilingSampler("DecalCreateDrawCallSystem.Execute");
|
|
m_MaxDrawDistance = maxDrawDistance;
|
|
}
|
|
|
|
public void Execute()
|
|
{
|
|
using (new ProfilingScope(null, m_Sampler))
|
|
{
|
|
for (int i = 0; i < m_EntityManager.chunkCount; ++i)
|
|
Execute(m_EntityManager.cachedChunks[i], m_EntityManager.culledChunks[i], m_EntityManager.drawCallChunks[i], m_EntityManager.cachedChunks[i].count);
|
|
}
|
|
}
|
|
|
|
private void Execute(DecalCachedChunk cachedChunk, DecalCulledChunk culledChunk, DecalDrawCallChunk drawCallChunk, int count)
|
|
{
|
|
if (count == 0)
|
|
return;
|
|
|
|
DrawCallJob drawCallJob = new DrawCallJob()
|
|
{
|
|
decalToWorlds = cachedChunk.decalToWorlds,
|
|
normalToWorlds = cachedChunk.normalToWorlds,
|
|
sizeOffsets = cachedChunk.sizeOffsets,
|
|
drawDistances = cachedChunk.drawDistances,
|
|
angleFades = cachedChunk.angleFades,
|
|
uvScaleBiases = cachedChunk.uvScaleBias,
|
|
layerMasks = cachedChunk.layerMasks,
|
|
sceneLayerMasks = cachedChunk.sceneLayerMasks,
|
|
fadeFactors = cachedChunk.fadeFactors,
|
|
boundingSpheres = cachedChunk.boundingSpheres,
|
|
|
|
cameraPosition = culledChunk.cameraPosition,
|
|
sceneCullingMask = culledChunk.sceneCullingMask,
|
|
cullingMask = culledChunk.cullingMask,
|
|
visibleDecalIndices = culledChunk.visibleDecalIndices,
|
|
visibleDecalCount = culledChunk.visibleDecalCount,
|
|
maxDrawDistance = m_MaxDrawDistance,
|
|
|
|
decalToWorldsDraw = drawCallChunk.decalToWorlds,
|
|
normalToDecalsDraw = drawCallChunk.normalToDecals,
|
|
subCalls = drawCallChunk.subCalls,
|
|
subCallCount = drawCallChunk.subCallCounts,
|
|
};
|
|
|
|
var handle = drawCallJob.Schedule(cachedChunk.currentJobHandle);
|
|
drawCallChunk.currentJobHandle = handle;
|
|
cachedChunk.currentJobHandle = handle;
|
|
}
|
|
|
|
#if ENABLE_BURST_1_0_0_OR_NEWER
|
|
[Unity.Burst.BurstCompile]
|
|
#endif
|
|
struct DrawCallJob : IJob
|
|
{
|
|
[ReadOnly] public NativeArray<float4x4> decalToWorlds;
|
|
[ReadOnly] public NativeArray<float4x4> normalToWorlds;
|
|
[ReadOnly] public NativeArray<float4x4> sizeOffsets;
|
|
[ReadOnly] public NativeArray<float2> drawDistances;
|
|
[ReadOnly] public NativeArray<float2> angleFades;
|
|
[ReadOnly] public NativeArray<float4> uvScaleBiases;
|
|
[ReadOnly] public NativeArray<int> layerMasks;
|
|
[ReadOnly] public NativeArray<ulong> sceneLayerMasks;
|
|
[ReadOnly] public NativeArray<float> fadeFactors;
|
|
[ReadOnly] public NativeArray<BoundingSphere> boundingSpheres;
|
|
|
|
public Vector3 cameraPosition;
|
|
public ulong sceneCullingMask;
|
|
public int cullingMask;
|
|
[ReadOnly] public NativeArray<int> visibleDecalIndices;
|
|
public int visibleDecalCount;
|
|
public float maxDrawDistance;
|
|
|
|
[WriteOnly] public NativeArray<float4x4> decalToWorldsDraw;
|
|
[WriteOnly] public NativeArray<float4x4> normalToDecalsDraw;
|
|
[WriteOnly] public NativeArray<DecalSubDrawCall> subCalls;
|
|
[WriteOnly] public NativeArray<int> subCallCount;
|
|
|
|
public void Execute()
|
|
{
|
|
int subCallIndex = 0;
|
|
int instanceIndex = 0;
|
|
int instanceStart = 0;
|
|
|
|
for (int i = 0; i < visibleDecalCount; ++i)
|
|
{
|
|
int decalIndex = visibleDecalIndices[i];
|
|
|
|
#if UNITY_EDITOR
|
|
ulong decalSceneCullingMask = sceneLayerMasks[decalIndex];
|
|
if ((sceneCullingMask & decalSceneCullingMask) == 0)
|
|
continue;
|
|
#endif
|
|
int decalMask = 1 << layerMasks[decalIndex];
|
|
if ((cullingMask & decalMask) == 0)
|
|
continue;
|
|
|
|
BoundingSphere boundingSphere = boundingSpheres[decalIndex];
|
|
float2 drawDistance = drawDistances[decalIndex];
|
|
|
|
float distanceToDecal = (cameraPosition - boundingSphere.position).magnitude;
|
|
float cullDistance = math.min(drawDistance.x, maxDrawDistance) + boundingSphere.radius;
|
|
if (distanceToDecal > cullDistance)
|
|
continue;
|
|
|
|
decalToWorldsDraw[instanceIndex] = decalToWorlds[decalIndex];
|
|
|
|
float fadeFactorScaler = fadeFactors[decalIndex];
|
|
float2 angleFade = angleFades[decalIndex];
|
|
float4 uvScaleBias = uvScaleBiases[decalIndex];
|
|
|
|
float4x4 normalToDecals = normalToWorlds[decalIndex];
|
|
// NormalToWorldBatchis a Matrix4x4x but is a Rotation matrix so bottom row and last column can be used for other data to save space
|
|
float fadeFactor = fadeFactorScaler * math.clamp((cullDistance - distanceToDecal) / (cullDistance * (1.0f - drawDistance.y)), 0.0f, 1.0f);
|
|
normalToDecals.c0.w = uvScaleBias.x;
|
|
normalToDecals.c1.w = uvScaleBias.y;
|
|
normalToDecals.c2.w = uvScaleBias.z;
|
|
normalToDecals.c3 = new float4(fadeFactor * 1.0f, angleFade.x, angleFade.y, uvScaleBias.w);
|
|
normalToDecalsDraw[instanceIndex] = normalToDecals;
|
|
|
|
instanceIndex++;
|
|
|
|
int instanceCount = instanceIndex - instanceStart;
|
|
bool isReachedMaximumBatchSize = instanceCount >= 250;
|
|
if (isReachedMaximumBatchSize)
|
|
{
|
|
subCalls[subCallIndex++] = new DecalSubDrawCall()
|
|
{
|
|
start = instanceStart,
|
|
end = instanceIndex,
|
|
};
|
|
instanceStart = instanceIndex;
|
|
}
|
|
}
|
|
|
|
int remainingInstanceCount = instanceIndex - instanceStart;
|
|
if (remainingInstanceCount != 0)
|
|
{
|
|
subCalls[subCallIndex++] = new DecalSubDrawCall()
|
|
{
|
|
start = instanceStart,
|
|
end = instanceIndex,
|
|
};
|
|
}
|
|
|
|
subCallCount[0] = subCallIndex;
|
|
}
|
|
}
|
|
}
|
|
}
|