struct SceneData { float4 positionNDC; //Unnormalized float2 screenPos; //Normalized and no refraction float3 positionWS; float3 color; float refractionMask; float viewDepth; float verticalDepth; }; // Project from eye space to world space #define WorldPosFromDepth(NDCw, depth, viewDir) -(depth.eye * (viewDir/NDCw) - _WorldSpaceCameraPos) //Linear depth difference between scene and current (transparent) geometry pixel #define SurfaceDepth(depth, positionCS) depth.eye - LinearEyeDepth(positionCS.z, _ZBufferParams) void PopulateSceneData(inout SceneData scene, in Varyings input, in WaterSurface water) { const float2 screenPos = input.positionNDC.xy / input.positionNDC.w; scene.positionNDC = input.positionNDC; scene.screenPos = screenPos; //Default for disabled depth texture scene.viewDepth = 1; scene.verticalDepth = 1; #ifdef _REFRACTION SceneDepth depth = SampleDepth(screenPos); float3 positionWS = WorldPosFromDepth(input.positionNDC.w, depth, water.viewDelta); float viewDepth = SurfaceDepth(depth, input.positionCS); const float2 refractionOffset = input.normalWS.xz * 0.5 * _RefractionStrength; SceneDepth depthRefract = SampleDepth(screenPos + refractionOffset); float3 positionWSRefract = WorldPosFromDepth(input.positionNDC.w, depthRefract, water.viewDelta); float viewDepthRefract = SurfaceDepth(depthRefract, input.positionCS); float mask = saturate(viewDepth) * saturate(viewDepthRefract); scene.positionWS = lerp(positionWS, positionWSRefract, mask); scene.viewDepth = lerp(viewDepth, viewDepthRefract, mask); //Distance to opaque geometry in normal direction scene.verticalDepth = length((water.positionWS - scene.positionWS) * water.vertexNormal); scene.color = SampleSceneColor(screenPos + refractionOffset * mask); scene.refractionMask = mask; #else SceneDepth depth = SampleDepth(screenPos); scene.positionWS = WorldPosFromDepth(input.positionNDC.w, depth, water.viewDelta); scene.viewDepth = SurfaceDepth(depth, input.positionCS); scene.verticalDepth = length((water.positionWS - scene.positionWS) * water.vertexNormal); scene.color = SampleSceneColor(screenPos); scene.refractionMask = 0; #endif } float GetWaterDensity(SceneData scene, float heightScalar, float viewDepthScalar) { const float viewDepth = scene.viewDepth; const float verticalDepth = scene.verticalDepth; const float depthAttenuation = 1.0 - exp(-viewDepth * viewDepthScalar * 0.1); const float heightAttenuation = saturate(verticalDepth * heightScalar); return max(depthAttenuation, heightAttenuation); } float4 ForwardPassFragment(Varyings input) : SV_Target { WaterSurface water = (WaterSurface)0; SceneData scene = (SceneData)0; float3 normalWS = normalize(input.normalWS.xyz); float3 WorldTangent = input.tangent.xyz; float3 WorldBiTangent = input.bitangent.xyz; //wPos.x in w-component float3 positionWS = float3(input.normalWS.w, input.tangent.w, input.bitangent.w); water.alpha = 1.0; water.positionWS = positionWS; water.viewDelta = _WorldSpaceCameraPos - positionWS; float3 viewDir = normalize(water.viewDelta); water.viewDir = viewDir; water.vertexNormal = normalize(input.normalWS.xyz); //Normal water.tangentNormal = float3(0.5, 0.5, 1); water.tangentWorldNormal = normalWS; half VdotN = 1.0 - saturate(dot(viewDir, normalWS)); half4 shadowMask = 1.0; float4 shadowCoords = float4(0, 0, 0, 0); Light mainLight = GetMainLight(shadowCoords, water.positionWS, shadowMask); PopulateSceneData(scene, input, water); //return float4(scene.verticalDepth.xxx, 1); //return float4(saturate(scene.viewDepth).xxx, 1); //return float4(scene.color, 1); water.fog = GetWaterDensity(scene, _DepthHorizontal, _DepthVertical); //Albedo float4 baseColor = lerp(_ShallowColor, _BaseColor, water.fog); water.fog *= baseColor.a; water.alpha = baseColor.a; float fresnel = saturate(pow(VdotN, _HorizonDistance)) * _HorizonColor.a; water.albedo = lerp(baseColor.rgb, _HorizonColor.rgb, fresnel); water.edgeFade = saturate(scene.verticalDepth / (_EdgeFade * 0.01)); water.alpha *= water.edgeFade; // Wave Mesure #if _INTERSECTION || _WAVE_FOAM float waveMesure = (positionWS.y - _WaveMesureMin) / (_WaveMesureMax - _WaveMesureMin); float2 nUV = positionWS.xz * _IntersectionTiling; float foamTexNoise = SAMPLE_TEXTURE2D(_IntersectionNoise, sampler_IntersectionNoise, nUV + TIME_VERTEX/_IntersectionTiling * _IntersectionSpeed).r; float interSecGradient = 1-saturate(exp(scene.verticalDepth) / _IntersectionLength); #endif #ifdef _WAVE_FOAM // remap wave from [_WaveFoamClipping,1] to [0,1] //float waveFoamNoise = (waveMesure - _WaveFoamClipping) / (1 - _WaveFoamClipping) * foamTexNoise; float waveFoamNoise = smoothstep(_WaveFoamClipping.x, _WaveFoamClipping.y, waveMesure * foamTexNoise); //return float4(waveFoamNoise.xxx, 1); #else float waveFoamNoise = 0; #endif /* ======== // Intercection =========== */ #ifdef _INTERSECTION float intersecMesure = waveMesure * interSecGradient; float dist = saturate(interSecGradient / _IntersectionFalloff); float intersecNoise = saturate(foamTexNoise + intersecMesure) * dist + dist; intersecNoise = smoothstep(_IntersectionClipping, 1, intersecNoise); #else float intersecNoise = 0; #endif #if _INTERSECTION || _WAVE_FOAM float noise = saturate(intersecNoise + waveFoamNoise); water.albedo.rgb = lerp(water.albedo.rgb, _IntersectionColor.rgb, noise); water.alpha = saturate(water.alpha + interSecGradient); #else float noise = 0; #endif /* ======== // Causitcs =========== */ #ifdef _CAUSTICS float2 cuv = positionWS.xz * _CausticsTiling; float coffset = TIME_VERTEX/_CausticsTiling * _CausticsSpeed; float3 caustics1 = SAMPLE_TEXTURE2D(_CausticsTex, sampler_CausticsTex, cuv + coffset).rgb; float3 caustics2 = SAMPLE_TEXTURE2D(_CausticsTex, sampler_CausticsTex, cuv*0.8 - coffset).rgb; // Limit distance from cam and verticalDepth float3 causticsDensity = saturate((1-length(water.viewDelta) / _CausticsClipping.x) * smoothstep(_CausticsClipping.y,1, scene.verticalDepth)); float3 caustics = min(caustics1, caustics2) * _CausticsBrightness * causticsDensity; #endif /* ======== // Reflection Prob =========== */ half3 reflectionVector = reflect(-viewDir, normalWS); water.reflections = GlossyEnvironmentReflection(reflectionVector, water.positionWS, _ReflectionBlur, 1 ,scene.screenPos.xy); //Schlick's BRDF fresnel AIR_RI = 1.000293 float cosTheta = saturate(dot(normalWS, viewDir)); water.reflectionMask = pow(max(0.0, 1.000293 - cosTheta), _ReflectionFresnel) * _ReflectionStrength; water.albedo = lerp(water.albedo, water.reflections.rgb, water.reflectionMask - noise); // =================== Make ApplyLight simple ========================= // =====Translucency Begin======== float3 lightDir = mainLight.direction; float3 lightColor = mainLight.color; float3 emission = 0; float3 specular = 0; float scatteringMask = saturate(water.fog + water.edgeFade); half incident = saturate(dot(lightDir, normalWS)) * _TranslucencyStrengthDirect; const float lightIntensity = lightColor.r * 0.3 + lightColor.g * 0.59 + lightColor.b * 0.11; half attenuation = incident * scatteringMask * lightIntensity; #ifdef _CAUSTICS emission += lerp(caustics * lightIntensity, _ShallowColor.rgb, attenuation) * mainLight.distanceAttenuation; #else emission = lerp(0, _ShallowColor.rgb, attenuation) * mainLight.distanceAttenuation; #endif // =====Translucency End======== #ifdef _LIGHT_COLOR // LightingLambert Light applied here half3 attenuatedLightColor = lightColor * (mainLight.distanceAttenuation * mainLight.shadowAttenuation); half3 diffuseColor = LightingLambert(attenuatedLightColor, lightDir, normalWS) + _GlossyEnvironmentColor.rgb * _AmbientStrength; float3 finalColor = (water.albedo * diffuseColor ) + emission + specular; #else float3 finalColor = (water.albedo ) + emission + specular; #endif finalColor = lerp(finalColor, _IntersectionColor.rgb, noise); // =================== Make ApplyLight simple end ========================= finalColor = lerp(scene.color, finalColor, water.fog + noise); //Apply fog half fogCoord = InitializeInputDataFog(float4(positionWS,1), input.fogFactor); finalColor = MixFog(finalColor, fogCoord); return float4(finalColor, water.alpha); }