// 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; }