#include "common_ps_fxc.h" struct PixelShaderLightInfo { float4 color; float4 dir; float4 pos; // These aren't used in pixel shaders. // float4 spotParams; // float4 atten; }; #define cOverbright 2.0f #define cOOOverbright 0.5f #define LIGHTTYPE_NONE 0 #define LIGHTTYPE_STATIC 1 #define LIGHTTYPE_SPOT 2 #define LIGHTTYPE_POINT 3 #define LIGHTTYPE_DIRECTIONAL 4 #define LIGHTTYPE_AMBIENT 5 static const int g_StaticLightTypeArray[22] = { LIGHTTYPE_NONE, LIGHTTYPE_STATIC, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_STATIC, LIGHTTYPE_STATIC, LIGHTTYPE_STATIC, LIGHTTYPE_STATIC, LIGHTTYPE_STATIC, LIGHTTYPE_STATIC, LIGHTTYPE_STATIC, LIGHTTYPE_STATIC, LIGHTTYPE_STATIC, LIGHTTYPE_STATIC }; static const int g_AmbientLightTypeArray[22] = { LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT, LIGHTTYPE_AMBIENT }; static const int g_LocalLightType0Array[22] = { LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_SPOT, LIGHTTYPE_POINT, LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_SPOT, LIGHTTYPE_SPOT, LIGHTTYPE_SPOT, LIGHTTYPE_POINT, LIGHTTYPE_POINT, LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_NONE, LIGHTTYPE_SPOT, LIGHTTYPE_POINT, LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_SPOT, LIGHTTYPE_SPOT, LIGHTTYPE_SPOT, LIGHTTYPE_POINT, LIGHTTYPE_POINT, LIGHTTYPE_DIRECTIONAL }; static const int g_LocalLightType1Array[22] = { LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_SPOT, LIGHTTYPE_POINT, LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_POINT, LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_NONE, LIGHTTYPE_SPOT, LIGHTTYPE_POINT, LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_POINT, LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_DIRECTIONAL }; // Better suited to Pixel shader models, 11 instructions in pixel shader float3 PixelShaderAmbientLight( const float3 worldNormal, const float3 cAmbientCube[6] ) { float3 linearColor, nSquared = worldNormal * worldNormal; float3 isNegative = ( worldNormal < 0.0 ); float3 isPositive = 1-isNegative; isNegative *= nSquared; isPositive *= nSquared; linearColor = isPositive.x * cAmbientCube[0] + isNegative.x * cAmbientCube[1] + isPositive.y * cAmbientCube[2] + isNegative.y * cAmbientCube[3] + isPositive.z * cAmbientCube[4] + isNegative.z * cAmbientCube[5]; return linearColor; } // Better suited to Vertex shader models // Six VS instructions due to use of constant indexing (slt, mova, mul, mul, mad, mad) float3 VertexShaderAmbientLight( const float3 worldNormal, const float3 cAmbientCube[6] ) { float3 nSquared = worldNormal * worldNormal; int3 isNegative = ( worldNormal < 0.0 ); float3 linearColor; linearColor = nSquared.x * cAmbientCube[isNegative.x] + nSquared.y * cAmbientCube[isNegative.y+2] + nSquared.z * cAmbientCube[isNegative.z+4]; return linearColor; } float3 AmbientLight( const float3 worldNormal, const float3 cAmbientCube[6] ) { // Vertex shader cases #ifdef SHADER_MODEL_VS_1_0 return VertexShaderAmbientLight( worldNormal, cAmbientCube ); #elif SHADER_MODEL_VS_1_1 return VertexShaderAmbientLight( worldNormal, cAmbientCube ); #elif SHADER_MODEL_VS_2_0 return VertexShaderAmbientLight( worldNormal, cAmbientCube ); #elif SHADER_MODEL_VS_3_0 return VertexShaderAmbientLight( worldNormal, cAmbientCube ); #else // Pixel shader case return PixelShaderAmbientLight( worldNormal, cAmbientCube ); #endif } //----------------------------------------------------------------------------- // Purpose: Compute scalar diffuse term with various optional tweaks such as // Half Lambert, ambient occlusion and Lafortune directional diffuse terms // Output : Returns a scalar result //----------------------------------------------------------------------------- float3 DiffuseTerm( const bool bHalfLambert, const float3 worldNormal, const float3 lightDir, const bool bDoAmbientOcclusion, const float fAmbientOcclusion, const bool bDoDirectionalDiffuse, const float3 vEyeDir, const bool bDoLightingWarp, in sampler lightWarpSampler ) { float3 fResult, NDotL = dot( worldNormal, lightDir ); // Unsaturated dot (-1 to 1 range) if( bHalfLambert ) { fResult = NDotL * 0.5 + 0.5; // Scale and bias to 0 to 1 range fResult *= fResult; // Square } else { fResult = max( 0.0f, NDotL ); // Saturate pure Lambertian term } if ( bDoDirectionalDiffuse ) { fResult *= dot( vEyeDir, worldNormal ) * 1.3; // Lafortune directional diffuse term } if ( bDoAmbientOcclusion ) { // Raise to higher powers for darker AO values // float fAOPower = lerp( 4.0f, 1.0f, fAmbientOcclusion ); // result *= pow( NDotL * 0.5 + 0.5, fAOPower ); fResult *= fAmbientOcclusion; } if ( bDoLightingWarp ) { fResult = 2.0f * tex1D( lightWarpSampler, fResult ); } return fResult; } float3 PixelShaderDoDiffuseLight( const float3 worldPos, const float3 worldNormal, int lightNum, int lightType, const float3 vertexColor, in sampler normalizeSampler, PixelShaderLightInfo cLightInfo[2], const bool bHalfLambert, const bool bDoAmbientOcclusion, const float fAmbientOcclusion, const bool bDoDirectionalDiffuse, const float3 vEyeDir, const bool bDoLightingWarp, in sampler lightWarpSampler ) { float3 lightDir, color = float3(0,0,0); if( ( lightType == LIGHTTYPE_SPOT ) || ( lightType == LIGHTTYPE_POINT ) ) // These two are equivalent for now... { lightDir = NormalizeWithCubemap( normalizeSampler, cLightInfo[lightNum].pos - worldPos ); color = vertexColor; } else if( lightType == LIGHTTYPE_DIRECTIONAL ) { lightDir = -cLightInfo[lightNum].dir; color = cLightInfo[lightNum].color; } return color * DiffuseTerm( bHalfLambert, worldNormal, lightDir, bDoAmbientOcclusion, fAmbientOcclusion, bDoDirectionalDiffuse, vEyeDir, bDoLightingWarp, lightWarpSampler ); } float3 SpecularTerm( const float3 vWorldNormal, const float3 vLightDir, const float fSpecularExponent, const float3 vEyeDir, const bool bDoAmbientOcclusion, const float fAmbientOcclusion ) { float3 result = float3(0.0f, 0.0f, 0.0f); float3 vReflect = reflect( -vEyeDir, vWorldNormal ); // Reflect view through normal float fSpecular = saturate(dot( vReflect, vLightDir )); // L.R (use half-angle instead?) fSpecular = pow( fSpecular, fSpecularExponent ); // Raise to specular power fSpecular *= saturate(dot( vWorldNormal, vLightDir )); // Mask with N.L if ( bDoAmbientOcclusion ) { fSpecular *= fAmbientOcclusion; } return fSpecular; } // Traditional fresnel term approximation float Fresnel( const float3 vNormal, const float3 vEyeDir ) { float fresnel = 1-saturate( dot( vNormal, vEyeDir ) ); // 1-(N.V) for Fresnel term return fresnel * fresnel; // Square for a more subtle look } // // Custom Fresnel with low, mid and high parameters defining a piecewise continuous function // with traditional fresnel (0 to 1 range) as input. The 0 to 0.5 range blends between // low and mid while the 0.5 to 1 range blends between mid and high // // | // | . M . . . H // | . // L // | // +---------------- // 0 1 // float Fresnel( const float3 vNormal, const float3 vEyeDir, float fLow, float fMid, float fHigh ) { float result, f = Fresnel( vNormal, vEyeDir); // Traditional Fresnel if ( f > 0.5f ) result = lerp( fMid, fHigh, (2*f)-1 ); // Blend between mid and high values else result = lerp( fLow, fMid, 2*f ); // Blend between low and mid values return result; } float3 PixelShaderDoSpecularLight( const float3 vWorldPos, const float3 vWorldNormal, const float fSpecularExponent, const float3 vEyeDir, int lightNum, int lightType, const float3 vertexColor, PixelShaderLightInfo cLightInfo[2], const bool bDoAmbientOcclusion, const float fAmbientOcclusion ) { float3 vLightDir, color = float3(0,0,0); if ( ( lightType == LIGHTTYPE_SPOT ) || ( lightType == LIGHTTYPE_POINT ) ) // These two are equivalent for now... { vLightDir = normalize( cLightInfo[lightNum].pos - vWorldPos ); color = vertexColor; } else if( lightType == LIGHTTYPE_DIRECTIONAL ) { vLightDir = -cLightInfo[lightNum].dir; color = cLightInfo[lightNum].color; } return color * SpecularTerm( vWorldNormal, vLightDir, fSpecularExponent, vEyeDir, bDoAmbientOcclusion, fAmbientOcclusion ); } float3 PixelShaderDoLightingLinear( const float3 worldPos, const float3 worldNormal, const float3 staticLightingColor, const int staticLightType, const int ambientLightType, const int localLightType0, const int localLightType1, const float3 vertexColor0, const float3 vertexColor1, const float3 cAmbientCube[6], in sampler normalizeSampler, PixelShaderLightInfo cLightInfo[2], const bool bHalfLambert, const int localLightType2, const int localLightType3, const bool bDoAmbientOcclusion, const float fAmbientOcclusion, const bool bDoDirectionalDiffuse, const float3 vEyeDir, const bool bDoLightingWarp, in sampler lightWarpSampler ) { float3 linearColor = 0.0f; if( staticLightType == LIGHTTYPE_STATIC ) { // The static lighting comes in in gamma space and has also been premultiplied by $cOOOverbright // need to get it into // linear space so that we can do adds. linearColor += GammaToLinear( staticLightingColor * cOverbright ); } if( ambientLightType == LIGHTTYPE_AMBIENT ) { float3 ambient = AmbientLight( worldNormal, cAmbientCube ); if ( bDoAmbientOcclusion ) ambient *= fAmbientOcclusion * fAmbientOcclusion; linearColor += ambient; } if( localLightType0 != LIGHTTYPE_NONE ) { linearColor += PixelShaderDoDiffuseLight( worldPos, worldNormal, 0, localLightType0, vertexColor0, normalizeSampler, cLightInfo, bHalfLambert, bDoAmbientOcclusion, fAmbientOcclusion, bDoDirectionalDiffuse, vEyeDir, bDoLightingWarp, lightWarpSampler ); } if( localLightType1 != LIGHTTYPE_NONE ) { linearColor += PixelShaderDoDiffuseLight( worldPos, worldNormal, 1, localLightType1, vertexColor1, normalizeSampler, cLightInfo, bHalfLambert, bDoAmbientOcclusion, fAmbientOcclusion, bDoDirectionalDiffuse, vEyeDir, bDoLightingWarp, lightWarpSampler ); } return linearColor; } float3 PixelShaderDoSpecularLighting( const float3 worldPos, const float3 worldNormal, const float fSpecularExponent, const float3 vEyeDir, const int localLightType0, const int localLightType1, const float3 vertexColor0, const float3 vertexColor1, PixelShaderLightInfo cLightInfo[2], const bool bDoAmbientOcclusion=false, const float fAmbientOcclusion=0 ) { float3 returnColor = float3( 0.0f, 0.0f, 0.0f ); if( localLightType0 != LIGHTTYPE_NONE ) { returnColor += PixelShaderDoSpecularLight( worldPos, worldNormal, fSpecularExponent, vEyeDir, 0, localLightType0, vertexColor0, cLightInfo, bDoAmbientOcclusion, fAmbientOcclusion ); } if( localLightType1 != LIGHTTYPE_NONE ) { returnColor += PixelShaderDoSpecularLight( worldPos, worldNormal, fSpecularExponent, vEyeDir, 1, localLightType1, vertexColor1, cLightInfo, bDoAmbientOcclusion, fAmbientOcclusion ); } return returnColor; } // Called directly by newer shaders or through the following wrapper for older shaders float3 PixelShaderDoLightingTwoLights( const float3 worldPos, const float3 worldNormal, const float3 staticLightingColor, const int staticLightType, const int ambientLightType, const int localLightType0, const int localLightType1, const float modulation, const float3 vertexColor0, const float3 vertexColor1, const float3 cAmbientCube[6], in sampler normalizeSampler, PixelShaderLightInfo cLightInfo[2], const bool bHalfLambert, // New optional/experimental parameters const bool bDoAmbientOcclusion, const float fAmbientOcclusion, const bool bDoDirectionalDiffuse, const float3 vEyeDir, const bool bDoLightingWarp, in sampler lightWarpSampler ) { PixelShaderLightInfo lightInfo[2]; lightInfo[0] = cLightInfo[0]; lightInfo[1] = cLightInfo[1]; float3 returnColor; // special case for no lighting if( staticLightType == LIGHTTYPE_NONE && ambientLightType == LIGHTTYPE_NONE && localLightType0 == LIGHTTYPE_NONE && localLightType1 == LIGHTTYPE_NONE ) { returnColor = float3( 0.0f, 0.0f, 0.0f ); } else if( staticLightType == LIGHTTYPE_STATIC && ambientLightType == LIGHTTYPE_NONE && localLightType0 == LIGHTTYPE_NONE && localLightType1 == LIGHTTYPE_NONE ) { // special case for static lighting only returnColor = GammaToLinear( staticLightingColor ); } else { float3 linearColor; linearColor = PixelShaderDoLightingLinear( worldPos, worldNormal, staticLightingColor, staticLightType, ambientLightType, localLightType0, localLightType1, vertexColor0, vertexColor1, cAmbientCube, normalizeSampler, lightInfo, bHalfLambert, LIGHTTYPE_NONE, LIGHTTYPE_NONE, bDoAmbientOcclusion, fAmbientOcclusion, bDoDirectionalDiffuse, vEyeDir, bDoLightingWarp, lightWarpSampler ); if (modulation != 1.0f) { linearColor *= modulation; } // go ahead and clamp to the linear space equivalent of overbright 2 so that we match // everything else. // returnColor = HuePreservingColorClamp( linearColor, pow( 2.0f, 2.2 ) ); returnColor = linearColor; } return returnColor; } // Two lights...legacy parameter list... float3 PixelShaderDoLighting( const float3 worldPos, const float3 worldNormal, const float3 staticLightingColor, const int staticLightType, const int ambientLightType, const int localLightType0, const int localLightType1, const float modulation, const float3 vertexColor0, const float3 vertexColor1, const float3 cAmbientCube[6], in sampler normalizeSampler, PixelShaderLightInfo cLightInfo[2], const bool bHalfLambert ) { // Call new entrypoint, hooking up default params return PixelShaderDoLightingTwoLights( worldPos, worldNormal, staticLightingColor, staticLightType, ambientLightType, localLightType0, localLightType1, modulation, vertexColor0, vertexColor1, cAmbientCube, normalizeSampler, cLightInfo, bHalfLambert, // Defaults for new params false, 0, false, float3(1,0,0), false, normalizeSampler ); }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 5821 | Knut Wikstrom |
Added Valve Source code. This is NOT to be commited to other than new code from Valve. |