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

209 lines
7.5 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Common.ush"
#include "SceneData.ush"
//
// Functions to get instanced stereo properties from a VF. They have to be macros as hlslcc does not support member functions (as of May 2022 it is still used for a couple platforms),
// whereas defining them as overloaded functions (taking VF as parameter) doesn't work as some VFs can be identical for typeless HLSL overloading rules.
//
#if INSTANCED_STEREO
#define GetInstanceIdFromVF(VFInput) (VFInput.InstanceId)
#define GetEyeIndexFromVF(VFInput) (IsInstancedStereo() ? (GetInstanceIdFromVF(VFInput) & 1) : 0)
#elif MOBILE_MULTI_VIEW
#define GetInstanceIdFromVF(VFInput) (0)
#define GetEyeIndexFromVF(VFInput) (VFInput.ViewId)
#else
#define GetInstanceIdFromVF(VFInput) (0)
#define GetEyeIndexFromVF(VFInput) (0)
#endif
#if MOBILE_MULTI_VIEW && !INSTANCED_STEREO
#define VF_MOBILE_MULTI_VIEW_DECLARE_INPUT_BLOCK() \
uint ViewId : SV_ViewID;
#else
#define VF_MOBILE_MULTI_VIEW_DECLARE_INPUT_BLOCK()
#endif // MOBILE_MULTI_VIEW && !INSTANCED_STEREO
//
// Required VF inputs to support dynamic instancing
//
#if VF_USE_PRIMITIVE_SCENE_DATA
#if SHADER_USES_PRIMITIVE_UBO
#define VF_GPUSCENE_DECLARE_INPUT_BLOCK(Attr0) \
uint DrawInstanceId : SV_InstanceID;
#define VF_GPUSCENE_GET_INTERMEDIATES(VFInput) \
GetSceneDataIntermediates(0u, VFInput.DrawInstanceId)
#else
#define VF_GPUSCENE_DECLARE_INPUT_BLOCK(Attr0) \
uint InstanceIdOffset : ATTRIBUTE##Attr0; \
uint DrawInstanceId : SV_InstanceID;
#define VF_GPUSCENE_GET_INTERMEDIATES(VFInput) \
GetSceneDataIntermediates(VFInput.InstanceIdOffset, VFInput.DrawInstanceId)
#endif //SHADER_USES_PRIMITIVE_UBO
#define VF_GPUSCENE_GET_LIGHTMAP_UV_SCALE_BIAS(VFInput, LightmapDataIndex) \
GetLightmapData(LightmapDataIndex, VFInput.DrawInstanceId).LightMapCoordinateScaleBias
#define VF_GPUSCENE_GET_SHADOWMAP_UV_SCALE_BIAS(VFInput, LightmapDataIndex) \
GetLightmapData(LightmapDataIndex, VFInput.DrawInstanceId).ShadowMapCoordinateScaleBias
#define VF_GPUSCENE_SET_INPUT_FOR_RT(_VFInputOut_, _InstanceId_, _DrawInstanceId_) \
_VFInputOut_.InstanceIdOffset = _InstanceId_ - _DrawInstanceId_; \
_VFInputOut_.DrawInstanceId = _DrawInstanceId_;
// GPUCULL_TODO: Makes use of DynamicDraw workaround, should instead refactor VF interfaces and provide the instance ID data directly.
#define VF_GPUSCENE_SET_INPUT_FOR_HAIR(_VFInputOut_, _PrimitiveId_, _DrawInstanceId_) \
_VFInputOut_.InstanceIdOffset = (_PrimitiveId_) | VF_TREAT_INSTANCE_ID_OFFSET_AS_PRIMITIVE_ID_FLAG; \
_VFInputOut_.DrawInstanceId = _DrawInstanceId_;
#define VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK()
#undef GetInstanceIdFromVF
#define GetInstanceIdFromVF(VFInput) (VFInput.DrawInstanceId)
#else
#define VF_GPUSCENE_DECLARE_INPUT_BLOCK(Attr0)
#define VF_GPUSCENE_GET_INTERMEDIATES(VFInput) GetSceneDataIntermediates()
#define VF_GPUSCENE_GET_LIGHTMAP_UV_SCALE_BIAS(VFInput, LightmapDataIndex) PrecomputedLightingBuffer.LightMapCoordinateScaleBias
#define VF_GPUSCENE_GET_SHADOWMAP_UV_SCALE_BIAS(VFInput, LightmapDataIndex) PrecomputedLightingBuffer.ShadowMapCoordinateScaleBias
#define VF_GPUSCENE_SET_INPUT_FOR_RT(_VFInputOut_, _InstanceId_, _DrawInstanceId_)
#define VF_GPUSCENE_SET_INPUT_FOR_HAIR(_VFInputOut_, _PrimitiveId_, _DrawInstanceId_)
#if INSTANCED_STEREO
#define VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK() \
uint InstanceId : SV_InstanceID;
#else
#define VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK()
#endif
#endif
// In case other paths in the above #if miss the declaration, catch this early
#if !defined(VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK)
#error VF_INSTANCED_STEREO_DECLARE_INPUT_BLOCK() should be defined for a vertex factory
#endif
#if !defined(GetInstanceIdFromVF)
#error GetInstanceIdFromVF() should be defined.
#endif
#if !defined(GetEyeIndexFromVF)
#error GetEyeIndexFromVF() should be defined.
#endif
#if INSTANCED_STEREO
#define StereoSetupVF(VFInput, Output) StereoSetupVS((IsInstancedStereo() ? (GetInstanceIdFromVF(VFInput) & 1) : 0), Output);
#elif MOBILE_MULTI_VIEW
#define StereoSetupVF(VFInput, Output) StereoSetupVS(VFInput.ViewId, Output);
#else
#define StereoSetupVF(VFInput, Output) StereoSetupVS(0, Output); // This will resolve the view regardless of the EyeIndex
#endif
FDFVector3 TransformLocalToWorld(float3 LocalPosition, FDFMatrix LocalToWorld)
{
return DFMultiply(LocalPosition, LocalToWorld);
}
FDFVector3 TransformLocalToWorld(float3 LocalPosition)
{
return TransformLocalToWorld(LocalPosition, GetPrimitiveDataFromUniformBuffer().LocalToWorld);
}
float4 TransformLocalToTranslatedWorld(float3 LocalPosition, FDFMatrix LocalToWorld)
{
return DFTransformLocalToTranslatedWorld(LocalPosition, LocalToWorld, ResolvedView.PreViewTranslation);
}
float4 TransformLocalToTranslatedWorld(float3 LocalPosition, float4x4 LocalToWorld)
{
return TransformLocalToTranslatedWorld(LocalPosition, DFPromote(LocalToWorld));
}
float4 TransformPreviousLocalPositionToTranslatedWorld(float3 PrevLocalPosition, FDFMatrix PrevLocalToWorld)
{
return DFTransformLocalToTranslatedWorld(PrevLocalPosition, PrevLocalToWorld, ResolvedView.PrevPreViewTranslation);
}
float4 TransformPreviousLocalPositionToTranslatedWorld(float3 PrevLocalPosition, float4x4 PrevLocalToWorld)
{
return TransformPreviousLocalPositionToTranslatedWorld(PrevLocalPosition, DFPromote(PrevLocalToWorld));
}
float3 RotateLocalToWorld(float3 LocalDirection, float3x3 LocalToWorld, float3 InvScale)
{
return
InvScale.x * LocalToWorld[0] * LocalDirection.xxx +
InvScale.y * LocalToWorld[1] * LocalDirection.yyy +
InvScale.z * LocalToWorld[2] * LocalDirection.zzz;
}
float3 RotateLocalToWorld(float3 LocalDirection, float4x4 LocalToWorld, float3 InvScale)
{
return RotateLocalToWorld(LocalDirection, (float3x3)LocalToWorld, InvScale);
}
float3 RotateLocalToWorld(float3 LocalDirection, FDFMatrix LocalToWorld, float3 InvScale)
{
return RotateLocalToWorld(LocalDirection, DFToFloat3x3(LocalToWorld), InvScale);
}
#if !VF_USE_PRIMITIVE_SCENE_DATA
float4 TransformLocalToTranslatedWorld(float3 LocalPosition)
{
return TransformLocalToTranslatedWorld(LocalPosition, GetPrimitiveDataFromUniformBuffer().LocalToWorld);
}
float3 RotateLocalToWorld(float3 LocalDirection)
{
FPrimitiveSceneData PrimitiveData = GetPrimitiveDataFromUniformBuffer();
return RotateLocalToWorld(LocalDirection, PrimitiveData.LocalToWorld, PrimitiveData.InvNonUniformScale);
}
float3 RotateWorldToLocal(float3 WorldDirection)
{
FPrimitiveSceneData PrimitiveData = GetPrimitiveDataFromUniformBuffer();
const float3 InvScale = PrimitiveData.InvNonUniformScale;
const float3x3 LocalToWorld = DFToFloat3x3(PrimitiveData.LocalToWorld);
float3x3 InvRot = {
InvScale.x * LocalToWorld[0],
InvScale.y * LocalToWorld[1],
InvScale.z * LocalToWorld[2]
};
InvRot = transpose(InvRot);
return mul(WorldDirection, InvRot);
}
#endif // !VF_USE_PRIMITIVE_SCENE_DATA
// Octahedron Normal Vectors
// [Cigolle 2014, "A Survey of Efficient Representations for Independent Unit Vectors"]
// Mean Max
// oct 8:8 0.33709 0.94424
// snorm 8:8:8 0.17015 0.38588
// oct 10:10 0.08380 0.23467
// snorm 10:10:10 0.04228 0.09598
// oct 12:12 0.02091 0.05874
float2 UnitToOct( float3 N )
{
N.xy /= dot( 1, abs(N) );
if( N.z <= 0 )
{
N.xy = ( 1 - abs(N.yx) ) * select( N.xy >= 0, float2(1,1), float2(-1,-1) );
}
return N.xy;
}
float3 OctToUnit( float2 Oct )
{
float3 N = float3( Oct, 1 - dot( 1, abs(Oct) ) );
if( N.z < 0 )
{
N.xy = ( 1 - abs(N.yx) ) * select( N.xy >= 0, float2(1,1), float2(-1,-1) );
}
return normalize(N);
}