281 lines
9.0 KiB
HLSL
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;
|
|
} |