Files
ZHGD_Web/Assets/Art/Art Plugins/GPUInstancer/Shaders/Include/GPUIBillboardSGInclude.cginc
2025-07-13 23:16:20 +08:00

77 lines
3.3 KiB
HLSL

#ifndef GPU_INSTANCER_BILLBOARD_SG_INCLUDED
#define GPU_INSTANCER_BILLBOARD_SG_INCLUDED
#define GPUI_PI 3.14159265359f
#define GPUI_TWO_PI 6.28318530718f
#ifdef unity_WorldToObject
#undef unity_WorldToObject
#endif
#ifdef unity_ObjectToWorld
#undef unity_ObjectToWorld
#endif
void GPUIBillboardVertexSG_float(in float3 vertex, in float frameCount, out float3 vertex_out, out float3 normal_out, out float3 tangent_out)
{
float3 billboardCameraDir = normalize(mul(((float3x3) unity_WorldToObject), _WorldSpaceCameraPos.xyz - unity_ObjectToWorld._m03_m13_m23));
// calculate camera vectors
float3 up = float3(0, 1, 0);
float3 forward = -normalize(UNITY_MATRIX_V._m20_m21_m22);
#ifdef _BILLBOARDFACECAMPOS_ON
float3 right = normalize(cross(float3(0, 1, 0), unity_ObjectToWorld._m03_m13_m23 - _WorldSpaceCameraPos));
#else
float3 right = normalize(UNITY_MATRIX_V._m00_m01_m02);
// adjust rotation matrix if camera is upside down
right *= sign(normalize(UNITY_MATRIX_V._m10_m11_m12).y);
#endif
// create camera rotation matrix
float4x4 rotationMatrix = float4x4(right, 0, up, 0, forward, 0, 0, 0, 0, 1);
// rotate to camera lookAt
vertex_out.x = vertex.x * length(unity_ObjectToWorld._m00_m10_m20);
vertex_out.y = vertex.y * length(unity_ObjectToWorld._m01_m11_m21);
vertex_out.z = vertex.z * length(unity_ObjectToWorld._m02_m12_m22);
vertex_out = (mul(float4(vertex_out, 1), rotationMatrix)).xyz;
// account for world position
vertex_out.xyz += unity_ObjectToWorld._m03_m13_m23;
// ignore initial object rotation for the billboard
vertex_out = (mul(unity_WorldToObject, float4(vertex_out, 1))).xyz;
vertex_out.y += (1 / frameCount * unity_ObjectToWorld[3].y + unity_ObjectToWorld[3].z) * length(unity_ObjectToWorld._m01_m11_m21);
// adjust normal and tangents
normal_out = -billboardCameraDir;
tangent_out = normalize(cross(up, normal_out));
}
void GPUIBillboardAtlasUVSG_float(in float4 texcoord, in float frameCount, out float2 atlasUV)
{
float3 billboardCameraDir = normalize(mul(((float3x3) unity_WorldToObject), _WorldSpaceCameraPos.xyz - unity_ObjectToWorld._m03_m13_m23));
// get current camera angle in radians
float angle = atan2(-billboardCameraDir.z, billboardCameraDir.x);
// calculate current frame index and set uvs
float frameIndex = round((angle - GPUI_PI / 2) / (GPUI_TWO_PI / frameCount));
atlasUV = texcoord.xy * float2(1.0 / frameCount, 1) + float2((1.0 / frameCount) * frameIndex, 0);
}
void GPUIBillboardFragmentSG_float(in float4 albedoTexture, in float4 normalTexture, in float normalStrength, in float3 normalWorld, in float3 tangentWorld, out float3 albedo_out, out float3 normal_out, out float depth_out)
{
albedo_out = albedoTexture.rgb;
// remap normalTexture back to [-1, 1]
float3 unpackedNormalTexture = lerp(float3(0, 1, 0), normalTexture.xyz, normalStrength);
float3 bitangentWorld = normalize(cross(normalWorld, tangentWorld) * (-unity_WorldTransformParams.w));
// modify normal map with the billboard world vectors
normal_out = normalize(mul(float3x3(tangentWorld, bitangentWorld, normalWorld), unpackedNormalTexture));
// calculate depth
depth_out = max(normalTexture.w - 0.35, 0);
}
#endif // GPU_INSTANCER_BILLBOARD_SG_INCLUDED