//========== Copyright (c) Valve Corporation, All rights reserved. ==========// #include "common_vs_fxc.h" #include "spline_fxc.h" const hlsl_float4x3 cModelView : register(SHADER_SPECIFIC_CONST_0); const float4x4 cProj : register(SHADER_SPECIFIC_CONST_3); const float g_MinPixelSize : register(SHADER_SPECIFIC_CONST_7); const float g_Const8 : register(SHADER_SPECIFIC_CONST_8); #define g_FlTilingMultiplier g_Const8.x struct VS_INPUT { // This is all of the stuff that we ever use. float4 vTint : COLOR; float4 vParms : POSITION; // T V side_id float4 vSplinePt0 : TEXCOORD0; // x y z rad float4 vSplinePt1 : TEXCOORD1; // x y z rad float4 vSplinePt2 : TEXCOORD2; // x y z rad float4 vSplinePt3 : TEXCOORD3; // x y z rad }; // VS_OUTPUT in a common file. #include "common_splinerope_fxc.h" #define P0 (v.vSplinePt0) #define P1 (v.vSplinePt1) #define P2 (v.vSplinePt2) #define P3 (v.vSplinePt3) VS_OUTPUT main( const VS_INPUT v ) { VS_OUTPUT o; // posrad.xyz is worldspace position and posrad.w is worldspace diameter. float4 posrad = CatmullRomSpline( P0, P1, P2, P3, v.vParms.x ); // calculate projected position here so that we can figure out how much to bloat the diameter to avoid aliasing of the sort where you skip pixels in a segment. { // PERF FIXME!! This could be simplified quite a bit if this ever becomes a bottleneck. I feel dirty. // Get the view-space position for two points that are posrad.w units away from each other horizontally. float3 viewPos1 = mul4x3( float4( posrad.xyz, 1.0f ), cModelView ); float3 viewPos2 = viewPos1 + float3( posrad.w, 0.0f, 0.0f ); // Project both points. float4 projPos1 = mul( float4( viewPos1, 1.0f ), cProj ); float4 projPos2 = mul( float4( viewPos2, 1.0f ), cProj ); // Get the distance of the two points from each other in normalized screen space. float projectedDiameterInPixels = abs( ( projPos1.x / projPos1.w ) - ( projPos2.x / projPos2.w ) ); // Compare the distance between the two points to the minimum allowed to keep from skipping pixels and causing aliasing. if ( projectedDiameterInPixels < g_MinPixelSize ) { // Scale the radius in world space so that it is bigger than the required pixel size in screen space. posrad.w *= ( g_MinPixelSize / projectedDiameterInPixels ); } } float3 v2p = float3( 0, 0, 1 ); v2p = posrad.xyz - cEyePos; // screen aligned float3 tangent = DCatmullRomSpline3( P0, P1, P2, P3, v.vParms.x ); float3 ofs = normalize( cross( v2p, normalize( tangent ) ) ); posrad.xyz += ofs * ( posrad.w * ( v.vParms.z - .5 ) ); o.projPos = mul( float4(posrad.xyz, 1.0f), cViewProj ); #ifdef _PS3 // Account for OpenGL's flipped y coordinate and expanded z range [-1,1] instead of [0,1] o.projPos.y = -o.projPos.y; o.projPos.z = 2.0f * o.projPos.z - o.projPos.w; #endif // _PS3 o.worldPos_projPosZ.xyz = posrad.xyz; o.worldPos_projPosZ.w = o.projPos.z; o.texCoord.xy = float2( 1.0f - v.vParms.z, v.vParms.y ); o.texCoord.y *= g_FlTilingMultiplier; o.argbcolor = float4( v.vTint.rgb, v.vTint.a ); #if !defined( _X360 ) && !defined( SHADER_MODEL_VS_3_0 ) { o.fog = CalcFixedFunctionFog( posrad.xyz, 0 ); } #endif return o; }