#ifndef KWS_WATER_FRAG_PASS #define KWS_WATER_FRAG_PASS half4 fragWater(v2fWater i) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); float2 screenUV = i.screenPos.xy / i.screenPos.w; float3 viewDir = GetWorldSpaceViewDirNorm(i.worldPosRefracted); float surfaceDepthZ = i.screenPos.z / i.screenPos.w; float surfaceDepthZEye = LinearEyeDepthUniversal(surfaceDepthZ); float sceneZ = GetSceneDepth(screenUV); float sceneZEye = LinearEyeDepthUniversal(sceneZ); float distanceToCamera = GetWorldToCameraDistance(i.worldPos); float3 sceneWorldPos = GetWorldSpacePositionFromDepth(screenUV, sceneZ); float waterDepth = i.worldPosRefracted.y - sceneWorldPos.y; waterDepth = lerp(clamp(abs(surfaceDepthZEye - sceneZEye) * 0.1, 0, 10), waterDepth, 1-KWS_Pow10(1-viewDir.y)); half surfaceMask = max(i.surfaceMask.x >= 0.999, i.surfaceMask.x <= 0.0001); half exposure = GetExposure(); half alpha = 1; float3 turbidityColor = KWS_TurbidityColor; float3 waterColor = KWS_WaterColor; float transparent = KWS_Transparent; float localZoneDensity = 0; bool isDynamicWavesZone = false; float4 foamData = float4(1, 2.25, 1, 1); float shorelineMask = 1; float riverMask = 0; float waterfallMask = 0; float foamMask = 0; float2 flowDirection = 0; float3 dynamicWavesNormal = float3(0, 1, 0); float borderFade = 0; float dynamicWavesNormalMask = 0; float flowSpeedMultiplier = 1; float velocityLength = 0; float dynamicWavesHeight = 0; float dynamicWavesFoamAlpha = 1; float4 colorData = float4(0, 0, 0, 0); #if defined(KWS_USE_LOCAL_WATER_ZONES) UNITY_LOOP for (uint zoneIdx = 0; zoneIdx < KWS_WaterLocalZonesCount; zoneIdx++) { LocalZoneData zone = KWS_ZoneData_LocalZone[zoneIdx]; // if (zone.cutoutMode > 0) // { // float3 distanceToBox = abs(i.worldPosRefracted.xyz - zone.center.xyz) / zone.halfSize.xyz; // float distanceToBorder = KWS_MAX(saturate(distanceToBox)); // float cutoutFadeFactor = saturate(smoothstep(0, zone.cutoutFadeFactor * 0.5, 1 - distanceToBorder)); // cutoutFadeFactor = 1 - KWS_Pow2(1 - cutoutFadeFactor); // alpha = lerp(1 - cutoutFadeFactor, cutoutFadeFactor, zone.cutoutMode == 2); // //return float4(distanceToBorder, 0, 0, 1); // } if (zone.overrideHeight > 0.5 && zone.clipWaterBelowZone) { float2 distanceToBox = abs(mul(i.worldPos.xz - zone.center.xz, zone.rotationMatrix)) / zone.halfSize.xz; float distanceToBorder = max(distanceToBox.x, distanceToBox.y); float zoneMinHeight = zone.center.y - zone.halfSize.y; if (distanceToBorder < 1.1 && i.worldPosRefracted.y < zoneMinHeight) discard; localZoneDensity = 1; } if (zone.overrideColorSettings > 0.5) { float tEntry=0; float3 sceneWorldPos = GetWorldSpacePositionFromDepth(screenUV, sceneZ); float3 surfaceOffset = float3(0, max(0, zone.center.y + zone.halfSize.y - i.worldPosRefracted.y) * 0.5f, 0); float density = 0; if (zone.useSphereBlending > 0.5) { density = KWS_SDF_SphereDensity(i.worldPosRefracted, normalize(sceneWorldPos - i.worldPosRefracted), zone.center.xyz, zone.halfSize.x, length(i.worldPosRefracted - sceneWorldPos), tEntry); } else { float2 boxSDF = KWS_SDF_IntersectionBox(i.worldPosRefracted, normalize(sceneWorldPos - i.worldPosRefracted), zone.rotationMatrix, zone.center, zone.halfSize); density = boxSDF.x < boxSDF.y && boxSDF.y > 0 && boxSDF.x < length(i.worldPosRefracted - sceneWorldPos); tEntry = boxSDF.x; } if (density > 0) { density = saturate(density * 2); density = lerp(0, density, saturate(transparent / max(1, tEntry))); transparent = lerp(transparent, zone.transparent, density); turbidityColor = lerp(turbidityColor, zone.turbidityColor.xyz, density); waterColor = lerp(waterColor, zone.waterColor.xyz, density); localZoneDensity = lerp(localZoneDensity, 1, density); } } } #endif if (alpha < 0.001) return 0; float4 advectedUV = 0; bool useAdvectedUV = false; bool useDynamicWavesFoamTexture = false; #ifdef KWS_USE_ZONE_INSTANCE isDynamicWavesZone = true; float4 dynamicWaves = GetDynamicWavesZone(i.uv); float4 dynamicWavesAdditionalData = GetDynamicWavesZoneAdditionalDataBicubic(i.uv); //(wetmap, shoreline mask, foam mask, wetDepth) float3 zoneNormal = i.worldNormal; float zoneFade = GetDynamicWavesBorderFading(i.uv); zoneNormal = lerp(float3(0, 1, 0), zoneNormal, zoneFade); flowSpeedMultiplier *= KWS_DynamicWavesZoneFlowSpeedMultiplier; dynamicWavesFoamAlpha *= KWS_DynamicWavesZoneFoamData.w; foamData.xyz = KWS_DynamicWavesZoneFoamData; foamData.w = foamData.z *(KWS_DynamicWavesZoneSize.z / KWS_DynamicWavesZoneSize.x); useDynamicWavesFoamTexture = KWS_DynamicWavesUseFoamTexture; useAdvectedUV = false; //baked mode can't use advected textures float waterfallThreshold = GetDynamicWavesWaterfallTreshold(zoneNormal) * zoneFade; dynamicWaves.xy = lerp(dynamicWaves.xy, dynamicWaves.xy * 0.2, waterfallThreshold); flowDirection = (flowDirection + dynamicWaves.xy); shorelineMask = max(dynamicWavesAdditionalData.y, 1 - zoneFade); dynamicWavesNormal = KWS_BlendNormals(dynamicWavesNormal, zoneNormal); velocityLength += length(dynamicWaves.xy); dynamicWavesHeight += dynamicWaves.z; borderFade = saturate(borderFade + zoneFade); foamMask = max(foamMask, dynamicWavesAdditionalData.z * zoneFade); waterfallThreshold *= exp(-dynamicWaves.z * 0.35); float foamWaveThreshold = 1-saturate(lerp(0.5, saturate(waterfallThreshold * 5), shorelineMask)); waterfallMask = saturate(waterfallMask + waterfallThreshold); #ifdef KWS_USE_COLORED_DYNAMIC_WAVES float4 zoneColorData = GetDynamicWavesZoneColorData(i.uv); float colorTransparencyFactor = (dot(zoneColorData.rgb, 0.33)); zoneColorData.a = lerp(zoneColorData.a, 0, colorTransparencyFactor); zoneColorData.rgb = lerp(zoneColorData.rgb, zoneColorData.rgb * 0.35, saturate(zoneColorData.a * zoneColorData.a + zoneColorData.a * 2)); zoneColorData.a = saturate(zoneColorData.a * 2); turbidityColor = lerp(turbidityColor, zoneColorData.rgb, zoneColorData.a); waterColor = lerp(waterColor, zoneColorData.rgb, zoneColorData.a); transparent = lerp(transparent, DYNAMIC_WAVE_COLOR_MAX_TRANSPARENT, zoneColorData.a); colorData = max(colorData, zoneColorData); #endif velocityLength *= KWS_Pow2(borderFade); dynamicWavesNormalMask = saturate(dynamicWavesHeight * 0.5 * velocityLength) * KWS_Pow3(borderFade); flowDirection *= KWS_Pow2(borderFade); #endif #if defined(KWS_USE_DYNAMIC_WAVES) || defined(KWS_USE_COLORED_DYNAMIC_WAVES) float3 dynamicWavesMapUV = GetDynamicWavesMapUV(i.worldPosRefracted, distanceToCamera); isDynamicWavesZone = !IsOutsideUvBorders(dynamicWavesMapUV.xy); if (isDynamicWavesZone) { float4 dynamicWaves = GetDynamicWavesMapBicubic(dynamicWavesMapUV); DynamicWavesAdditionalData additionalData = GetDynamicWavesAdditionalMapBicubic(dynamicWavesMapUV); dynamicWavesNormal = GetDynamicWavesNormalMap(dynamicWavesMapUV); float waterfallThreshold = GetDynamicWavesWaterfallTreshold(dynamicWavesNormal); dynamicWaves.xy = lerp(dynamicWaves.xy, dynamicWaves.xy * 0.2, waterfallThreshold); borderFade = additionalData.zoneFade; waterfallThreshold *= exp(-dynamicWaves.z * 0.35); waterfallMask = saturate(waterfallMask + waterfallThreshold); foamMask = additionalData.foamMask * borderFade; flowDirection = dynamicWaves.xy * borderFade; shorelineMask = max(additionalData.shorelineMask, 1-borderFade); velocityLength = length(dynamicWaves.xy) * borderFade; dynamicWavesHeight = dynamicWaves.z; ZoneData zone = KWS_ZoneData[additionalData.zoneID]; useAdvectedUV = zone.useAdvectedUV; useDynamicWavesFoamTexture = zone.useFoamTexture; flowSpeedMultiplier = zone.flowSpeedMultiplier; dynamicWavesFoamAlpha *= zone.foamData.w; foamData.xyz = zone.foamData.xyz; foamData.w = foamData.z * (zone.halfSize.z / zone.halfSize.x); foamMask *= useDynamicWavesFoamTexture; if (zone.useAdvectedUV) advectedUV = GetDynamicWavesAdvectedUVMap(dynamicWavesMapUV); #ifdef KWS_USE_COLORED_DYNAMIC_WAVES float4 zoneColorData = GetDynamicWavesColorMap(dynamicWavesMapUV); float colorTransparencyFactor = (dot(zoneColorData.rgb, 0.33)); zoneColorData.a = lerp(zoneColorData.a, 0, colorTransparencyFactor); zoneColorData.rgb = lerp(zoneColorData.rgb, zoneColorData.rgb * 0.35, saturate(zoneColorData.a * zoneColorData.a + zoneColorData.a * 2)); zoneColorData.a = saturate(zoneColorData.a * 2); turbidityColor = lerp(turbidityColor, zoneColorData.rgb, zoneColorData.a); waterColor = lerp(waterColor, zoneColorData.rgb, zoneColorData.a); //transparent = lerp(transparent, DYNAMIC_WAVE_COLOR_MAX_TRANSPARENT, zoneColorData.a); colorData = zoneColorData; #endif } #endif alpha = lerp(1-KWS_Pow5(1-borderFade), alpha, KWS_RenderOcean); if (alpha < 0.001) return 0; float2 flowDirectionNormalized = NormalizeDynamicWavesVelocity(flowDirection); float noiseMask = GetNoiseMask(i.worldPos.xz, 1, 1); ///////////////////////////////////////////////////////////// NORMAL //////////////////////////////////////////////////////////////////////////////////////////////////////// float3 tangentNormal = float3(0, 1, 0); float oceanFoamMask = 0; #if defined(KWS_USE_OCEAN_RENDERING) float3 wavesNormalFoam = GetFftWavesNormalFoam(i.worldPos, i.windAttenuation); tangentNormal = float3(wavesNormalFoam.x, 1, wavesNormalFoam.z); tangentNormal = lerp(float3(0, 1, 0), tangentNormal, any(fwidth(i.worldPos.xz))); //fix horizontal flickering oceanFoamMask = wavesNormalFoam.y * noiseMask; #endif #if defined(KWS_USE_DYNAMIC_WAVES) || defined(KWS_USE_COLORED_DYNAMIC_WAVES) || defined(KWS_USE_ZONE_INSTANCE) if (isDynamicWavesZone && borderFade > 0.0) { riverMask = saturate(i.worldPosRefracted.y - KWS_WaterLevel - 3) * (1 - shorelineMask); float flowSpeed = lerp(0.25, 0.5, riverMask); float3 dynamicWavesFlowNormal = Texture2DSampleFlowmapJumpStochastic(KWS_WaterDynamicWavesFlowMapNormal, sampler_linear_repeat, i.worldPos.xz * 0.05, flowDirectionNormalized * flowSpeed, KWS_ScaledTime * 1 * flowSpeedMultiplier, 5).xzy * 2 - 1; dynamicWavesFlowNormal.z *= -1; dynamicWavesFlowNormal.xz *= RIVER_FLOW_NORMAL_MULTIPLIER; dynamicWavesFlowNormal = lerp(float3(0, 1, 0), dynamicWavesFlowNormal, riverMask * saturate(velocityLength - 0.15)); dynamicWavesNormal = KWS_BlendNormals(dynamicWavesNormal, dynamicWavesFlowNormal); tangentNormal = lerp(KWS_BlendNormals(dynamicWavesNormal, tangentNormal), dynamicWavesNormal, saturate((1-shorelineMask) - 0.2)); } #endif #if defined(KWS_USE_OCEAN_RENDERING) if (KWS_UseOceanFoam) { //return float4(wavesNormalFoam.yyy, 1); foamMask = max(foamMask, oceanFoamMask * surfaceMask * shorelineMask * KWS_Pow3(i.windAttenuation)); } #endif tangentNormal = lerp(float3(0, 1, 0), tangentNormal, surfaceMask * alpha); #ifdef KWS_USE_ZONE_INSTANCE float3 worldNormal = tangentNormal; #else float3 worldNormal = KWS_BlendNormals(tangentNormal, i.worldNormal); #endif //worldNormal = KWS_GetDerivativeNormal(i.worldPosRefracted, _ProjectionParams.x); ///////////////////////////////////////////////////////////// end normal //////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// REFRACTION /////////////////////////////////////////////////////////////////// half3 refraction; float2 refractionUV; //todo surfaceMask > 0.5 #ifdef KWS_USE_REFRACTION_IOR float3 refractionPos = float3(i.worldPos.x, i.worldPosRefracted.y, i.worldPos.z); float riverRefractionMultiplier = lerp(1, 3, saturate(dynamicWavesHeight)); refractionUV = GetRefractedUV_IOR(viewDir, worldNormal, refractionPos, sceneZEye, surfaceDepthZEye, transparent, clamp(waterDepth * riverRefractionMultiplier, 0.1, KWS_MAX_TRANSPARENT)); /* //todo fix alpha float3 refractedWorldPosDepth = GetWorldSpacePositionFromDepth(refractionUV, GetSceneDepth(refractionUV)); waterDepth = i.worldPosRefracted.y - refractedWorldPosDepth.y; waterDepth = lerp(clamp(abs(surfaceDepthZEye - sceneZEye) * 0.1, 0, 10), waterDepth, 1-KWS_Pow10(1-viewDir.y)); refractionUV = GetRefractedUV_IOR(viewDir, worldNormal, refractionPos, sceneZEye, surfaceDepthZEye, transparent, clamp(waterDepth * riverRefractionMultiplier, 0.1, KWS_MAX_TRANSPARENT)); */ #else refractionUV = GetRefractedUV_Simple(screenUV, worldNormal); #endif refractionUV = lerp(screenUV, refractionUV, surfaceMask); refractionUV += waterfallMask * clamp(flowDirectionNormalized * 0.5, -0.25, 0.25) * lerp(1.0, RIVER_FLOW_FRESNEL_MULTIPLIER * 0.5, riverMask) * (1.1-saturate(distanceToCamera * 0.01)) * saturate(waterDepth * 0.5); float refractedSceneZ = GetSceneDepth(refractionUV); float refractedSceneZEye = LinearEyeDepthUniversal(refractedSceneZ); FixRefractionSurfaceLeaking(surfaceDepthZEye, sceneZ, sceneZEye, screenUV, refractedSceneZ, refractedSceneZEye, refractionUV); //todo surfaceMask > 0.5 #ifdef KWS_USE_REFRACTION_DISPERSION refraction = GetSceneColorWithDispersion(refractionUV, KWS_RefractionDispersionStrength); #else refraction = GetSceneColor(refractionUV); #endif //refraction *= float3(0.85, 0.87, 0.9); //return float4(refraction, 1); ///////////////////////////////////////////////////////////// end refraction //////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// CAUSTIC /////////////////////////////////////////// #if defined(KWS_USE_CAUSTIC) float3 refractedWorldPos = GetWorldSpacePositionFromDepth(refractionUV, refractedSceneZ); float2 causticUV = refractedWorldPos.xz; float3 oceanCaustic = 0; float3 zoneCaustic = 0; float zoneCausticFade = KWS_Pow2(borderFade); #if defined(KWS_USE_DYNAMIC_WAVES) || defined(KWS_USE_COLORED_DYNAMIC_WAVES) || defined(KWS_USE_ZONE_INSTANCE) if (isDynamicWavesZone && zoneCausticFade > 0.0) { float causticNoiseMask = GetNoiseMask(causticUV, 2.5, 7); causticNoiseMask = saturate(noiseMask * causticNoiseMask + 0.1 + velocityLength * 0.25); //todo add high quality option /* float3 dynamicWavesMapUVRefracted = GetDynamicWavesMapUV(refractedWorldPos, distanceToCamera); float4 dynamicWavesRefracted = GetDynamicWavesMap(dynamicWavesMapUVRefracted); float2 flowDirectionRefractedNormalized = NormalizeDynamicWavesVelocity(dynamicWavesRefracted.xy); float velocityLengthRefracted = length(dynamicWavesRefracted.xy); */ float2 flowDirectionRefractedNormalized = flowDirectionNormalized; float velocityLengthRefracted = velocityLength; zoneCaustic = GetDynamicWavesZoneCaustic(causticUV, waterDepth, flowDirectionRefractedNormalized, velocityLengthRefracted, flowSpeedMultiplier, causticNoiseMask); } #endif #if defined(KWS_USE_OCEAN_RENDERING) if (zoneCausticFade < 0.95) oceanCaustic = GetOceanCaustic(i.pos.xy, causticUV, waterDepth); #endif float3 finalCaustic = lerp(oceanCaustic.xyz, zoneCaustic.xyz, zoneCausticFade); float depthFadingDistance = saturate(waterDepth * 0.1); finalCaustic *= lerp(saturate(1-saturate((distanceToCamera + 25) * 0.01) + 0.25), 1, saturate(depthFadingDistance)); #ifdef KWS_USE_VOLUMETRIC_LIGHT VolumetricLightAdditionalData volumeData = GetVolumetricLightAdditionalData(screenUV); finalCaustic *= KWS_Pow10(volumeData.SceneDirShadow); #endif refraction.rgb *= 1.0 + finalCaustic; // caustic ~ 0.0–1.0 #endif ///////////////////////////////////////////////////////////// end caustic /////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// UNDERWATER /////////////////////////////////////////////////////////////////// float2 refractedVolumeLightUV = lerp(refractionUV, screenUV, waterfallMask); #if defined(KWS_USE_LOCAL_WATER_ZONES) refractedVolumeLightUV = lerp(refractedVolumeLightUV, screenUV, localZoneDensity); #endif #ifdef KWS_USE_CUSTOM_MESH refractedVolumeLightUV = screenUV; #endif float2 volumeDepth = GetWaterVolumeDepth(screenUV, surfaceDepthZ, refractedSceneZ, 0); half4 volumeLight = GetVolumetricLightWithAbsorbtion(screenUV, refractedVolumeLightUV, transparent, turbidityColor, waterColor, refraction, volumeDepth, exposure, 0); if (surfaceMask < 0.5) return float4(volumeLight.xyz, 1); float depthAngleFix = (surfaceMask < 0.5 || KWS_MeshType == KWS_MESH_TYPE_CUSTOM_MESH) ? 0.25 : saturate(GetWorldSpaceViewDirNorm(i.worldPos - float3(0, KWS_WindSpeed * 0.5, 0)).y); float fade = GetWaterRawFade(i.worldPos, surfaceDepthZEye, refractedSceneZEye, surfaceMask, depthAngleFix); half3 underwaterColor = volumeLight.xyz; float oceanFoam = 0; float advectedFoam = 0; float flowmapFoam = 0; #if defined(KWS_USE_OCEAN_RENDERING) UNITY_BRANCH if(KWS_UseOceanFoam) //todo add KWS_UseOceanFoam keyword { float2 oceanUV = i.worldPos.xz * 0.05 * KWS_FoamTextureScaleMultiplier; float2 dx = ddx(oceanUV); float2 dy = ddy(oceanUV); float4 oceanFoamTex = Tex2DStochastic(KW_FluidsFoamTex, sampler_KW_FluidsFoamTex, oceanUV, dx, dy).xyzw * (1-borderFade); float4 foamChannelMask = saturate(1.0 - abs(KWS_FoamTextureType - float4(0, 1, 2, 3))); float selectedFoamChannel = dot(oceanFoamTex, foamChannelMask); oceanFoam = saturate(saturate(pow(selectedFoamChannel, KWS_FoamTextureContrast) - (1 - sqrt(foamMask)))); } #endif #if defined(KWS_USE_DYNAMIC_WAVES) || defined(KWS_USE_COLORED_DYNAMIC_WAVES) || defined(KWS_USE_ZONE_INSTANCE) UNITY_BRANCH if (useDynamicWavesFoamTexture) { float foamTextureType = foamData.x; float foamTextureContrast = foamData.y; float2 foamTextureScale = foamData.zw; float4 foamChannelMask = saturate(1.0 - abs(foamTextureType - float4(0, 1, 2, 3))); UNITY_BRANCH if (useAdvectedUV > 0) { float4 advectedFoam0 = KW_FluidsFoamTex.Sample(sampler_KW_FluidsFoamTex, advectedUV.xy * 20 * foamTextureScale); float4 advectedFoam1 = KW_FluidsFoamTex.Sample(sampler_KW_FluidsFoamTex, advectedUV.zw * 20 * foamTextureScale); float selectedFoamChannel0 = dot(advectedFoam0, foamChannelMask); float selectedFoamChannel1 = dot(advectedFoam1, foamChannelMask); float weight0 = sin(frac(KWS_ScaledTime / KWS_ADVECTED_UV_REPEAT_TIME) * 3.1415); float weight1 = sin(frac((KWS_ScaledTime + KWS_ADVECTED_UV_REPEAT_TIME * 0.5) / KWS_ADVECTED_UV_REPEAT_TIME) * 3.1415); weight0 = sqrt(weight0); weight1 = sqrt(weight1); advectedFoam = max(selectedFoamChannel0 * weight0, selectedFoamChannel1 * weight1) * borderFade; advectedFoam = saturate(saturate(pow(advectedFoam, foamTextureContrast) - (1 - sqrt(foamMask)))); } else { float flowSpeed = lerp(0.25, 0.5, riverMask); float4 flowmapFoamTex = Texture2DSampleFlowmapJump(KW_FluidsFoamTex, sampler_KW_FluidsFoamTex, i.worldPos.xz * 0.05, flowDirectionNormalized * flowSpeed * 1.0, KWS_ScaledTime * 1 * flowSpeedMultiplier, foamTextureScale.x).xyzw * borderFade; float selectedFoamChannel = dot(flowmapFoamTex, foamChannelMask); flowmapFoam = saturate(saturate(pow(selectedFoamChannel, foamTextureContrast) - (1 - sqrt(foamMask)))); } } #endif #if defined(KWS_USE_DYNAMIC_WAVES) || defined(KWS_USE_COLORED_DYNAMIC_WAVES) || defined(KWS_USE_ZONE_INSTANCE) || defined(KWS_USE_OCEAN_RENDERING) UNITY_BRANCH if (useDynamicWavesFoamTexture || KWS_UseOceanFoam) { float3 surfaceColor = GetVolumetricSurfaceLight(screenUV); float3 foamColor = 0; foamColor += advectedFoam * dynamicWavesFoamAlpha; foamColor += flowmapFoam * dynamicWavesFoamAlpha; foamColor += oceanFoam; foamColor += foamMask * 0.25 * KWS_TurbidityColor * borderFade * saturate(KWS_MAX_TRANSPARENT_INVERSE * transparent * 3); foamColor = saturate(foamColor) * KWS_Pow3(alpha); foamColor *= clamp(surfaceColor, 0, 1.15); foamColor *= lerp(1, colorData.rgb, saturate(colorData.a * 1.35)); underwaterColor = lerp(underwaterColor + foamColor, foamColor, colorData.a); } #endif float3 subsurfaceScatteringColor = ComputeSSS(screenUV, GetWaterSSS(screenUV), underwaterColor, volumeLight.a, transparent); underwaterColor += subsurfaceScatteringColor * 5; //return float4(underwaterColor.xyz, 1); ///////////////////////////////////////////////////////////// end underwater //////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// REFLECTION //////////////////////////////////////////////////////////////////////////////////////////////////////// float3 reflDir = reflect(-viewDir, worldNormal); reflDir.y *= sign(dot(reflDir, float3(0, 1, 0))); float3 reflection = 0; #if defined(KWS_SSR_REFLECTION) || defined(KWS_USE_PLANAR_REFLECTION) float2 refl_uv = GetScreenSpaceReflectionUV(reflDir, screenUV + tangentNormal.xz * 0.5); #endif #ifdef KWS_USE_PLANAR_REFLECTION reflection = GetPlanarReflectionWithClipOffset(refl_uv) * exposure; #else #ifdef KWS_USE_REFLECTION_PROBES reflection = KWS_GetReflectionProbeEnv(screenUV, surfaceDepthZEye, i.worldPosRefracted, reflDir, KWS_SkyLodRelativeToWind, exposure); #else reflection = KWS_GetSkyColor(reflDir, KWS_SkyLodRelativeToWind, exposure); #endif #endif #ifdef KWS_SSR_REFLECTION float4 ssrReflection = GetScreenSpaceReflectionWithStretchingMask(refl_uv, i.worldPosRefracted); float inverseReflectionFix = 1 - saturate(dot(reflDir, float3(0, 1, 0))); inverseReflectionFix = lerp(1, KWS_Pow5(inverseReflectionFix), saturate((KWS_WindSpeed - 2.5) * 0.25)); inverseReflectionFix = lerp(inverseReflectionFix, 1, riverMask); ssrReflection.a = lerp(0, ssrReflection.a, inverseReflectionFix); reflection = lerp(reflection, ssrReflection.rgb, ssrReflection.a); #endif reflection *= surfaceMask * (1 - waterfallMask); //reflection = ApplyShorelineWavesReflectionFix(reflDir, reflection, underwaterColor); ///////////////////////////////////////////////////////////// end reflection //////////////////////////////////////////////////////////////////////////////////////////////////////// half waterFresnel = ComputeWaterFresnel(worldNormal, viewDir); waterFresnel *= lerp(1.0, RIVER_FLOW_FRESNEL_MULTIPLIER, riverMask); waterFresnel *= surfaceMask * (1 - waterfallMask); half3 finalColor = lerp(underwaterColor, reflection, waterFresnel); #ifdef KWS_REFLECT_SUN float3 sunReflection = ComputeSunlight(worldNormal, viewDir, GetMainLightDir(), GetMainLightColor(exposure), volumeLight.a, surfaceDepthZEye, _ProjectionParams.z, transparent); float sunFadeFactor = saturate(abs(sceneZEye - surfaceDepthZEye)); sunFadeFactor = KWS_Pow5(sunFadeFactor) * saturate(1 - waterfallMask * 2); finalColor += sunReflection * saturate((1 - foamMask) * sunFadeFactor); #endif half3 fogColor; half3 fogOpacity; #ifdef KWS_HDRP GetInternalFogVariables(i.pos, GetWorldSpaceViewDirNorm(i.worldPos), LinearEyeDepthUniversal(i.pos.z), i.worldPos, fogColor, fogOpacity); #else GetInternalFogVariables(LinearEyeDepthUniversal(i.pos.z), fogColor, fogOpacity); #endif finalColor.xyz = ComputeInternalFog(finalColor.xyz , fogColor, fogOpacity); finalColor.xyz = ComputeThirdPartyFog(finalColor.xyz , i.worldPos, i.pos.xy / _ScreenParams.xy, i.pos.z); finalColor += srpBatcherFix; alpha *= saturate(waterDepth * 5); return float4(finalColor, alpha); } struct WaterFragmentOutput { half4 pass1 : SV_Target0; half2 pass2 : SV_Target1; }; WaterFragmentOutput fragDepth(v2fDepth i, float facing : VFACE) { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); WaterFragmentOutput o = (WaterFragmentOutput)0; float facingColor = 0.75 - facing * 0.25; float2 screenUV = i.screenPos.xy / i.screenPos.w; float z = i.screenPos.z / i.screenPos.w; float sceneDepth = GetSceneDepth(screenUV); half surfaceMask = max(i.surfaceMask.x >= 0.999, i.surfaceMask.x <= 0.0001); float distanceToCamera = GetWorldToCameraDistance(i.worldPos); #ifdef KWS_PRE_PASS_BACK_FACE float mask = i.surfaceMask.x < 0.9999 ? 0.1 : 1; #else float mask = facing > 0 ? 0.25 : 0.75; if (surfaceMask < 0.5) { mask = facing > 0.0 ? 0.1 : 1; } #endif float2 flowDirection = 0; bool isDynamicWavesZone = false; float3 dynamicWavesNormal = float3(0, 1, 0); float dynamicWavesNormalMask = 0; float borderFade = 0; float flowSpeedMultiplier = 1; float velocityLength = 0; float shorelineMask = 1; float riverMask = 0; #if defined(KWS_USE_DYNAMIC_WAVES) || defined(KWS_USE_COLORED_DYNAMIC_WAVES) float3 dynamicWavesMapUV = GetDynamicWavesMapUV(i.worldPosRefracted, distanceToCamera); isDynamicWavesZone = !IsOutsideUvBorders(dynamicWavesMapUV.xy); if (isDynamicWavesZone) { float4 dynamicWaves = GetDynamicWavesMapBicubic(dynamicWavesMapUV); DynamicWavesAdditionalData additionalData = GetDynamicWavesAdditionalMapBicubic(dynamicWavesMapUV); dynamicWavesNormal = GetDynamicWavesNormalMap(dynamicWavesMapUV); float waterfallThreshold = GetDynamicWavesWaterfallTreshold(dynamicWavesNormal); dynamicWaves.xy = lerp(dynamicWaves.xy, dynamicWaves.xy * 0.2, waterfallThreshold); borderFade = additionalData.zoneFade; flowDirection = dynamicWaves.xy * borderFade; shorelineMask = max(additionalData.shorelineMask, 1-borderFade); velocityLength = length(dynamicWaves.xy) * borderFade; ZoneData zone = KWS_ZoneData[additionalData.zoneID]; flowSpeedMultiplier = zone.flowSpeedMultiplier; } #endif //float alpha = lerp(1-KWS_Pow5(1-borderFade), 1, KWS_RenderOcean); //if (alpha < 0.001) discard; float2 flowDirectionNormalized = NormalizeDynamicWavesVelocity(flowDirection); ///////////////////////////////////////////////////////////// NORMAL //////////////////////////////////////////////////////////////////////////////////////////////////////// float3 tangentNormal = float3(0, 1, 0); #if defined(KWS_USE_OCEAN_RENDERING) float3 wavesNormalFoam = GetFftWavesNormalFoam(i.worldPos, i.windAttenuation); tangentNormal = float3(wavesNormalFoam.x, 1, wavesNormalFoam.z); tangentNormal = lerp(float3(0, 1, 0), tangentNormal, any(fwidth(i.worldPos.xz))); //fix horizontal flickering #endif float3 tangentNormalScatter = tangentNormal; #if defined(KWS_USE_DYNAMIC_WAVES) || defined(KWS_USE_COLORED_DYNAMIC_WAVES) || defined(KWS_USE_ZONE_INSTANCE) if (isDynamicWavesZone && borderFade > 0.0) { riverMask = saturate(i.worldPosRefracted.y - KWS_WaterLevel - 3) * (1 - shorelineMask); float3 dynamicWavesFlowNormal = Texture2DSampleFlowmapJump(KWS_WaterDynamicWavesFlowMapNormal, sampler_linear_repeat, i.worldPos.xz * 0.05, flowDirectionNormalized * 0.5, KWS_ScaledTime * 1.0 * flowSpeedMultiplier, 5).xzy * 2 - 1; dynamicWavesFlowNormal.z *= -1; dynamicWavesFlowNormal.xz *= RIVER_FLOW_NORMAL_MULTIPLIER * 0.5; dynamicWavesFlowNormal = lerp(float3(0, 1, 0), dynamicWavesFlowNormal, riverMask * saturate(velocityLength - 0.15)); dynamicWavesNormal = KWS_BlendNormals(dynamicWavesNormal, dynamicWavesFlowNormal); tangentNormal = lerp(KWS_BlendNormals(dynamicWavesNormal, tangentNormal), dynamicWavesNormal, saturate((1-shorelineMask) - 0.2)); } #endif //half surfaceMask = max(i.surfaceMask.x >= 0.999, i.surfaceMask.x <= 0.0001); tangentNormal = lerp(float3(0, 1, 0), tangentNormal, surfaceMask); float3 worldNormal = KWS_BlendNormals(tangentNormal, i.worldNormal); #if defined(KWS_USE_DYNAMIC_WAVES) || defined(KWS_USE_COLORED_DYNAMIC_WAVES) if (isDynamicWavesZone) { float underwaterRefractionFix = 1 - saturate(1.25 * saturate(1 - dot(dynamicWavesNormal, float3(0, 1, 0)))); worldNormal *= underwaterRefractionFix; } #endif float transparent = KWS_Transparent; #if defined(KWS_USE_LOCAL_WATER_ZONES) UNITY_LOOP for (uint zoneIdx = 0; zoneIdx < KWS_WaterLocalZonesCount; zoneIdx++) { LocalZoneData zone = KWS_ZoneData_LocalZone[zoneIdx]; float2 distanceToBox = abs(mul(i.worldPos.xz - zone.center.xz, zone.rotationMatrix)) / zone.halfSize.xz; float distanceToBorder = max(distanceToBox.x, distanceToBox.y); float zoneMinHeight = zone.center.y - zone.halfSize.y; if (distanceToBorder < 1.1 && i.worldPosRefracted.y < zoneMinHeight && GetCameraAbsolutePosition().y > i.worldPos.y) discard; } #endif float3 viewDir = GetWorldSpaceViewDirNorm(i.worldPosRefracted); float3 lightDir = GetMainLightDir(); float dotVal = dot(lightDir, float3(0, 1, 0)); float sunAngleAttenuation = smoothstep(-0.1, 1.0, dotVal); float3 refractedVector = normalize(refract(-viewDir, tangentNormalScatter, 0.66)); float scattering = pow(saturate(dot(refractedVector, lightDir)), 16); float sss = saturate(scattering * sunAngleAttenuation * 5000); half tensionMask = 0; #ifdef KWS_USE_HALF_LINE_TENSION tensionMask = abs(i.localHeightAndTensionMask.y) * KWS_InstancingWaterScale.y * lerp(40, 10, KWS_UnderwaterHalfLineTensionScale); if (tensionMask >= 0.99) tensionMask = ((1.2 - tensionMask) * 5); if (i.surfaceMask.x > 0.9999 || facing < 0 || z <= sceneDepth) tensionMask = 0; tensionMask *= 1 - saturate(distanceToCamera * 0.1); #endif o.pass1 = half4(transparent / 100.0, mask, sss, tensionMask); o.pass2 = worldNormal.xz; return o; } #endif