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

281 lines
9.0 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#ifndef PLATFORM_USES_PRIMITIVE_UBO
#define PLATFORM_USES_PRIMITIVE_UBO 0
#endif
#ifndef PRIMITIVE_HAS_TILEOFFSET_DATA
#error "Missing PRIMITIVE_HAS_TILEOFFSET_DATA"
#endif
float4 LoadPrimitiveDataElementUBO(uint DrawInstanceId, uint DataIdx)
{
#if PLATFORM_USES_PRIMITIVE_UBO
uint DataOffset = DrawInstanceId * BATCHED_PRIMITIVE_DATA_STRIDE_FLOAT4 + DataIdx;
return BatchedPrimitive.Data[DataOffset];
#else
return (float4)0;
#endif
}
FPrimitiveSceneData LoadPrimitiveDataUBO(uint DrawInstanceId)
{
FPrimitiveSceneData PrimitiveData = (FPrimitiveSceneData)0;
uint DataIdx = 0;
#if ALLOW_STATIC_LIGHTING
// 2 float4 reservered for pre-computed lighting data
float4 Data = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+2);
PrimitiveData.LightmapDataIndex = asuint(Data.x);
DataIdx += 3u;
#endif
// PositionHigh, Flags
{
float4 Data = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx + 0);
PrimitiveData.PositionHigh = Data.xyz;
PrimitiveData.Flags = asuint(Data.w);
DataIdx += 1u;
}
// LocalToWorld
{
float4x4 LocalToRelativeWorld = transpose(float4x4(
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0),
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+1),
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+2),
float4(0, 0, 0, 1)
));
PrimitiveData.LocalToWorld = MakeDFMatrix4x3(PrimitiveData.PositionHigh, LocalToRelativeWorld);
DataIdx += 3u;
}
// InvNonUniformScale, TODO .w
{
float4 Data = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0);
PrimitiveData.InvNonUniformScale = Data.xyz;
DataIdx += 1u;
// Computing it from InvScale should be fine?
PrimitiveData.NonUniformScale.xyz = rcp(PrimitiveData.InvNonUniformScale);
PrimitiveData.NonUniformScale.w = max3(PrimitiveData.NonUniformScale.x, PrimitiveData.NonUniformScale.y, PrimitiveData.NonUniformScale.z);
}
// ObjectWorldPosition, Radius
{
float4 Data = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0);
float4 Data2 = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+1);
#if PRIMITIVE_HAS_TILEOFFSET_DATA
PrimitiveData.ObjectWorldPositionTO = MakeLWCVector3(Data.xyz, Data2.xyz);
PrimitiveData.ObjectWorldPosition = DFFromTileOffset(PrimitiveData.ObjectWorldPositionTO);
#else
PrimitiveData.ObjectWorldPosition = MakeDFVector3(Data.xyz, Data2.xyz);
#endif
PrimitiveData.ObjectRadius = Data.w;
DataIdx += 2u;
}
// ActorWorldPosition, TODO .w
{
float4 Data = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0);
float4 Data2 = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+1);
#if PRIMITIVE_HAS_TILEOFFSET_DATA
PrimitiveData.ActorWorldPositionTO = MakeLWCVector3(Data.xyz, Data2.xyz);
PrimitiveData.ActorWorldPosition = DFFromTileOffset(PrimitiveData.ActorWorldPositionTO);
#else
PrimitiveData.ActorWorldPosition = MakeDFVector3(Data.xyz, Data2.xyz);
#endif
DataIdx += 2u;
}
// ObjectOrientation, ObjectBoundsX
{
float4 Data = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0);
PrimitiveData.ObjectOrientation = Data.xyz;
PrimitiveData.ObjectBoundsX = Data.w;
DataIdx += 1u;
}
// LocalObjectBoundsMin, ObjectBoundsY
{
float4 Data = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0);
PrimitiveData.LocalObjectBoundsMin = Data.xyz;
PrimitiveData.ObjectBoundsY = Data.w;
DataIdx += 1u;
}
// LocalObjectBoundsMax, ObjectBoundsZ
{
float4 Data = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0);
PrimitiveData.LocalObjectBoundsMax = Data.xyz;
PrimitiveData.ObjectBoundsZ = Data.w;
DataIdx += 1u;
}
// InstanceLocalBounds
{
PrimitiveData.InstanceLocalBoundsCenter = (PrimitiveData.LocalObjectBoundsMin + PrimitiveData.LocalObjectBoundsMax) * 0.5f;
PrimitiveData.InstanceLocalBoundsExtent = PrimitiveData.LocalObjectBoundsMax - PrimitiveData.InstanceLocalBoundsCenter;
}
// WorldToLocal, TODO compute from LocalToWorld?
{
float4x4 RelativeWorldToLocal = transpose(float4x4(
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0),
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+1),
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+2),
float4(0, 0, 0, 1)
));
PrimitiveData.WorldToLocal = MakeDFInverseMatrix(PrimitiveData.PositionHigh, RelativeWorldToLocal);
DataIdx += 3u;
}
// PreviousLocalToWorld, TODO make optional
{
float4x4 PreviousLocalToRelativeWorld = transpose(float4x4(
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0),
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+1),
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+2),
float4(0, 0, 0, 1)
));
PrimitiveData.PreviousLocalToWorld = MakeDFMatrix4x3(PrimitiveData.PositionHigh, PreviousLocalToRelativeWorld);
DataIdx += 3u;
}
// PreviousWorldToLocal, TODO make optional
{
float4x4 PreviousRelativeWorldToLocal = transpose(float4x4(
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+0),
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+1),
LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+2),
float4(0, 0, 0, 1)
));
PrimitiveData.PreviousWorldToLocal = MakeDFInverseMatrix(PrimitiveData.PositionHigh, PreviousRelativeWorldToLocal);
DataIdx += 3u;
}
// Should not be used with regular primitives
PrimitiveData.WorldToPreviousWorld = float4x4(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
// PreSkinnedLocalBounds, TODO.w
// TODO: this is needed only for skinned meshes
{
PrimitiveData.PreSkinnedLocalBoundsMin = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx + 0).xyz;
PrimitiveData.PreSkinnedLocalBoundsMax = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx + 1).xyz;
DataIdx += 2u;
}
// CustomData, TODO make optional
{
uint NumCustomData = min(NUM_CUSTOM_PRIMITIVE_DATA, BATCHED_PRIMITIVE_DATA_STRIDE_FLOAT4 - DataIdx); //23u
UNROLL
for (uint i = 0; i < NumCustomData; ++i)
{
PrimitiveData.CustomPrimitiveData[i] = LoadPrimitiveDataElementUBO(DrawInstanceId, DataIdx+i);
}
DataIdx += NumCustomData;
}
return PrimitiveData;
}
float4 LoadInstanceDataElementUBO(uint DrawInstanceId, uint DataIdx)
{
#if PLATFORM_USES_PRIMITIVE_UBO
uint DataOffset = DrawInstanceId * BATCHED_INSTANCE_DATA_STRIDE_FLOAT4 + DataIdx;
return BatchedPrimitive.Data[DataOffset];
#else
return (float4)0;
#endif
}
FInstanceSceneData LoadInstanceDataUBO(uint DrawInstanceId)
{
FInstanceSceneData InstanceData = (FInstanceSceneData)0;
uint DataIdx = 0;
// TilePosition, Flags
float3 PositionHigh = 0;
{
float4 Data = LoadInstanceDataElementUBO(DrawInstanceId, DataIdx + 0);
PositionHigh = Data.xyz;
InstanceData.Flags = asuint(Data.w);
DataIdx += 1u;
}
// LocalToWorld
{
float4x4 LocalToRelativeWorld = transpose(float4x4(
LoadInstanceDataElementUBO(DrawInstanceId, DataIdx+0),
LoadInstanceDataElementUBO(DrawInstanceId, DataIdx+1),
LoadInstanceDataElementUBO(DrawInstanceId, DataIdx+2),
float4(0, 0, 0, 1)
));
InstanceData.LocalToWorld = MakeDFMatrix4x3(PositionHigh, LocalToRelativeWorld);
DataIdx += 3u;
}
// InvNonUniformScale, RandomID
{
float4 Data = LoadInstanceDataElementUBO(DrawInstanceId, DataIdx+0);
InstanceData.InvNonUniformScale = Data.xyz;
InstanceData.RandomID = Data.w;
// Computing it from InvScale should be fine?
InstanceData.NonUniformScale.xyz = rcp(InstanceData.InvNonUniformScale);
InstanceData.NonUniformScale.w = max3(InstanceData.NonUniformScale.x, InstanceData.NonUniformScale.y, InstanceData.NonUniformScale.z);
DataIdx += 1u;
}
// PreviousLocalToWorld
{
float4x4 PreviousLocalToRelativeWorld = transpose(float4x4(
LoadInstanceDataElementUBO(DrawInstanceId, DataIdx+0),
LoadInstanceDataElementUBO(DrawInstanceId, DataIdx+1),
LoadInstanceDataElementUBO(DrawInstanceId, DataIdx+2),
float4(0, 0, 0, 1)
));
InstanceData.PrevLocalToWorld = MakeDFMatrix4x3(PositionHigh, PreviousLocalToRelativeWorld);
DataIdx += 3u;
}
#if ALLOW_STATIC_LIGHTING
const bool bHasLightShadowUVBias = (InstanceData.Flags & INSTANCE_SCENE_DATA_FLAG_HAS_LIGHTSHADOW_UV_BIAS) != 0u;
if (bHasLightShadowUVBias)
{
InstanceData.LightMapAndShadowMapUVBias = LoadInstanceDataElementUBO(DrawInstanceId, DataIdx+0);
}
DataIdx += 1u;
#endif
// CustomDataCount, TODO: yzw
{
float4 Data = LoadInstanceDataElementUBO(DrawInstanceId, DataIdx+0);
#if ENABLE_PER_INSTANCE_CUSTOM_DATA
InstanceData.CustomDataCount = asuint(Data.x);
#endif
DataIdx += 1u;
}
return InstanceData;
}
float LoadInstanceCustomDataElementUBO(uint DrawInstanceId, uint CustomDataIdx, float DefaultValue)
{
#if USE_INSTANCE_CULLING
uint CustomDataFloat4Offset = 8u; // where custom data starts in an Instance UBO
#if ALLOW_STATIC_LIGHTING
CustomDataFloat4Offset += 1u; // one float4 reserved for pre-computed lighting
#endif
const uint Float4Index = (CustomDataIdx >> 2u);
const uint CustomDataCount = asuint(LoadInstanceDataElementUBO(DrawInstanceId, CustomDataFloat4Offset).x);
CustomDataFloat4Offset += 1u;
if (Float4Index < CustomDataCount)
{
const float4 Float4Packed = LoadInstanceDataElementUBO(DrawInstanceId, Float4Index + CustomDataFloat4Offset);
return Float4Packed[CustomDataIdx & 0x3u];
}
#endif
return DefaultValue;
}