671 lines
25 KiB
HLSL
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 |