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