Files
healer-man/public/assets/game/combat-effects/original/runewaker/shaders/particle-spriteex.vertex.hlsl
T
2026-09-24 16:42:43 -04:00

96 lines
3.7 KiB
HLSL

// Globals
float4x3 g_worldTransform : register(c0);
float4x3 g_viewTransform : register(c3);
float4x4 g_projectionTransform : register(c6);
float4 g_ambientColor : register(c10);
float4 g_shCoefficients[9] : register(c11); // Spherical harmonics coefficients
float4 g_specularDirection : register(c21); // Object space specular position
float4 g_specularColor : register(c22);
float4 g_selfIllumination : register(c23); // Self-illumination term
float4 g_globalSettings : register(c25); // (Fog Constant, Start, End, Extrude Scale)
float4 g_globalDiffuse : register(c26);
float4x4 g_billboardTransform : register(c27); // Billboard transform
float4 g_prtParam : register(c31); // (u increment, v increment, AR, world ROT)
float4 g_quadScaleOffset : register(c32); // (scaleX, scaleY, offsetX, offsetY)
float4x4 g_orientationTransform : register(c33); // Particle poly orientation transform
float4 g_instanceData[210] : register(c37); // Instance data
struct VS_INPUT
{
float4 position : POSITION;
float4 diffuse : COLOR0;
};
struct VS_OUTPUT
{
float4 position : POSITION;
float4 diffuse : COLOR0;
float2 uv_albedo : TEXCOORD0;
float1 fog : TEXCOORD1;
};
VS_OUTPUT main(const VS_INPUT v)
{
VS_OUTPUT output;
// Initialize world-view vectors to 1
float4 worldPos = float4(1, 1, 1, 1);
// Calculate instance data indices
float1 posScaleOffset = (v.diffuse.w * 256.0f) * 3.0f;
float1 uvRotOffset = posScaleOffset + 1.0f;
float1 colorOffset = uvRotOffset + 1.0f;
// Scale & translate position by quad scale/offset
float3 scaledPosition = v.position.xyz;
scaledPosition.y = (scaledPosition.y + g_quadScaleOffset[2]) * g_quadScaleOffset[0];
scaledPosition.z = (scaledPosition.z + g_quadScaleOffset[3]) * g_quadScaleOffset[1] * g_prtParam.z;
// Scale position by particle scale
scaledPosition = scaledPosition * g_instanceData[(int) posScaleOffset].www;
// Rotate position
float3 rotRow0 = float3(0.0f, g_instanceData[(int) uvRotOffset].w, -g_instanceData[(int) uvRotOffset].z);
float3 rotRow1 = float3(0.0f, g_instanceData[(int) uvRotOffset].z, g_instanceData[(int) uvRotOffset].w);
worldPos.x = scaledPosition.x;
worldPos.y = dot(scaledPosition, rotRow0);
worldPos.z = dot(scaledPosition, rotRow1);
// Orientation transform
worldPos.xyz = mul(worldPos, (float4x3) g_orientationTransform);
// Handle world rotation
float4 rotatedWorldPos = float4(1, 1, 1, 1);
rotatedWorldPos.xyz = mul(worldPos, (float3x3) g_worldTransform);
worldPos = lerp(worldPos, rotatedWorldPos, g_prtParam.w);
// Billboard transform
worldPos.xyz = mul(worldPos, (float3x3) g_billboardTransform);
// Transform position to world space
float4 particleWorldPos = float4(1, 1, 1, 1);
particleWorldPos.xyz = g_instanceData[(int) posScaleOffset].xyz;
worldPos.xyz = worldPos.xyz + mul(particleWorldPos, (float4x3) g_worldTransform);
// Transform position to view space
float4 viewPos = float4(1, 1, 1, 1);
viewPos.xyz = mul(worldPos, (float4x3) g_viewTransform);
// Transform position to homogeneous space
output.position = mul(viewPos, (float4x4) g_projectionTransform);
// Calculate fog
float1 rcpFogRange = 1.0f / (g_globalSettings.z - g_globalSettings.y);
float1 relativeZ = max(viewPos.z - g_globalSettings.y, 0.0f);
output.fog = clamp(min(1.0f - (relativeZ * rcpFogRange), 1.0f - g_globalSettings.x), 0.0f, 1.0f);
// Multiply particle color by global diffuse
output.diffuse = g_instanceData[(int) colorOffset] * g_globalDiffuse;
// Calculate UV based on current frame index and texture uv increment
output.uv_albedo.xy = (g_instanceData[(int) uvRotOffset].xy * g_prtParam.xy) + v.diffuse.xy * g_prtParam.xy;
return output;
}