//========= Copyright Valve Corporation, All rights reserved. ============// #include "common_ps_fxc.h" struct DrawWater_params_t { float2 vBumpTexCoord; #if MULTITEXTURE float4 vExtraBumpTexCoord; #endif float4 vReflectXY_vRefractYX; float w; float4 vReflectRefractScale; float fReflectOverbright; float4 vReflectTint; float4 vRefractTint; half3 vTangentEyeVect; float4 waterFogColor; #if BASETEXTURE HALF4 lightmapTexCoord1And2; HALF4 lightmapTexCoord3; #endif float4 vProjPos; float4 pixelFogParams; float fWaterFogStart; float fWaterFogEndMinusStart; }; void DrawWater( in DrawWater_params_t i, #if BASETEXTURE in sampler BaseTextureSampler, in sampler LightmapSampler, #endif in sampler NormalSampler, in sampler RefractSampler, in sampler ReflectSampler, out float4 result, out float fogFactor ) { bool bReflect = REFLECT ? true : false; bool bRefract = REFRACT ? true : false; #if MULTITEXTURE float4 vNormal = tex2D( NormalSampler, i.vBumpTexCoord ); float4 vNormal1 = tex2D( NormalSampler, i.vExtraBumpTexCoord.xy ); float4 vNormal2 = tex2D( NormalSampler, i.vExtraBumpTexCoord.zw ); vNormal = 0.33 * ( vNormal + vNormal1 + vNormal2 ); #if ( NORMAL_DECODE_MODE == NORM_DECODE_ATI2N ) vNormal.xy = vNormal.xy * 2.0f - 1.0f; vNormal.z = sqrt( 1.0f - dot(vNormal.xy, vNormal.xy) ); vNormal.a = 1.0f; #else vNormal.xyz = 2.0 * vNormal.xyz - 1.0; #endif #else float4 vNormal = DecompressNormal( NormalSampler, i.vBumpTexCoord, NORMAL_DECODE_MODE ); #endif // Perform division by W only once float ooW = 1.0f / i.w; float2 unwarpedRefractTexCoord = i.vReflectXY_vRefractYX.wz * ooW; #if ABOVEWATER float waterFogDepthValue = tex2D( RefractSampler, unwarpedRefractTexCoord ).a; #else // We don't actually have valid depth values in alpha when we are underwater looking out, so // just set to farthest value. float waterFogDepthValue = 1.0f; #endif float4 reflectRefractScale = i.vReflectRefractScale; #if !BASETEXTURE #if ( BLURRY_REFRACT == 0 ) reflectRefractScale *= waterFogDepthValue; #endif #endif // Compute coordinates for sampling Reflection float2 vReflectTexCoord; float2 vRefractTexCoord; // vectorize the dependent UV calculations (reflect = .xy, refract = .wz) float4 vN; vN.xy = vNormal.xy; vN.w = vNormal.x; vN.z = vNormal.y; float4 vDependentTexCoords = vN * vNormal.a * reflectRefractScale; vDependentTexCoords += ( i.vReflectXY_vRefractYX * ooW ); vReflectTexCoord = vDependentTexCoords.xy; vRefractTexCoord = vDependentTexCoords.wz; HALF4 vReflectColor = tex2D( ReflectSampler, vReflectTexCoord ); #if BLURRY_REFRACT // Sample reflection and refraction float2 ddx1=float2(0.005,0); float2 ddy1=float2(0,0.005); float4 vRefractColor=float4(0,0,0,0); #if 0 float sumweights=0; for(int ix=-2;ix<=2;ix++) { for(int iy=-2;iy<=2;iy++) { float weight=1; ///(1+abs(ix)+abs(iy)); vRefractColor += weight*tex2D( RefractSampler, vRefractTexCoord+ix*ddx1+iy*ddy1); sumweights+=weight; } } #else // NOTE: Generated by genwaterloop.pl in the stdshaders directory. // Need to unroll for 360 to avoid shader compilation problems. // Modified genwaterloop.pl and regenerate if you need different params vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -2 * ddx1 + -2 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -2 * ddx1 + -1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -2 * ddx1 + 0 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -2 * ddx1 + 1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -2 * ddx1 + 2 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -1 * ddx1 + -2 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -1 * ddx1 + -1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -1 * ddx1 + 0 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -1 * ddx1 + 1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + -1 * ddx1 + 2 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 0 * ddx1 + -2 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 0 * ddx1 + -1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 0 * ddx1 + 0 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 0 * ddx1 + 1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 0 * ddx1 + 2 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 1 * ddx1 + -2 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 1 * ddx1 + -1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 1 * ddx1 + 0 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 1 * ddx1 + 1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 1 * ddx1 + 2 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 2 * ddx1 + -2 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 2 * ddx1 + -1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 2 * ddx1 + 0 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 2 * ddx1 + 1 * ddy1 ); vRefractColor += tex2D( RefractSampler, vRefractTexCoord + 2 * ddx1 + 2 * ddy1 ); float sumweights = 25; // NOTE: end of generated code. #endif vRefractColor *= (1.0/sumweights); vReflectColor *= i.fReflectOverbright; vReflectColor *= i.vReflectTint; vRefractColor *= i.vRefractTint; # if ABOVEWATER // Don't mess with this in the underwater case since we don't really have // depth values there. // get the blurred depth value to be used for fog. waterFogDepthValue = vRefractColor.a; # endif #else vReflectColor *= i.vReflectTint; HALF4 vRefractColor = tex2D( RefractSampler, vRefractTexCoord ); // get the depth value from the refracted sample to be used for fog. # if ABOVEWATER // Don't mess with this in the underwater case since we don't really have // depth values there. waterFogDepthValue = tex2D( RefractSampler, vRefractTexCoord ).a; # endif #endif half3 vEyeVect; vEyeVect = normalize( i.vTangentEyeVect ); // Fresnel term HALF fNdotV = saturate( dot( vEyeVect, vNormal ) ); HALF fFresnel = pow( 1.0 - fNdotV, 5 ); #if !BASETEXTURE // fFresnel == 1.0f means full reflection fFresnel *= saturate( ( waterFogDepthValue - 0.05f ) * 20.0f ); #endif // blend between refraction and fog color. #if ABOVEWATER vRefractColor = lerp( vRefractColor, i.waterFogColor * LINEAR_LIGHT_SCALE, saturate( waterFogDepthValue - 0.05f ) ); #else float waterFogFactor = saturate( ( i.vProjPos.z - i.fWaterFogStart ) / i.fWaterFogEndMinusStart ); vRefractColor = lerp( vRefractColor, i.waterFogColor * LINEAR_LIGHT_SCALE, waterFogFactor ); #endif #if BASETEXTURE float4 baseSample = tex2D( BaseTextureSampler, i.vBumpTexCoord.xy ); HALF2 bumpCoord1; HALF2 bumpCoord2; HALF2 bumpCoord3; ComputeBumpedLightmapCoordinates( i.lightmapTexCoord1And2, i.lightmapTexCoord3.xy, bumpCoord1, bumpCoord2, bumpCoord3 ); HALF4 lightmapSample1 = tex2D( LightmapSampler, bumpCoord1 ); HALF3 lightmapColor1 = lightmapSample1.rgb; HALF3 lightmapColor2 = tex2D( LightmapSampler, bumpCoord2 ); HALF3 lightmapColor3 = tex2D( LightmapSampler, bumpCoord3 ); float3 dp; dp.x = saturate( dot( vNormal, bumpBasis[0] ) ); dp.y = saturate( dot( vNormal, bumpBasis[1] ) ); dp.z = saturate( dot( vNormal, bumpBasis[2] ) ); dp *= dp; float3 diffuseLighting = dp.x * lightmapColor1 + dp.y * lightmapColor2 + dp.z * lightmapColor3; float sum = dot( dp, float3( 1.0f, 1.0f, 1.0f ) ); diffuseLighting *= LIGHT_MAP_SCALE / sum; HALF3 diffuseComponent = baseSample.rgb * diffuseLighting; #endif if( bReflect && bRefract ) { result = lerp( vRefractColor, vReflectColor, fFresnel ); } else if( bReflect ) { #if BASETEXTURE result = float4( diffuseComponent, 1.0f ) + vReflectColor * fFresnel * baseSample.a; #else result = vReflectColor; #endif } else if( bRefract ) { result = vRefractColor; } else { result = float4( 0.0f, 0.0f, 0.0f, 0.0f ); } #if (PIXELFOGTYPE == PIXEL_FOG_TYPE_RANGE) fogFactor = CalcRangeFog( i.vProjPos.z, i.pixelFogParams.x, i.pixelFogParams.z, i.pixelFogParams.w ); #else fogFactor = 0; #endif }