Files
UnrealEngine/Engine/Shaders/Private/PhysicsFieldBuilder.usf
2025-05-18 13:04:45 +08:00

136 lines
4.6 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
PhysicsFieldBuilder.ush
=============================================================================*/
#pragma once
#include "Common.ush"
#include "PhysicsFieldEval.ush"
/* -----------------------------------------------------------------
* Field System constants and context
* -----------------------------------------------------------------
*/
RWBuffer<float> FieldClipmap;
Buffer<int> CellsOffsets;
Buffer<uint4> CellsMin;
Buffer<uint4> CellsMax;
int ClipmapResolution;
float ClipmapDistance;
float3 ClipmapCenter;
int ClipmapCount;
int ClipmapExponent;
int ValidCount;
int ValidTargets[MAX_PHYSICS_FIELD_TARGETS];
int TargetsIndex[MAX_PHYSICS_FIELD_TARGETS];
int NumCells;
int TargetCount;
uint3 GetCellVoxel( in int ThreadId, in int CellIndex)
{
const int LocalIndex = ThreadId - CellsOffsets[CellIndex];
const uint4 CellsDelta = CellsMax[CellIndex] - CellsMin[CellIndex];
const int IndexZ = LocalIndex / (CellsDelta.y * CellsDelta.x);
const int IndexT = LocalIndex % (CellsDelta.y * CellsDelta.x);
const int IndexY = IndexT / CellsDelta.x;
const int IndexX = IndexT % CellsDelta.x;
return CellsMin[CellIndex].xyz + uint3(IndexX, IndexY, IndexZ);
}
int GetBufferOffset(in int CellTarget, in int CellClipmap, in uint3 CellVoxel)
{
const int DatasOffset = CellClipmap + TargetsIndex[CellTarget] * ClipmapCount;
return (CellVoxel.x + CellVoxel.y * ClipmapResolution + (CellVoxel.z + ClipmapResolution * DatasOffset) * ClipmapResolution * ClipmapResolution);
}
float GetClipmapFade(in int CellClipmap, in uint3 CellVoxel)
{
float ClipmapFade = 1.0;
if (CellClipmap == ClipmapCount - 1)
{
const float LimitDistance = (float) ClipmapResolution / 8.0;
const uint3 BorderDirection = min(uint3(ClipmapResolution - 1, ClipmapResolution - 1, ClipmapResolution - 1) - CellVoxel.xyz, CellVoxel.xyz);
const float BorderDistance = min(min(BorderDirection.x, BorderDirection.y), BorderDirection.z);
ClipmapFade = (BorderDistance < LimitDistance) ? (BorderDistance * BorderDistance / (LimitDistance * LimitDistance)) : 1.0;
}
return ClipmapFade;
}
float3 GetSamplePosition(in float ClipmapExtent, in uint3 CellVoxel)
{
const float3 SampleUV = (CellVoxel.xyz) / float3(ClipmapResolution - 1, ClipmapResolution - 1, ClipmapResolution - 1);
return ClipmapCenter + (SampleUV - 0.5) * 2.0 * ClipmapExtent;
}
[numthreads(BUILD_FIELD_THREAD_GROUP_SIZE, 1, 1)]
void BuildPhysicsFieldClipmapCS(
uint3 GroupId : SV_GroupID,
uint3 DispatchThreadId : SV_DispatchThreadID,
uint3 GroupThreadId : SV_GroupThreadID)
{
GFieldGroupThreadId = GroupThreadId.x;
if ((DispatchThreadId.x < NumCells))
{
int CellIndex = 0;
int CellTarget = -1;
for (int ValidIndex = 0; ValidIndex < ValidCount; ++ValidIndex, CellIndex += ClipmapCount)
{
if ((DispatchThreadId.x >= CellsOffsets[CellIndex]) && (DispatchThreadId.x < CellsOffsets[CellIndex + ClipmapCount]))
{
CellTarget = ValidTargets[ValidIndex];
break;
}
}
if (CellTarget != -1)
{
int CellClipmap = -1;
for (int ClipmapIndex = 0; ClipmapIndex < ClipmapCount; ++ClipmapIndex, ++CellIndex)
{
if ((DispatchThreadId.x >= CellsOffsets[CellIndex]) && (DispatchThreadId.x < CellsOffsets[CellIndex + 1]))
{
CellClipmap = ClipmapIndex;
break;
}
}
if (CellClipmap != -1)
{
const uint3 CellVoxel = GetCellVoxel(DispatchThreadId.x, CellIndex);
if (all(CellVoxel.xyz < int3(ClipmapResolution, ClipmapResolution, ClipmapResolution)))
{
const float ClipmapFade = GetClipmapFade(CellClipmap,CellVoxel);
const float ClipmapExtent = ClipmapDistance * pow(ClipmapExponent, CellClipmap + 1 - ClipmapCount);
const float3 SamplePosition = GetSamplePosition(ClipmapExtent, CellVoxel);
const int BufferOffset = GetBufferOffset(CellTarget, CellClipmap, CellVoxel);
int LocalIndex = 0;
SampleFieldDatas(SamplePosition, LocalIndex, CellTarget,
ClipmapExtent* 2 * 256 * 4 / ClipmapResolution, ClipmapDistance * 8 / ClipmapResolution);
const int AttributeOffset = ClipmapResolution * ClipmapResolution * ClipmapResolution * ClipmapCount;
if (LocalIndex == 3)
{
FieldClipmap[BufferOffset] = SharedDatas[GFieldGroupThreadId][0] * ClipmapFade;
FieldClipmap[BufferOffset + 1 * AttributeOffset] = SharedDatas[GFieldGroupThreadId][1] * ClipmapFade;
FieldClipmap[BufferOffset + 2 * AttributeOffset] = SharedDatas[GFieldGroupThreadId][2] * ClipmapFade;
}
else if (LocalIndex == 1)
{
FieldClipmap[BufferOffset] = SharedDatas[GFieldGroupThreadId][0] * ClipmapFade;
}
}
}
}
}
}