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

671 lines
25 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "DoubleFloat.ush"
struct FLWCScalar
{
float Tile;
float Offset;
#if !COMPILER_SUPPORTS_HLSL2021
int Dummy; // avoid problem with HLSL overloading/implicit cast (should be DCE'd)
#endif
};
struct FLWCVector2
{
float2 Tile;
float2 Offset;
#if !COMPILER_SUPPORTS_HLSL2021
int Dummy; // avoid problem with HLSL overloading/implicit cast (should be DCE'd)
#endif
};
struct FLWCVector3
{
float3 Tile;
float3 Offset;
#if !COMPILER_SUPPORTS_HLSL2021
int Dummy; // avoid problem with HLSL overloading/implicit cast (should be DCE'd)
#endif
};
struct FLWCVector4
{
float4 Tile;
float4 Offset;
#if !COMPILER_SUPPORTS_HLSL2021
int Dummy; // avoid problem with HLSL overloading/implicit cast (should be DCE'd)
#endif
};
struct FLWCScalarDeriv
{
FLWCScalar Value;
float Ddx;
float Ddy;
};
struct FLWCVector2Deriv
{
FLWCVector2 Value;
float2 Ddx;
float2 Ddy;
};
struct FLWCVector3Deriv
{
FLWCVector3 Value;
float3 Ddx;
float3 Ddy;
};
struct FLWCVector4Deriv
{
FLWCVector4 Value;
float4 Ddx;
float4 Ddy;
};
// Transforms *to* absolute world space
struct FLWCMatrix
{
float4x4 M;
float3 Tile; // Added to result, *after* multiplying 'M'
#if !COMPILER_SUPPORTS_HLSL2021
int2 Dummy; // avoid problem with HLSL overloading/implicit cast (should be DCE'd)
#endif
};
// Transforms *from* absolute world space
struct FLWCInverseMatrix
{
float4x4 M;
float3 Tile; // Added to input position *before* multiplying 'M'
#if !COMPILER_SUPPORTS_HLSL2021
int3 Dummy; // avoid problem with HLSL overloading/implicit cast (should be DCE'd)
#endif
};
#define LWCSetTile(V, InTile) (V).Tile = (InTile)
#define LWCGetTile(V) ((V).Tile)
float LWCGetTileOffset(FLWCScalar V) { return LWCGetTile(V) * UE_LWC_RENDER_TILE_SIZE; }
float2 LWCGetTileOffset(FLWCVector2 V) { return LWCGetTile(V) * UE_LWC_RENDER_TILE_SIZE; }
float3 LWCGetTileOffset(FLWCVector3 V) { return LWCGetTile(V) * UE_LWC_RENDER_TILE_SIZE; }
float4 LWCGetTileOffset(FLWCVector4 V) { return LWCGetTile(V) * UE_LWC_RENDER_TILE_SIZE; }
float3 LWCGetTileOffset(FLWCMatrix V) { return LWCGetTile(V) * UE_LWC_RENDER_TILE_SIZE; }
float3 LWCGetTileOffset(FLWCInverseMatrix V) { return LWCGetTile(V) * UE_LWC_RENDER_TILE_SIZE; }
FLWCScalar MakeLWCScalar(float Tile, float Offset)
{
FLWCScalar Result;
LWCSetTile(Result, Tile);
Result.Offset = Offset;
#if !COMPILER_SUPPORTS_HLSL2021
Result.Dummy = 0;
#endif
return Result;
}
FLWCVector2 MakeLWCVector2(float2 Tile, float2 Offset)
{
FLWCVector2 Result;
LWCSetTile(Result, Tile);
Result.Offset = Offset;
#if !COMPILER_SUPPORTS_HLSL2021
Result.Dummy = 0;
#endif
return Result;
}
FLWCVector3 MakeLWCVector3(float3 Tile, float3 Offset)
{
FLWCVector3 Result;
LWCSetTile(Result, Tile);
Result.Offset = Offset;
#if !COMPILER_SUPPORTS_HLSL2021
Result.Dummy = 0;
#endif
return Result;
}
FLWCVector4 MakeLWCVector4(float4 Tile, float4 Offset)
{
FLWCVector4 Result;
LWCSetTile(Result, Tile);
Result.Offset = Offset;
#if !COMPILER_SUPPORTS_HLSL2021
Result.Dummy = 0;
#endif
return Result;
}
FLWCVector4 MakeLWCVector4(float3 Tile, float4 Offset)
{
return MakeLWCVector4(float4(Tile, 0), Offset);
}
FLWCVector4 MakeLWCVector4(FLWCVector3 XYZ, float W)
{
return MakeLWCVector4(LWCGetTile(XYZ), float4(XYZ.Offset, W));
}
FLWCScalar MakeLWCVector(FLWCScalar X) { return X; }
FLWCVector2 MakeLWCVector(FLWCScalar X, FLWCScalar Y) { return MakeLWCVector2(float2(LWCGetTile(X), LWCGetTile(Y)), float2(X.Offset, Y.Offset)); }
FLWCVector3 MakeLWCVector(FLWCScalar X, FLWCScalar Y, FLWCScalar Z) { return MakeLWCVector3(float3(LWCGetTile(X), LWCGetTile(Y), LWCGetTile(Z)), float3(X.Offset, Y.Offset, Z.Offset)); }
FLWCVector3 MakeLWCVector(FLWCScalar X, FLWCVector2 YZ) { return MakeLWCVector3(float3(LWCGetTile(X), LWCGetTile(YZ)), float3(X.Offset, YZ.Offset)); }
FLWCVector3 MakeLWCVector(FLWCVector2 XY, FLWCScalar Z) { return MakeLWCVector3(float3(LWCGetTile(XY), LWCGetTile(Z)), float3(XY.Offset, Z.Offset)); }
FLWCVector4 MakeLWCVector(FLWCScalar X, FLWCScalar Y, FLWCScalar Z, FLWCScalar W) { return MakeLWCVector4(float4(LWCGetTile(X), LWCGetTile(Y), LWCGetTile(Z), LWCGetTile(W)), float4(X.Offset, Y.Offset, Z.Offset, W.Offset)); }
FLWCVector4 MakeLWCVector(FLWCScalar X, FLWCScalar Y, FLWCVector2 ZW) { return MakeLWCVector4(float4(LWCGetTile(X), LWCGetTile(Y), LWCGetTile(ZW)), float4(X.Offset, Y.Offset, ZW.Offset)); }
FLWCVector4 MakeLWCVector(FLWCScalar X, FLWCVector2 YZ, FLWCScalar W) { return MakeLWCVector4(float4(LWCGetTile(X), LWCGetTile(YZ), LWCGetTile(W)), float4(X.Offset, YZ.Offset, W.Offset)); }
FLWCVector4 MakeLWCVector(FLWCVector2 XY, FLWCScalar Z, FLWCScalar W) { return MakeLWCVector4(float4(LWCGetTile(XY), LWCGetTile(Z), LWCGetTile(W)), float4(XY.Offset, Z.Offset, W.Offset)); }
FLWCVector4 MakeLWCVector(FLWCVector2 XY, FLWCVector2 ZW) { return MakeLWCVector4(float4(LWCGetTile(XY), LWCGetTile(ZW)), float4(XY.Offset, ZW.Offset)); }
FLWCVector4 MakeLWCVector(FLWCScalar X, FLWCVector3 YZW) { return MakeLWCVector4(float4(LWCGetTile(X), LWCGetTile(YZW)), float4(X.Offset, YZW.Offset)); }
FLWCVector4 MakeLWCVector(FLWCVector3 XYZ, FLWCScalar W) { return MakeLWCVector4(float4(LWCGetTile(XYZ), LWCGetTile(W)), float4(XYZ.Offset, W.Offset)); }
FLWCMatrix MakeLWCMatrix(float3 Tile, float4x4 InMatrix)
{
FLWCMatrix Result;
LWCSetTile(Result, Tile);
Result.M = InMatrix;
#if !COMPILER_SUPPORTS_HLSL2021
Result.Dummy = 0;
#endif
return Result;
}
FLWCMatrix MakeLWCMatrix4x3(float3 Tile, float4x4 InMatrix)
{
FLWCMatrix Result;
LWCSetTile(Result, Tile);
Result.M = Make4x3Matrix(InMatrix);
#if !COMPILER_SUPPORTS_HLSL2021
Result.Dummy = 0;
#endif
return Result;
}
FLWCInverseMatrix MakeLWCInverseMatrix(float3 Tile, float4x4 InMatrix)
{
FLWCInverseMatrix Result;
LWCSetTile(Result, -Tile);
Result.M = InMatrix;
#if !COMPILER_SUPPORTS_HLSL2021
Result.Dummy = 0;
#endif
return Result;
}
FLWCInverseMatrix MakeLWCInverseMatrix4x3(float3 Tile, float4x4 InMatrix)
{
FLWCInverseMatrix Result;
LWCSetTile(Result, -Tile);
Result.M = Make4x3Matrix(InMatrix);
#if !COMPILER_SUPPORTS_HLSL2021
Result.Dummy = 0;
#endif
return Result;
}
// 'C' should typically be a constant value for optimized codegen; 0, 1, 2, 3 to select X, Y, Z, or W component
// Undefined if out-of-bounds
FLWCScalar LWCGetComponent(FLWCScalar V, int C) { return V; }
FLWCScalar LWCGetComponent(FLWCVector2 V, int C) { return MakeLWCScalar(LWCGetTile(V)[C], V.Offset[C]); }
FLWCScalar LWCGetComponent(FLWCVector3 V, int C) { return MakeLWCScalar(LWCGetTile(V)[C], V.Offset[C]); }
FLWCScalar LWCGetComponent(FLWCVector4 V, int C) { return MakeLWCScalar(LWCGetTile(V)[C], V.Offset[C]); }
#define LWCGetX(V) LWCGetComponent(V, 0)
#define LWCGetY(V) LWCGetComponent(V, 1)
#define LWCGetZ(V) LWCGetComponent(V, 2)
#define LWCGetW(V) LWCGetComponent(V, 3)
FLWCScalar LWCSwizzle(FLWCScalar V, int C0) { return V; }
FLWCScalar LWCSwizzle(FLWCVector2 V, int C0) { return LWCGetComponent(V, C0); }
FLWCScalar LWCSwizzle(FLWCVector3 V, int C0) { return LWCGetComponent(V, C0); }
FLWCScalar LWCSwizzle(FLWCVector4 V, int C0) { return LWCGetComponent(V, C0); }
FLWCVector2 LWCSwizzle(FLWCScalar V, int C0, int C1) { return MakeLWCVector(V, V); }
FLWCVector2 LWCSwizzle(FLWCVector2 V, int C0, int C1) { return MakeLWCVector(LWCGetComponent(V, C0), LWCGetComponent(V, C1)); }
FLWCVector2 LWCSwizzle(FLWCVector3 V, int C0, int C1) { return MakeLWCVector(LWCGetComponent(V, C0), LWCGetComponent(V, C1)); }
FLWCVector2 LWCSwizzle(FLWCVector4 V, int C0, int C1) { return MakeLWCVector(LWCGetComponent(V, C0), LWCGetComponent(V, C1)); }
FLWCVector3 LWCSwizzle(FLWCScalar V, int C0, int C1, int C2) { return MakeLWCVector(V, V, V); }
FLWCVector3 LWCSwizzle(FLWCVector2 V, int C0, int C1, int C2) { return MakeLWCVector(LWCGetComponent(V, C0), LWCGetComponent(V, C1), LWCGetComponent(V, C2)); }
FLWCVector3 LWCSwizzle(FLWCVector3 V, int C0, int C1, int C2) { return MakeLWCVector(LWCGetComponent(V, C0), LWCGetComponent(V, C1), LWCGetComponent(V, C2)); }
FLWCVector3 LWCSwizzle(FLWCVector4 V, int C0, int C1, int C2) { return MakeLWCVector(LWCGetComponent(V, C0), LWCGetComponent(V, C1), LWCGetComponent(V, C2)); }
FLWCVector4 LWCSwizzle(FLWCScalar V, int C0, int C1, int C2, int C3) { return MakeLWCVector(V, V, V, V); }
FLWCVector4 LWCSwizzle(FLWCVector2 V, int C0, int C1, int C2, int C3) { return MakeLWCVector(LWCGetComponent(V, C0), LWCGetComponent(V, C1), LWCGetComponent(V, C2), LWCGetComponent(V, C3)); }
FLWCVector4 LWCSwizzle(FLWCVector3 V, int C0, int C1, int C2, int C3) { return MakeLWCVector(LWCGetComponent(V, C0), LWCGetComponent(V, C1), LWCGetComponent(V, C2), LWCGetComponent(V, C3)); }
FLWCVector4 LWCSwizzle(FLWCVector4 V, int C0, int C1, int C2, int C3) { return MakeLWCVector(LWCGetComponent(V, C0), LWCGetComponent(V, C1), LWCGetComponent(V, C2), LWCGetComponent(V, C3)); }
float LWCToFloat(FLWCScalar Value) { return LWCGetTileOffset(Value) + Value.Offset; }
float2 LWCToFloat(FLWCVector2 Value) { return LWCGetTileOffset(Value) + Value.Offset; }
float3 LWCToFloat(FLWCVector3 Value) { return LWCGetTileOffset(Value) + Value.Offset; }
float4 LWCToFloat(FLWCVector4 Value) { return LWCGetTileOffset(Value) + Value.Offset; }
float4x4 LWCToFloat(FLWCMatrix Value)
{
float4x4 Result = Value.M;
Result[3].xyz = LWCGetTileOffset(Value) + Result[3].xyz;
return Result;
}
float4x4 LWCToFloat(FLWCInverseMatrix Value)
{
float4x4 TileOffset = MakeTranslationMatrix(LWCGetTileOffset(Value));
return mul(TileOffset, Value.M);
}
float3x3 LWCToFloat3x3(FLWCMatrix Value)
{
return (float3x3)Value.M;
}
float3x3 LWCToFloat3x3(FLWCInverseMatrix Value)
{
return (float3x3)Value.M;
}
// Allow LWCToFloat to be called on float values (as nop)
float LWCToFloat(float Value) { return Value; }
float2 LWCToFloat(float2 Value) { return Value; }
float3 LWCToFloat(float3 Value) { return Value; }
float4 LWCToFloat(float4 Value) { return Value; }
float4x4 LWCToFloat(float4x4 Value) { return Value; }
// 'LWCPromote' will convert a float value to LWC, or leave an LWC value as-is
FLWCScalar LWCPromote(FLWCScalar Value) { return Value; }
FLWCVector2 LWCPromote(FLWCVector2 Value) { return Value; }
FLWCVector3 LWCPromote(FLWCVector3 Value) { return Value; }
FLWCVector4 LWCPromote(FLWCVector4 Value) { return Value; }
FLWCMatrix LWCPromote(FLWCMatrix Value) { return Value; }
FLWCInverseMatrix LWCPromote(FLWCInverseMatrix Value) { return Value; }
FLWCScalar LWCPromote(float Value) { return MakeLWCScalar(0, Value); }
FLWCVector2 LWCPromote(float2 Value) { return MakeLWCVector2((float2)0, Value); }
FLWCVector3 LWCPromote(float3 Value) { return MakeLWCVector3((float3)0, Value); }
FLWCVector4 LWCPromote(float4 Value) { return MakeLWCVector4((float4)0, Value); }
FLWCMatrix LWCPromote(float4x4 Value) { return MakeLWCMatrix((float3)0, Value); }
FLWCInverseMatrix LWCPromoteInverse(float4x4 Value) { return MakeLWCInverseMatrix((float3)0, Value); }
FLWCVector3 LWCMultiply(float3 Position, FLWCMatrix InMatrix)
{
// Explicit operations rather than mul() avoids z-fighting between depth/base passes
float3 Offset = (Position.xxx * InMatrix.M[0].xyz + Position.yyy * InMatrix.M[1].xyz + Position.zzz * InMatrix.M[2].xyz) + InMatrix.M[3].xyz;
return MakeLWCVector3(LWCGetTile(InMatrix), Offset);
}
FLWCVector4 LWCMultiply(float4 Position, FLWCMatrix InMatrix)
{
float4 Offset = mul(Position, InMatrix.M);
return MakeLWCVector4(LWCGetTile(InMatrix), Offset);
}
float3 LWCMultiply(FLWCVector3 Position, FLWCInverseMatrix InMatrix)
{
float3 LocalPosition = LWCToFloat(MakeLWCVector3(LWCGetTile(Position) + LWCGetTile(InMatrix), Position.Offset));
return (LocalPosition.xxx * InMatrix.M[0].xyz + LocalPosition.yyy * InMatrix.M[1].xyz + LocalPosition.zzz * InMatrix.M[2].xyz) + InMatrix.M[3].xyz;
}
float4 LWCMultiply(FLWCVector4 Position, FLWCInverseMatrix InMatrix)
{
float4 LocalPosition = LWCToFloat(MakeLWCVector4(LWCGetTile(Position) + float4(LWCGetTile(InMatrix), 0), Position.Offset));
return mul(LocalPosition, InMatrix.M);
}
float3 LWCMultiplyVector(float3 Vector, FLWCMatrix InMatrix)
{
return mul(Vector, (float3x3)InMatrix.M);
}
float3 LWCMultiplyVector(float3 Vector, FLWCInverseMatrix InMatrix)
{
return mul(Vector, (float3x3)InMatrix.M);
}
FLWCMatrix LWCMultiply(float4x4 Lhs, FLWCMatrix Rhs)
{
float4x4 ResultMatrix = mul(Lhs, Rhs.M);
return MakeLWCMatrix(LWCGetTile(Rhs), ResultMatrix);
}
FLWCInverseMatrix LWCMultiply(FLWCInverseMatrix Lhs, float4x4 Rhs)
{
float4x4 ResultMatrix = mul(Lhs.M, Rhs);
return MakeLWCInverseMatrix(-LWCGetTile(Lhs), ResultMatrix);
}
float4x4 LWCMultiply(FLWCMatrix Lhs, FLWCInverseMatrix Rhs)
{
// Lhs.M * Lhs.Tile * Rhs.Tile * Rhs.M
float4x4 Result = Lhs.M;
Result = mul(Result, MakeTranslationMatrix((LWCGetTile(Lhs) + LWCGetTile(Rhs)) * UE_LWC_RENDER_TILE_SIZE));
Result = mul(Result, Rhs.M);
return Result;
}
float4x4 LWCMultiplyTranslation(FLWCMatrix Lhs, FLWCVector3 Rhs)
{
float4x4 Result = Lhs.M;
Result[3].xyz += (LWCGetTile(Lhs) + LWCGetTile(Rhs)) * UE_LWC_RENDER_TILE_SIZE;
Result[3].xyz += Rhs.Offset;
return Result;
}
FLWCMatrix LWCMultiplyTranslation(float4x4 Lhs, FLWCVector3 Rhs)
{
FLWCMatrix Result = MakeLWCMatrix(LWCGetTile(Rhs), Lhs);
Result.M[3].xyz += Rhs.Offset;
return Result;
}
float4x4 LWCMultiplyTranslation(FLWCVector3 Lhs, FLWCInverseMatrix Rhs)
{
float3 Offset = (LWCGetTile(Lhs) + LWCGetTile(Rhs)) * UE_LWC_RENDER_TILE_SIZE + Lhs.Offset;
return mul(MakeTranslationMatrix(Offset), Rhs.M);
}
FLWCInverseMatrix LWCMultiplyTranslation(FLWCVector3 Lhs, float4x4 Rhs)
{
FLWCInverseMatrix Result = MakeLWCInverseMatrix(-LWCGetTile(Lhs), Rhs);
Result.M = mul(MakeTranslationMatrix(Lhs.Offset), Result.M);
return Result;
}
FLWCVector3 LWCGetOrigin(FLWCMatrix InMatrix)
{
return MakeLWCVector3(LWCGetTile(InMatrix), InMatrix.M[3].xyz);
}
void LWCSetOrigin(inout FLWCMatrix InOutMatrix, FLWCVector3 Origin)
{
LWCSetTile(InOutMatrix, LWCGetTile(Origin));
InOutMatrix.M[3].xyz = Origin.Offset;
}
#define FLWCType FLWCScalar
#define FFloatType float
#define FBoolType bool
#define LWCConstructor MakeLWCScalar
#include "LWCOperations.ush"
#undef FLWCType
#undef FFloatType
#undef FBoolType
#undef LWCConstructor
#define FLWCType FLWCVector2
#define FFloatType float2
#define FBoolType bool2
#define LWCConstructor MakeLWCVector2
#include "LWCOperations.ush"
#undef FLWCType
#undef FFloatType
#undef FBoolType
#undef LWCConstructor
#define FLWCType FLWCVector3
#define FFloatType float3
#define FBoolType bool3
#define LWCConstructor MakeLWCVector3
#include "LWCOperations.ush"
#undef FLWCType
#undef FFloatType
#undef FBoolType
#undef LWCConstructor
#define FLWCType FLWCVector4
#define FFloatType float4
#define FBoolType bool4
#define LWCConstructor MakeLWCVector4
#include "LWCOperations.ush"
#undef FLWCType
#undef FFloatType
#undef FBoolType
#undef LWCConstructor
// Creates a coordinate with the same value, but relative to the specified tile, while keeping precision loss as low as possible
FLWCScalar LWCMakeRelativeToTile(FLWCScalar V, float NewTile) { return MakeLWCScalar(NewTile, LWCToFloat(LWCSubtract(V, MakeLWCScalar(NewTile, (float)0.0f)))); }
FLWCVector2 LWCMakeRelativeToTile(FLWCVector2 V, float2 NewTile) { return MakeLWCVector2(NewTile, LWCToFloat(LWCSubtract(V, MakeLWCVector2(NewTile, (float2)0.0f)))); }
FLWCVector3 LWCMakeRelativeToTile(FLWCVector3 V, float3 NewTile) { return MakeLWCVector3(NewTile, LWCToFloat(LWCSubtract(V, MakeLWCVector3(NewTile, (float3)0.0f)))); }
FLWCVector4 LWCMakeRelativeToTile(FLWCVector4 V, float4 NewTile) { return MakeLWCVector4(NewTile, LWCToFloat(LWCSubtract(V, MakeLWCVector4(NewTile, (float4)0.0f)))); }
FLWCMatrix LWCMakeRelativeToTile(FLWCMatrix M, float3 NewTile)
{
LWCSetOrigin(M, LWCMakeRelativeToTile(LWCGetOrigin(M), NewTile));
return M;
}
FLWCScalar LWCVectorSum(FLWCScalar V) { return V; }
FLWCScalar LWCVectorSum(FLWCVector2 V) { return LWCAdd(LWCGetX(V), LWCGetY(V)); }
FLWCScalar LWCVectorSum(FLWCVector3 V) { return LWCAdd(LWCAdd(LWCGetX(V), LWCGetY(V)), LWCGetZ(V)); }
FLWCScalar LWCVectorSum(FLWCVector4 V) { return LWCAdd(LWCAdd(LWCAdd(LWCGetX(V), LWCGetY(V)), LWCGetZ(V)), LWCGetW(V)); }
FLWCScalar LWCDot(FLWCScalar Lhs, FLWCScalar Rhs) { return LWCMultiply(Lhs, Rhs); }
FLWCScalar LWCDot(FLWCScalar Lhs, float Rhs) { return LWCMultiply(Lhs, Rhs); }
FLWCScalar LWCDot(FLWCVector2 Lhs, FLWCVector2 Rhs) { return LWCVectorSum(LWCMultiply(Lhs, Rhs)); }
FLWCScalar LWCDot(FLWCVector2 Lhs, float2 Rhs) { return LWCVectorSum(LWCMultiply(Lhs, Rhs)); }
FLWCScalar LWCDot(FLWCVector3 Lhs, FLWCVector3 Rhs) { return LWCVectorSum(LWCMultiply(Lhs, Rhs)); }
FLWCScalar LWCDot(FLWCVector3 Lhs, float3 Rhs) { return LWCVectorSum(LWCMultiply(Lhs, Rhs)); }
FLWCScalar LWCDot(FLWCVector4 Lhs, FLWCVector4 Rhs) { return LWCVectorSum(LWCMultiply(Lhs, Rhs)); }
FLWCScalar LWCDot(FLWCVector4 Lhs, float4 Rhs) { return LWCVectorSum(LWCMultiply(Lhs, Rhs)); }
// LWCLength2Scaled returns the length2 of the vector, scaled by the LWC tile size
FLWCScalar LWCLength2Scaled(FLWCScalar V)
{
return LWCSquareScaled(V);
}
FLWCScalar LWCLength2Scaled(FLWCVector2 V)
{
FLWCScalar X2 = LWCSquareScaled(LWCGetX(V));
FLWCScalar Y2 = LWCSquareScaled(LWCGetY(V));
return LWCAdd(X2, Y2);
}
FLWCScalar LWCLength2Scaled(FLWCVector3 V)
{
FLWCScalar X2 = LWCSquareScaled(LWCGetX(V));
FLWCScalar Y2 = LWCSquareScaled(LWCGetY(V));
FLWCScalar Z2 = LWCSquareScaled(LWCGetZ(V));
return LWCAdd(LWCAdd(X2, Y2), Z2);
}
FLWCScalar LWCLength2Scaled(FLWCVector4 V)
{
FLWCScalar X2 = LWCSquareScaled(LWCGetX(V));
FLWCScalar Y2 = LWCSquareScaled(LWCGetY(V));
FLWCScalar Z2 = LWCSquareScaled(LWCGetZ(V));
FLWCScalar W2 = LWCSquareScaled(LWCGetW(V));
return LWCAdd(LWCAdd(LWCAdd(X2, Y2), Z2), W2);
}
// LWCLength2Scaled scales the result by TileSize, which means the result of LWCSqrtUnscaled needs to be scaled by TileSize as well
// Rather than apply that scale directly, just put the result into the TileCoordinate (with no offset)
FLWCScalar LWCLength(FLWCScalar V) { return MakeLWCScalar(LWCSqrtUnscaled(LWCLength2Scaled(V)), 0.0f); }
FLWCScalar LWCLength(FLWCVector2 V) { return MakeLWCScalar(LWCSqrtUnscaled(LWCLength2Scaled(V)), 0.0f); }
FLWCScalar LWCLength(FLWCVector3 V) { return MakeLWCScalar(LWCSqrtUnscaled(LWCLength2Scaled(V)), 0.0f); }
FLWCScalar LWCLength(FLWCVector4 V) { return MakeLWCScalar(LWCSqrtUnscaled(LWCLength2Scaled(V)), 0.0f); }
float LWCRcpLength(FLWCScalar V) { return LWCRsqrtScaled(LWCLength2Scaled(V), UE_LWC_RENDER_TILE_SIZE_RCP); }
float LWCRcpLength(FLWCVector2 V) { return LWCRsqrtScaled(LWCLength2Scaled(V), UE_LWC_RENDER_TILE_SIZE_RCP); }
float LWCRcpLength(FLWCVector3 V) { return LWCRsqrtScaled(LWCLength2Scaled(V), UE_LWC_RENDER_TILE_SIZE_RCP); }
float LWCRcpLength(FLWCVector4 V) { return LWCRsqrtScaled(LWCLength2Scaled(V), UE_LWC_RENDER_TILE_SIZE_RCP); }
float LWCNormalize(FLWCScalar V) { return 1.0f; } // Normalizing a scalar always results in 1
float2 LWCNormalize(FLWCVector2 V) { return LWCToFloat(LWCMultiply(V, LWCRcpLength(V))); }
float3 LWCNormalize(FLWCVector3 V) { return LWCToFloat(LWCMultiply(V, LWCRcpLength(V))); }
float4 LWCNormalize(FLWCVector4 V) { return LWCToFloat(LWCMultiply(V, LWCRcpLength(V))); }
// LWCHackToFloat is a marker for places where LWC quantities are transformed to float, without regard for range/precision
// This will work correctly for content that's not using LWC scale values
// 'LWC_HACK_TO_ZERO' is a big hammer to work around some internal compiler errors....using this will break the functionality of the shader, but can unblock testing of other shaders
#ifdef LWC_HACK_TO_ZERO
float3 LWCHackToFloat(FLWCVector3 v) { return (float3)0.0f; }
float4 LWCHackToFloat(FLWCVector4 v) { return (float4)0.0f; }
float4x4 LWCHackToFloat(FLWCMatrix v) { return (float4x4)0.0f; }
float4x4 LWCHackToFloat(FLWCInverseMatrix v) { return (float4x4)0.0f; }
#else
#define LWCHackToFloat(V) LWCToFloat(V)
#endif
#define DEFINE_DF_TO_TILEOFFSET_OPERATOR(FDFType, FLWCType, LWCConstructor, FFloatType) \
FLWCType DFToTileOffset(FDFType In) \
{ \
/* CPU side defines MakeTile as floor(Value / TILE_SIZE + 0.5) which is not quite the same as round but */ \
/* divergent cases are extremely rare and result simply in rollover from one tile edge to the edge of the next tile */ \
/* Values greater than 2^(24+floor(log2(TILE_SIZE-1))) are not converted correctly, because In.Low is assumed to be */ \
/* less than half a tile. These values by definition exceed WORLD_MAX, so this is not an issue. */ \
FFloatType Tile = round(In.High / UE_LWC_RENDER_TILE_SIZE); \
FFloatType Offset = INVARIANT_ADD(INVARIANT_FMA(Tile, -UE_LWC_RENDER_TILE_SIZE, In.High), In.Low); \
\
return LWCConstructor(Tile, Offset); \
}
#if UE_DF_NO_FAST_MATH
#define DEFINE_DF_FAST_TO_TILEOFFSET_OPERATOR(FDFType, FLWCType, LWCConstructor, FFloatType) \
FLWCType DFFastToTileOffset(FDFType In) \
{ \
return DFToTileOffset(In); \
}
#else
#define DEFINE_DF_FAST_TO_TILEOFFSET_OPERATOR(FDFType, FLWCType, LWCConstructor, FFloatType) \
FLWCType DFFastToTileOffset(FDFType In) \
{ \
/* Produces a non-normalized tile-offset coordinate. */ \
/* If we're not rounding, Tile has the full precision of In.High because UE_LWC_RENDER_TILE_SIZE is pow2 */ \
/* Therefore, we don't need to calculate the error term and can just use In.Low */ \
FFloatType Tile = In.High * (1 / UE_LWC_RENDER_TILE_SIZE); \
FFloatType Offset = In.Low; \
\
return LWCConstructor(Tile, Offset); \
}
#endif
DEFINE_DF_TO_TILEOFFSET_OPERATOR(FDFScalar, FLWCScalar, MakeLWCScalar, float)
DEFINE_DF_TO_TILEOFFSET_OPERATOR(FDFVector2, FLWCVector2, MakeLWCVector2, float2)
DEFINE_DF_TO_TILEOFFSET_OPERATOR(FDFVector3, FLWCVector3, MakeLWCVector3, float3)
DEFINE_DF_TO_TILEOFFSET_OPERATOR(FDFVector4, FLWCVector4, MakeLWCVector4, float4)
DEFINE_DF_FAST_TO_TILEOFFSET_OPERATOR(FDFScalar, FLWCScalar, MakeLWCScalar, float)
DEFINE_DF_FAST_TO_TILEOFFSET_OPERATOR(FDFVector2, FLWCVector2, MakeLWCVector2, float2)
DEFINE_DF_FAST_TO_TILEOFFSET_OPERATOR(FDFVector3, FLWCVector3, MakeLWCVector3, float3)
DEFINE_DF_FAST_TO_TILEOFFSET_OPERATOR(FDFVector4, FLWCVector4, MakeLWCVector4, float4)
#undef DEFINE_DF_TO_TILEOFFSET_OPERATOR
#undef DEFINE_DF_FAST_TO_TILEOFFSET_OPERATOR
FLWCMatrix DFToTileOffset(FDFMatrix In)
{
FLWCVector3 PosHigh = DFToTileOffset(MakeDFVector3(In.PostTranslation, 0));
float4x4 M = MultiplyTranslation(In.M, PosHigh.Offset);
float3 Tile = PosHigh.Tile;
return MakeLWCMatrix(Tile, M);
}
FLWCMatrix DFFastToTileOffset(FDFMatrix In)
{
#if UE_DF_NO_FAST_MATH
return DFToTileOffset(In);
#else
float4x4 M = In.M;
float3 Tile = In.PostTranslation / UE_LWC_RENDER_TILE_SIZE;
return MakeLWCMatrix(Tile, M);
#endif
}
FLWCInverseMatrix DFToTileOffset(FDFInverseMatrix In)
{
FLWCVector3 PosHigh = DFToTileOffset(MakeDFVector3(In.PreTranslation, 0));
float4x4 M = MultiplyTranslation(-PosHigh.Offset, In.M);
float3 Tile = PosHigh.Tile;
return MakeLWCInverseMatrix(Tile, M);
}
FLWCInverseMatrix DFFastToTileOffset(FDFInverseMatrix In)
{
#if UE_DF_NO_FAST_MATH
return DFToTileOffset(In);
#else
float4x4 M = In.M;
float3 Tile = In.PreTranslation / UE_LWC_RENDER_TILE_SIZE;
return MakeLWCInverseMatrix(Tile, M);
#endif
}
#define DFToTileOffset_Hack DFToTileOffset
FDFScalar DFFromTileOffset(FLWCScalar In)
{
float TileOffset = In.Tile * UE_LWC_RENDER_TILE_SIZE;
return DFFastTwoSum(TileOffset, In.Offset);
}
FDFVector2 DFFromTileOffset(FLWCVector2 In)
{
float2 TileOffset = In.Tile * UE_LWC_RENDER_TILE_SIZE;
return DFFastTwoSum(TileOffset, In.Offset);
}
FDFVector3 DFFromTileOffset(FLWCVector3 In)
{
float3 TileOffset = In.Tile * UE_LWC_RENDER_TILE_SIZE;
return DFFastTwoSum(TileOffset, In.Offset);
}
FDFVector4 DFFromTileOffset(FLWCVector4 In)
{
float4 TileOffset = In.Tile * UE_LWC_RENDER_TILE_SIZE;
return DFFastTwoSum(TileOffset, In.Offset);
}
FDFMatrix DFFromTileOffset(FLWCMatrix In)
{
float4x4 M = In.M;
float3 PostTranslation = In.Tile * UE_LWC_RENDER_TILE_SIZE;
return MakeDFMatrix(PostTranslation, M);
}
FDFInverseMatrix DFFromTileOffset(FLWCInverseMatrix In)
{
float4x4 M = In.M;
float3 PreTranslation = -In.Tile * UE_LWC_RENDER_TILE_SIZE;
return MakeDFInverseMatrix(PreTranslation, M);
}
#define DFFromTileOffset_Hack DFFromTileOffset
// Hacky LWCFunc(DFParam) shims for custom hlsl nodes in materials
float LWCToFloat(FDFScalar Value) { return DFDemote(Value); }
float2 LWCToFloat(FDFVector2 Value) { return DFDemote(Value); }
float3 LWCToFloat(FDFVector3 Value) { return DFDemote(Value); }
float4 LWCToFloat(FDFVector4 Value) { return DFDemote(Value); }
float4x4 LWCToFloat(FDFMatrix Value) { return DFDemote(Value); }
float4x4 LWCToFloat(FDFInverseMatrix Value) { return DFDemote(Value); }
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM6 || PLATFORM_SUPPORTS_SM6_0_WAVE_OPERATIONS
FLWCMatrix WaveReadLaneAt(FLWCMatrix In, uint SrcIndex)
{
FLWCMatrix Result;
Result.M[0] = WaveReadLaneAt(In.M[0], SrcIndex);
Result.M[1] = WaveReadLaneAt(In.M[1], SrcIndex);
Result.M[2] = WaveReadLaneAt(In.M[2], SrcIndex);
Result.M[3] = WaveReadLaneAt(In.M[3], SrcIndex);
Result.Tile = WaveReadLaneAt(In.Tile, SrcIndex);
return Result;
}
FLWCInverseMatrix WaveReadLaneAt(FLWCInverseMatrix In, uint SrcIndex)
{
FLWCInverseMatrix Result;
Result.M[0] = WaveReadLaneAt(In.M[0], SrcIndex);
Result.M[1] = WaveReadLaneAt(In.M[1], SrcIndex);
Result.M[2] = WaveReadLaneAt(In.M[2], SrcIndex);
Result.M[3] = WaveReadLaneAt(In.M[3], SrcIndex);
Result.Tile = WaveReadLaneAt(In.Tile, SrcIndex);
return Result;
}
#endif