WuhuIslandTesting/Assets/SLZShaders/Include/Triplanar.hlsl
2025-01-07 02:06:59 +01:00

95 lines
No EOL
4 KiB
HLSL

#if !defined(SLZ_TRIPLANAR_INCLUDED)
#define SLZ_TRIPLANAR_INCLUDED
//#define TEXTURE2D_PARAM(textureName, samplerName) Texture2D textureName, sampler samplerName
/**
* Struct containg the ddx and ddy of the uvs combined into one half4 for each axis
*/
struct tpDerivatives
{
half4 ddX;
half4 ddY;
half4 ddZ;
};
/**
* Gets the derivatives of the worldspace coordinates reduced to 3 2 dimensional planes defined by each axis
*
* @param wPos Worldspace position
* @param[out] dd struct containing the x and y derivatives of each plane
*/
void GetDirectionalDerivatives(float3 wPos, out tpDerivatives dd)
{
dd.ddX.xy = ddx(wPos.zy);
dd.ddY.xy = ddx(wPos.xz);
dd.ddZ.xy = ddx(wPos.xy);
dd.ddX.zw = ddy(wPos.zy);
dd.ddY.zw = ddy(wPos.xz);
dd.ddZ.zw = ddy(wPos.xy);
}
/**
* Determines the worldspace axis that the given mesh normal is most closely aligned to, and returns the coordinates of the
* pixel in the plane aligned with that axis and the derivatives associated with that plane. Also generates a tangent to world
* matrix using the axes orthogonal to the dominant axis as the tangent and bitangent.
*
* @param[out] triplanarUV Coordinates of the fragment in the plane aligned with the dominant axis
* @param[out] ddxMax X derivatives of the coordinates of the fragment in the plane aligned with the dominant axis
* @param[out] ddyMax Y derivatives of the coordinates of the fragment in the plane aligned with the dominant axis
* @param[out] tanToWrld Tangent to world matrix composed of the other two axes as tangent and bitangent, and the mesh normal as the normal
* @param wPos World-space position of the fragment
* @param wNorm World-space mesh normal
* @param dd derivatives of the fragment's coordinates in each axis aligned plane
*/
void GetTPUVExpensive(out float2 triplanarUV, out half2 ddxMax, out half2 ddyMax, out half3x3 tanToWrld, float3 wPos, half3 wNorm,
tpDerivatives dd)
{
half3 dir;
dir.x = abs(wNorm.x) > abs(wNorm.y) && abs(wNorm.x) > abs(wNorm.z) ? 1 : 0;
dir.y = abs(wNorm.y) >= abs(wNorm.x) && abs(wNorm.y) > abs(wNorm.z) ? 1 : 0;
dir.z = abs(wNorm.z) >= abs(wNorm.y) && abs(wNorm.z) >= abs(wNorm.x) ? 1 : 0;
half3 dirSign = sign(wNorm);
dirSign.z = -dirSign.z; // u should be flipped on Z
ddxMax = dir.x * dd.ddX.xy + dir.y * dd.ddY.xy + dir.z * dd.ddZ.xy;
ddyMax = dir.x * dd.ddX.zw + dir.y * dd.ddY.zw + dir.z * dd.ddZ.zw;
//half3 maxDir = half3(dirX, dirY, dirZ);
float2 uvX = wPos.zy * float2(dirSign.x, 1.0);
triplanarUV = dir.x * uvX;
float2 uvY = wPos.xz * float2(dirSign.y, 1.0);
triplanarUV = mad(dir.y, uvY, triplanarUV);
float2 uvZ = wPos.xy * float2(dirSign.z, 1.0);
triplanarUV = mad(dir.z, uvZ, triplanarUV);
tanToWrld = half3x3(
dir.y * dirSign.y + dir.z * dirSign.z, 0, wNorm.x,
0, dir.x + dir.z, wNorm.y,
dir.x * dirSign.x, dir.y, wNorm.z
);
}
void GetTPUVCheap(out float2 triplanarUV, out half3x3 tanToWrld, float3 wPos, half3 wNorm)
{
half3 dir;
dir.x = abs(wNorm.x) > abs(wNorm.y) && abs(wNorm.x) > abs(wNorm.z) ? 1 : 0;
dir.y = abs(wNorm.y) >= abs(wNorm.x) && abs(wNorm.y) > abs(wNorm.z) ? 1 : 0;
dir.z = abs(wNorm.z) >= abs(wNorm.y) && abs(wNorm.z) >= abs(wNorm.x) ? 1 : 0;
half3 dirSign = sign(wNorm);
dirSign.z = -dirSign.z; // u should be flipped on Z
//half3 maxDir = half3(dirX, dirY, dirZ);
float2 uvX = wPos.zy * float2(dirSign.x, 1.0);
triplanarUV = dir.x * uvX;
float2 uvY = wPos.xz * float2(dirSign.y, 1.0);
triplanarUV = mad(dir.y, uvY, triplanarUV);
float2 uvZ = wPos.xy * float2(dirSign.z, 1.0);
triplanarUV = mad(dir.z, uvZ, triplanarUV);
tanToWrld = half3x3(
dir.y * dirSign.y + dir.z * dirSign.z, 0, wNorm.x,
0, dir.x + dir.z, wNorm.y,
dir.x * dirSign.x, dir.y, wNorm.z
);
}
#endif