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

227 lines
7.8 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
void WriteDataElementUBO(RWStructuredBuffer<float4> Output, uint Offset, uint DataIdx, float4 Data)
{
#if PLATFORM_USES_PRIMITIVE_UBO
uint DataOffset = Offset + DataIdx;
Output[DataOffset] = Data;
#endif
}
//
// Note: layout must match FBatchedPrimitiveShaderData in PrimitiveUniformShaderParameters.cpp
//
void WritePrimitiveDataUBO(RWStructuredBuffer<float4> Output, uint Offset, FPrimitiveSceneData PrimitiveData, uint MeshLODIndex)
{
uint DataIdx = 0;
#if ALLOW_STATIC_LIGHTING
// Pre-computed lighting data
{
float4 LightMapUVScaleBias = float4(1, 1, 0, 0);
float4 ShadowMapUVScaleBias = float4(1, 1, 0, 0);
uint LightmapDataIndex = PrimitiveData.LightmapDataIndex + MeshLODIndex;
if (LightmapDataIndex < GetSceneData().NumLightmapDataItems)
{
FLightmapSceneData LightmapData = GetLightmapData(LightmapDataIndex);
LightMapUVScaleBias = LightmapData.LightMapCoordinateScaleBias;
ShadowMapUVScaleBias = LightmapData.ShadowMapCoordinateScaleBias;
}
WriteDataElementUBO(Output, Offset, DataIdx + 0, LightMapUVScaleBias);
WriteDataElementUBO(Output, Offset, DataIdx + 1, ShadowMapUVScaleBias);
WriteDataElementUBO(Output, Offset, DataIdx + 2, float4(asfloat(PrimitiveData.LightmapDataIndex), 0.f, 0.f, 0.f));
DataIdx += 3u;
}
#endif
// PositionHigh, Flags
{
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(PrimitiveData.LocalToWorld.PostTranslation, asfloat(PrimitiveData.Flags)));
DataIdx += 1u;
}
// LocalToWorld
{
float4x4 LocalToWorld = transpose(PrimitiveData.LocalToWorld.M);
WriteDataElementUBO(Output, Offset, DataIdx + 0, LocalToWorld[0]);
WriteDataElementUBO(Output, Offset, DataIdx + 1, LocalToWorld[1]);
WriteDataElementUBO(Output, Offset, DataIdx + 2, LocalToWorld[2]);
DataIdx += 3u;
}
// InvNonUniformScale, TODO .w
{
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(PrimitiveData.InvNonUniformScale, 0.0));
DataIdx += 1u;
}
// ObjectWorldPosition, Radius
{
#if PRIMITIVE_HAS_TILEOFFSET_DATA
float3 Data = PrimitiveData.ObjectWorldPositionTO.Tile;
float3 Data2 = PrimitiveData.ObjectWorldPositionTO.Offset;
#else
float3 Data = PrimitiveData.ObjectWorldPosition.High;
float3 Data2 = PrimitiveData.ObjectWorldPosition.Low;
#endif
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(Data, PrimitiveData.ObjectRadius));
WriteDataElementUBO(Output, Offset, DataIdx + 1, float4(Data2, 0));
DataIdx += 2u;
}
// ActorWorldPosition, TODO .w
{
#if PRIMITIVE_HAS_TILEOFFSET_DATA
float3 Data = PrimitiveData.ActorWorldPositionTO.Tile;
float3 Data2 = PrimitiveData.ActorWorldPositionTO.Offset;
#else
float3 Data = PrimitiveData.ActorWorldPosition.High;
float3 Data2 = PrimitiveData.ActorWorldPosition.Low;
#endif
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(Data, 0.0));
WriteDataElementUBO(Output, Offset, DataIdx + 1, float4(Data2, 0.0));
DataIdx += 2u;
}
// ObjectOrientation, ObjectBoundsX
{
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(PrimitiveData.ObjectOrientation, PrimitiveData.ObjectBoundsX));
DataIdx += 1u;
}
// LocalObjectBoundsMin, ObjectBoundsY
{
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(PrimitiveData.LocalObjectBoundsMin, PrimitiveData.ObjectBoundsY));
DataIdx += 1u;
}
// LocalObjectBoundsMax, ObjectBoundsZ
{
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(PrimitiveData.LocalObjectBoundsMax, PrimitiveData.ObjectBoundsZ));
DataIdx += 1u;
}
// WorldToLocal, TODO compute from LocalToWorld?
{
float4x4 RelativeWorldToLocal = transpose(PrimitiveData.WorldToLocal.M);
WriteDataElementUBO(Output, Offset, DataIdx + 0, RelativeWorldToLocal[0]);
WriteDataElementUBO(Output, Offset, DataIdx + 1, RelativeWorldToLocal[1]);
WriteDataElementUBO(Output, Offset, DataIdx + 2, RelativeWorldToLocal[2]);
DataIdx += 3u;
}
// PreviousLocalToWorld, TODO make optional
{
float4x4 PreviousLocalToWorld = transpose(PrimitiveData.PreviousLocalToWorld.M);
WriteDataElementUBO(Output, Offset, DataIdx + 0, PreviousLocalToWorld[0]);
WriteDataElementUBO(Output, Offset, DataIdx + 1, PreviousLocalToWorld[1]);
WriteDataElementUBO(Output, Offset, DataIdx + 2, PreviousLocalToWorld[2]);
DataIdx += 3u;
}
// PreviousWorldToLocal, TODO make optional
{
float4x4 PreviousRelativeWorldToLocal = transpose(PrimitiveData.PreviousWorldToLocal.M);
WriteDataElementUBO(Output, Offset, DataIdx + 0, PreviousRelativeWorldToLocal[0]);
WriteDataElementUBO(Output, Offset, DataIdx + 1, PreviousRelativeWorldToLocal[1]);
WriteDataElementUBO(Output, Offset, DataIdx + 2, PreviousRelativeWorldToLocal[2]);
DataIdx += 3u;
}
// PreSkinnedLocalBounds, TODO.w
// TODO: this is needed only for skinned meshes
{
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(PrimitiveData.PreSkinnedLocalBoundsMin, 0.f));
WriteDataElementUBO(Output, Offset, DataIdx + 1, float4(PrimitiveData.PreSkinnedLocalBoundsMax, 0.f));
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)
{
WriteDataElementUBO(Output, Offset, DataIdx + i, PrimitiveData.CustomPrimitiveData[i]);
}
DataIdx += NumCustomData;
}
}
void WriteInstanceDataUBO(RWStructuredBuffer<float4> Output, uint Offset, uint InstanceId, FInstanceSceneData InstanceData)
{
uint DataIdx = 0;
// PositionHigh, Flags
{
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(InstanceData.LocalToWorld.PostTranslation, asfloat(InstanceData.Flags)));
DataIdx += 1u;
}
// LocalToWorld
{
float4x4 LocalToWorld = transpose(InstanceData.LocalToWorld.M);
WriteDataElementUBO(Output, Offset, DataIdx + 0, LocalToWorld[0]);
WriteDataElementUBO(Output, Offset, DataIdx + 1, LocalToWorld[1]);
WriteDataElementUBO(Output, Offset, DataIdx + 2, LocalToWorld[2]);
DataIdx += 3u;
}
// InvNonUniformScale, RandomID
{
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(InstanceData.InvNonUniformScale, InstanceData.RandomID));
DataIdx += 1u;
}
// PreviousLocalToWorld
{
float4x4 PrevLocalToWorld = transpose(InstanceData.PrevLocalToWorld.M);
WriteDataElementUBO(Output, Offset, DataIdx + 0, PrevLocalToWorld[0]);
WriteDataElementUBO(Output, Offset, DataIdx + 1, PrevLocalToWorld[1]);
WriteDataElementUBO(Output, Offset, DataIdx + 2, PrevLocalToWorld[2]);
DataIdx += 3u;
}
uint CustomDataCount = 0;
uint InstanceRelativeId = 0;
LoadInstanceRelativeIdAndCustomDataCount(InstanceId, InstanceRelativeId, CustomDataCount);
FInstancePayloadDataOffsets Offsets = GetInstancePayloadDataOffsets(InstanceData.PrimitiveId, InstanceData.Flags, InstanceRelativeId);
#if ALLOW_STATIC_LIGHTING
{
if (Offsets.LightShadowUVBias != INVALID_INSTANCE_PAYLOAD_OFFSET)
{
float4 LightMapAndShadowMapUVBias = LoadInstancePayloadDataElement(Offsets.LightShadowUVBias);
WriteDataElementUBO(Output, Offset, DataIdx + 0, LightMapAndShadowMapUVBias);
}
DataIdx += 1u;
}
#endif
// CustomDataCount, TODO: yzw
{
CustomDataCount = min(CustomDataCount, (BATCHED_INSTANCE_DATA_STRIDE_FLOAT4 - DataIdx - 1u) * 4u);
WriteDataElementUBO(Output, Offset, DataIdx + 0, float4(asfloat(CustomDataCount), 0.f, 0.f, 0.f));
DataIdx += 1u;
}
// TODO: make it optional, doubles instance data size
{
// limited space for instance custom data
InstanceData.CustomDataCount = CustomDataCount;
InstanceData.CustomDataOffset = Offsets.CustomData;
uint CustomDataElements = (CustomDataCount + 3u) >> 2u;
UNROLL
for (uint i = 0; i < CustomDataElements; ++i)
{
float4 CustomData = LoadInstanceCustomDataElement(InstanceData, i);
WriteDataElementUBO(Output, Offset, DataIdx + i, CustomData);
}
}
}