You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
640 lines
22 KiB
640 lines
22 KiB
#ifndef SAMPLE_WATER_SURFACE_H
|
|
#define SAMPLE_WATER_SURFACE_H
|
|
|
|
#if !defined(IGNORE_WATER_DEFORMATION)
|
|
#define SUPPORT_WATER_DEFORMATION
|
|
#endif
|
|
|
|
// Number of bands based on the multi compile
|
|
#if defined(WATER_TWO_BANDS)
|
|
#define NUM_WATER_BANDS 2
|
|
#elif defined(WATER_THREE_BANDS)
|
|
#define NUM_WATER_BANDS 3
|
|
#else
|
|
#define NUM_WATER_BANDS 1
|
|
#endif
|
|
|
|
#define WATER_SYSTEM_CHOPPINESS 2.25
|
|
#define WATER_DEEP_FOAM_JACOBIAN_OVER_ESTIMATION 1.03
|
|
#define SURFACE_FOAM_BRIGHTNESS 1.0
|
|
#define SCATTERING_FOAM_BRIGHTNESS 2.0
|
|
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/NormalSurfaceGradient.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Water/WaterSystemDef.cs.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/WaterCurrentUtilities.hlsl"
|
|
|
|
// Water simulation data
|
|
Texture2DArray<float4> _WaterDisplacementBuffer;
|
|
Texture2DArray<float4> _WaterAdditionalDataBuffer;
|
|
|
|
// Space transform overrides
|
|
float3 TransformObjectToWorld_Water(float3 positionOS)
|
|
{
|
|
return mul(ApplyCameraTranslationToMatrix(_WaterSurfaceTransform), float4(positionOS, 1.0)).xyz;
|
|
}
|
|
|
|
float3 TransformObjectToWorldDir_Water(float3 dirOS)
|
|
{
|
|
return mul((float3x3)ApplyCameraTranslationToMatrix(_WaterSurfaceTransform), dirOS);
|
|
}
|
|
|
|
float2 RotateUV(float2 uv)
|
|
{
|
|
float2 axis1 = float2(_WaterSurfaceTransform[0].x, _WaterSurfaceTransform[2].x);
|
|
float2 axis2 = float2(-axis1.y, axis1.x);
|
|
return float2(dot(uv, axis1), dot(uv, axis2));
|
|
}
|
|
|
|
// Water Mask
|
|
TEXTURE2D(_WaterMask);
|
|
SAMPLER(sampler_WaterMask);
|
|
|
|
float3 EvaluateWaterMask(float3 positionOS)
|
|
{
|
|
float2 maskUV = (positionOS.xz - _WaterMaskOffset) * _WaterMaskScale + 0.5f;
|
|
float3 waterMask = SAMPLE_TEX2D(_WaterMask, sampler_WaterMask, maskUV).xyz;
|
|
|
|
return _WaterMaskRemap.xxx + waterMask * _WaterMaskRemap.yyy;
|
|
}
|
|
|
|
// Deformation region
|
|
Texture2D<float> _WaterDeformationBuffer;
|
|
Texture2D<float2> _WaterDeformationSGBuffer;
|
|
|
|
float2 EvaluateDeformationUV(float3 transformedPositionAWS)
|
|
{
|
|
return RotateUV(transformedPositionAWS.xz - _DeformationRegionOffset) * _DeformationRegionScale + 0.5f;
|
|
}
|
|
|
|
float EvaluateWaterDeformation(float3 positionAWS)
|
|
{
|
|
float2 deformationUV = EvaluateDeformationUV(positionAWS);
|
|
return SAMPLE_TEXTURE2D_LOD(_WaterDeformationBuffer, s_linear_clamp_sampler, deformationUV, 0);
|
|
}
|
|
|
|
// Band data
|
|
float4 GetBandPatchData(int bandIdx)
|
|
{
|
|
switch (bandIdx)
|
|
{
|
|
case 0:
|
|
return _Band0_ScaleOffset_AmplitudeMultiplier;
|
|
case 1:
|
|
return _Band1_ScaleOffset_AmplitudeMultiplier;
|
|
default:
|
|
return _Band2_ScaleOffset_AmplitudeMultiplier;
|
|
}
|
|
}
|
|
|
|
|
|
float GetPatchAmplitudeMultiplier(int bandIdx)
|
|
{
|
|
return GetBandPatchData(bandIdx).w;
|
|
}
|
|
|
|
// Attenuation is: lerp(data, 0, saturate((distance - fadeStart) / fadeDistance))
|
|
// = data * saturate(1 - distance / fadeDistance + fadeStart / fadeDistance)
|
|
// => FadeA = -1 / fadeDistance FadeB = 1 + fadeStart / fadeDistance
|
|
float DistanceFade(float distanceToCamera, int bandIdx)
|
|
{
|
|
#ifndef IGNORE_WATER_FADE
|
|
float2 patchFade;
|
|
switch (bandIdx)
|
|
{
|
|
case 0:
|
|
patchFade = _Band0_Fade;
|
|
break;
|
|
case 1:
|
|
patchFade = _Band1_Fade;
|
|
break;
|
|
default:
|
|
patchFade = _Band2_Fade;
|
|
break;
|
|
}
|
|
|
|
float fade = saturate(distanceToCamera * patchFade.x + patchFade.y);
|
|
|
|
// perform a remap from [0, 1] to [0, 1] on the fade value to make it smoother
|
|
return Smoothstep01(fade * fade);
|
|
#else
|
|
return 1.0f;
|
|
#endif
|
|
}
|
|
|
|
// Band UV
|
|
struct PatchSimData
|
|
{
|
|
float2 uv;
|
|
float blend;
|
|
float4 swizzle;
|
|
};
|
|
|
|
struct WaterSimCoord
|
|
{
|
|
PatchSimData data[NUM_WATER_BANDS];
|
|
};
|
|
|
|
float2 TransformWaterUV(float2 uv, int bandIdx)
|
|
{
|
|
float3 scaleOffset = GetBandPatchData(bandIdx).xyz;
|
|
return uv * scaleOffset.x - scaleOffset.yz;
|
|
}
|
|
|
|
void ComputeWaterUVs(float2 uv, out WaterSimCoord simC)
|
|
{
|
|
UNITY_UNROLL for (int bandIdx = 0; bandIdx < NUM_WATER_BANDS; ++bandIdx)
|
|
{
|
|
simC.data[bandIdx].uv = TransformWaterUV(uv, bandIdx);
|
|
simC.data[bandIdx].blend = 1.0;
|
|
simC.data[bandIdx].swizzle = float4(1, 0, 0, 1);
|
|
}
|
|
}
|
|
|
|
void AggregateWaterSimCoords(in WaterSimCoord waterCoord[2],
|
|
in CurrentData currentData[2], int firstPass,
|
|
out WaterSimCoord simCoords)
|
|
{
|
|
// Grab the sector data for both groups
|
|
float4 dir[2];
|
|
dir[0] = _WaterSectorData[int2(currentData[0].quadrant + SECTOR_DATA_OTHER_OFFSET, 0)];
|
|
dir[1] = _WaterSectorData[int2(currentData[1].quadrant + SECTOR_DATA_OTHER_OFFSET, 0)];
|
|
|
|
// Process the bands that we have
|
|
UNITY_UNROLL for (int bandIdx = 0; bandIdx < NUM_WATER_BANDS; ++bandIdx)
|
|
{
|
|
int group = _PatchGroup[bandIdx];
|
|
float4 packedDir = dir[group];
|
|
simCoords.data[bandIdx].uv = waterCoord[group].data[bandIdx].uv;
|
|
if (firstPass)
|
|
{
|
|
simCoords.data[bandIdx].blend = 1.0 - currentData[group].proportion;
|
|
simCoords.data[bandIdx].swizzle = float4(packedDir.xy, -packedDir.y, packedDir.x);
|
|
}
|
|
else
|
|
{
|
|
simCoords.data[bandIdx].blend = currentData[group].proportion;
|
|
simCoords.data[bandIdx].swizzle = float4(packedDir.zw, -packedDir.w, packedDir.z);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// Sample displacement
|
|
float3 SampleDisplacement_VS(float2 uv, float bandIdx)
|
|
{
|
|
return SAMPLE_TEXTURE2D_ARRAY_LOD(_WaterDisplacementBuffer, s_linear_repeat_sampler, uv, bandIdx, 0).xyz;
|
|
}
|
|
|
|
void SampleSimulation_VS(WaterSimCoord waterCoord, float3 waterMask, float distanceToCamera,
|
|
out float3 totalDisplacement, out float lowFrequencyHeight)
|
|
{
|
|
// Initialize the output
|
|
totalDisplacement = 0.0;
|
|
lowFrequencyHeight = 0.0;
|
|
|
|
// Loop through the bands
|
|
UNITY_UNROLL for (int bandIdx = 0; bandIdx < NUM_WATER_BANDS; ++bandIdx)
|
|
{
|
|
float distanceFade = DistanceFade(distanceToCamera, bandIdx);
|
|
if (distanceFade == 0.0f) continue;
|
|
|
|
// Grab the data for the current band
|
|
PatchSimData currentData = waterCoord.data[bandIdx];
|
|
|
|
// Read the raw simulation data
|
|
float3 rawDisplacement = SampleDisplacement_VS(currentData.uv, (float)bandIdx);
|
|
|
|
// Apply the global attenuations
|
|
rawDisplacement *= GetPatchAmplitudeMultiplier(bandIdx) * waterMask[bandIdx] * currentData.blend;
|
|
|
|
// Apply the camera distance attenuation
|
|
rawDisplacement *= distanceFade;
|
|
|
|
// Swizzle the displacement and add it
|
|
totalDisplacement += float3(rawDisplacement.x, dot(rawDisplacement.yz, currentData.swizzle.xy), dot(rawDisplacement.yz, currentData.swizzle.zw));
|
|
|
|
// Contribute to the low frequency height
|
|
lowFrequencyHeight += bandIdx < 2 ? rawDisplacement.x : 0;
|
|
}
|
|
}
|
|
|
|
// Evaluate Water displacement
|
|
|
|
struct WaterDisplacementData
|
|
{
|
|
float3 displacement;
|
|
float lowFrequencyHeight;
|
|
};
|
|
|
|
void EvaluateWaterDisplacement(float3 positionOS, out WaterDisplacementData displacementData)
|
|
{
|
|
// Evaluate the pre-displaced absolute position
|
|
float3 positionRWS = TransformObjectToWorld_Water(positionOS);
|
|
// Evaluate the distance to the camera
|
|
float distanceToCamera = length(positionRWS);
|
|
|
|
// Attenuate using the water mask
|
|
float3 waterMask = EvaluateWaterMask(positionOS);
|
|
|
|
float3 totalDisplacement = 0.0;
|
|
float lowFrequencyHeight = 0.0;
|
|
|
|
#if !defined(WATER_LOCAL_CURRENT)
|
|
// Compute the simulation coordinates
|
|
WaterSimCoord waterCoord;
|
|
ComputeWaterUVs(positionOS.xz, waterCoord);
|
|
|
|
// Sample the simulation
|
|
SampleSimulation_VS(waterCoord, waterMask, distanceToCamera, totalDisplacement, lowFrequencyHeight);
|
|
#else
|
|
// Read the current data
|
|
CurrentData currentData[2];
|
|
EvaluateGroup0CurrentData(positionOS.xz, currentData[0]);
|
|
EvaluateGroup1CurrentData(positionOS.xz, currentData[1]);
|
|
|
|
// Compute the simulation coordinates
|
|
float4 tapCoords[2];
|
|
SwizzleSamplingCoordinates(positionOS.xz, currentData[0].quadrant, tapCoords[0]);
|
|
SwizzleSamplingCoordinates(positionOS.xz, currentData[1].quadrant, tapCoords[1]);
|
|
|
|
// Compute the 2 simulation coordinates
|
|
WaterSimCoord waterCoord[2];
|
|
WaterSimCoord finalCoords;
|
|
|
|
// Sample the simulation (first time)
|
|
ComputeWaterUVs(tapCoords[0].xy, waterCoord[0]);
|
|
ComputeWaterUVs(tapCoords[1].xy, waterCoord[1]);
|
|
AggregateWaterSimCoords(waterCoord, currentData, true, finalCoords);
|
|
|
|
float3 totalDisplacement0 = 0.0;
|
|
float lowFrequencyHeight0 = 0.0;
|
|
SampleSimulation_VS(finalCoords, waterMask, distanceToCamera, totalDisplacement0, lowFrequencyHeight0);
|
|
|
|
// Sample the simulation (second time)
|
|
ComputeWaterUVs(tapCoords[0].zw, waterCoord[0]);
|
|
ComputeWaterUVs(tapCoords[1].zw, waterCoord[1]);
|
|
AggregateWaterSimCoords(waterCoord, currentData, false, finalCoords);
|
|
|
|
float3 totalDisplacement1 = 0.0;
|
|
float lowFrequencyHeight1 = 0.0;
|
|
SampleSimulation_VS(finalCoords, waterMask, distanceToCamera, totalDisplacement1, lowFrequencyHeight1);
|
|
|
|
// Combine both contributions
|
|
totalDisplacement = totalDisplacement0 + totalDisplacement1;
|
|
lowFrequencyHeight = lowFrequencyHeight0 + lowFrequencyHeight1;
|
|
#endif
|
|
|
|
// We apply the choppiness to all bands
|
|
totalDisplacement.yz *= WATER_SYSTEM_CHOPPINESS;
|
|
|
|
// The vertical displacement is stored in the X channel and the XZ displacement in the YZ channel
|
|
displacementData.lowFrequencyHeight = lowFrequencyHeight;
|
|
displacementData.displacement = float3(-totalDisplacement.y, totalDisplacement.x, -totalDisplacement.z);
|
|
|
|
#if defined(SUPPORT_WATER_DEFORMATION)
|
|
// Apply the deformation data
|
|
float verticalDeformation = EvaluateWaterDeformation(GetAbsolutePositionWS(positionRWS) + displacementData.displacement);
|
|
displacementData.displacement += float3(0.0, verticalDeformation, 0.0);
|
|
displacementData.lowFrequencyHeight += verticalDeformation;
|
|
#endif
|
|
|
|
#if defined(SHADER_STAGE_VERTEX) && !defined(WATER_DISPLACEMENT)
|
|
ZERO_INITIALIZE(WaterDisplacementData, displacementData);
|
|
#endif
|
|
|
|
// Remap lf height to [0, 1]
|
|
displacementData.lowFrequencyHeight /= _ScatteringWaveHeight;
|
|
displacementData.lowFrequencyHeight = saturate(displacementData.lowFrequencyHeight * 0.5 + 0.5);
|
|
}
|
|
|
|
// Foam
|
|
Texture2D<float2> _WaterFoamBuffer;
|
|
TEXTURE2D(_SimulationFoamMask);
|
|
SAMPLER(sampler_SimulationFoamMask);
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/FoamUtilities.hlsl"
|
|
|
|
// UV to sample the foam mask
|
|
float2 EvaluateFoamMaskUV(float2 foamUV)
|
|
{
|
|
return foamUV * _SimulationFoamMaskScale - _SimulationFoamMaskOffset * _SimulationFoamMaskScale + 0.5f;
|
|
}
|
|
|
|
// UV to sample the foam simulation
|
|
float2 EvaluateFoamUV(float3 transformedPositionAWS)
|
|
{
|
|
return RotateUV(transformedPositionAWS.xz - _FoamRegionOffset) * _FoamRegionScale + 0.5f;
|
|
}
|
|
|
|
float EvaluateFoam(float jacobian, float foamAmount)
|
|
{
|
|
return saturate(-jacobian + foamAmount);
|
|
}
|
|
|
|
float EvaluateFoamMask(float3 positionOS)
|
|
{
|
|
float2 maskUV = (positionOS.xz - _SimulationFoamMaskOffset) * _SimulationFoamMaskScale + 0.5f;
|
|
float foamMask = SAMPLE_TEX2D(_SimulationFoamMask, sampler_SimulationFoamMask, maskUV).x;
|
|
|
|
return foamMask * _SimulationFoamIntensity;
|
|
}
|
|
|
|
// Evaluate additional data
|
|
|
|
struct WaterAdditionalData
|
|
{
|
|
float3 normalWS;
|
|
float3 lowFrequencyNormalWS;
|
|
float surfaceFoam;
|
|
float deepFoam;
|
|
};
|
|
|
|
#if !defined(WATER_SIMULATION)
|
|
float4 SampleAdditionalData(float2 uv, float bandIdx, float4 texSize)
|
|
{
|
|
#ifdef IGNORE_HQ_NORMAL_SAMPLE
|
|
return SAMPLE_TEXTURE2D_ARRAY_LOD(_WaterAdditionalDataBuffer, s_linear_repeat_sampler, uv, bandIdx, 0);
|
|
#else
|
|
//if (bandIdx < NUM_WATER_BANDS - 1)
|
|
// return SAMPLE_TEXTURE2D_ARRAY(_WaterAdditionalDataBuffer, s_linear_repeat_sampler, uv, bandIdx);
|
|
//else
|
|
// return SampleTexture2DArrayBicubic(TEXTURE2D_ARRAY_ARGS(_WaterAdditionalDataBuffer, s_linear_repeat_sampler), uv, bandIdx, texSize);
|
|
return SampleTexture2DArrayBicubic(TEXTURE2D_ARRAY_ARGS(_WaterAdditionalDataBuffer, s_linear_repeat_sampler), uv, bandIdx, texSize);
|
|
#endif
|
|
}
|
|
|
|
void SampleSimulation_PS(WaterSimCoord waterCoord, float3 waterMask, float distanceToCamera, float4 texSize,
|
|
out float2 surfGrdt, out float2 lfSurfGrdt, out float jcbSurface, out float jcbDeep)
|
|
{
|
|
// Initialize the outputs
|
|
surfGrdt = 0.0;
|
|
lfSurfGrdt = 0.0;
|
|
jcbSurface = 0.0;
|
|
jcbDeep = 0.0;
|
|
|
|
// Loop through the bands
|
|
UNITY_UNROLL for (int bandIdx = NUM_WATER_BANDS-1; bandIdx >= 0; --bandIdx)
|
|
{
|
|
// Grab the data for the current band
|
|
PatchSimData currentData = waterCoord.data[bandIdx];
|
|
|
|
// Read the raw additional data
|
|
float4 additionalData = SampleAdditionalData(currentData.uv, bandIdx, texSize);
|
|
additionalData.w = additionalData.z; // currently they are the same (see kernel EvaluateNormalsJacobian)
|
|
|
|
// Compute the camera distance attenuation and water mask
|
|
float fade = DistanceFade(distanceToCamera, bandIdx) * waterMask[bandIdx];
|
|
|
|
// Add the jacobian contribution
|
|
// This cannot be easily faded like displacement, but each band roughly has a maximum jacobian of 4
|
|
// This is not accurate, empirically gives good enough results
|
|
jcbSurface += currentData.blend * lerp(4.0f, additionalData.z, fade);
|
|
jcbDeep += currentData.blend * lerp(4.0f * WATER_DEEP_FOAM_JACOBIAN_OVER_ESTIMATION, additionalData.w, fade);
|
|
|
|
if (fade == 0.0f) continue;
|
|
additionalData.xy *= currentData.blend * fade;
|
|
|
|
// Swizzle the displacement
|
|
additionalData.xy = float2(dot(additionalData.xy, currentData.swizzle.xy), dot(additionalData.xy, currentData.swizzle.zw));
|
|
|
|
// Evaluate the surface gradient
|
|
surfGrdt += additionalData.xy;
|
|
|
|
// Contribute to the low frequency height
|
|
lfSurfGrdt += bandIdx < 2 ? additionalData.xy : 0;
|
|
}
|
|
}
|
|
|
|
void EvaluateWaterAdditionalData(float3 positionOS, float3 transformedPosition, float3 meshNormalOS, out WaterAdditionalData waterAdditionalData)
|
|
{
|
|
ZERO_INITIALIZE(WaterAdditionalData, waterAdditionalData);
|
|
if (_GridSize.x < 0)
|
|
return;
|
|
|
|
// Evaluate the pre-displaced absolute position
|
|
float3 positionRWS = TransformObjectToWorld_Water(positionOS);
|
|
// Evaluate the distance to the camera
|
|
float distanceToCamera = length(positionRWS);
|
|
// Get the world space transformed postion
|
|
float3 transformedAWS = GetAbsolutePositionWS(transformedPosition);
|
|
|
|
// Compute the texture size param for the filtering
|
|
float4 texSize = 0.0;
|
|
texSize.xy = _BandResolution;
|
|
texSize.zw = 1.0f / _BandResolution;
|
|
|
|
// Attenuate using the water mask
|
|
float3 waterMask = EvaluateWaterMask(positionOS);
|
|
|
|
// Initialize the surface gradients
|
|
float2 surfaceGradient = 0.0;
|
|
float2 lFSurfaceGradient = 0.0;
|
|
float jacobianSurface = 0.0;
|
|
float jacobianDeep = 0.0;
|
|
|
|
#ifdef WATER_DISPLACEMENT
|
|
#if !defined(WATER_LOCAL_CURRENT)
|
|
// Sample the simulation
|
|
WaterSimCoord waterCoord;
|
|
ComputeWaterUVs(positionOS.xz, waterCoord);
|
|
SampleSimulation_PS(waterCoord, waterMask, distanceToCamera, texSize,
|
|
surfaceGradient, lFSurfaceGradient, jacobianSurface, jacobianDeep);
|
|
#else
|
|
// Read the current data
|
|
CurrentData currentData[2];
|
|
EvaluateGroup0CurrentData(positionOS.xz, currentData[0]);
|
|
EvaluateGroup1CurrentData(positionOS.xz, currentData[1]);
|
|
|
|
// Compute the simulation coordinates
|
|
float4 tapCoords[2];
|
|
SwizzleSamplingCoordinates(positionOS.xz, currentData[0].quadrant, tapCoords[0]);
|
|
SwizzleSamplingCoordinates(positionOS.xz, currentData[1].quadrant, tapCoords[1]);
|
|
|
|
// Compute the 2 simulation coordinates
|
|
WaterSimCoord waterCoord[2];
|
|
WaterSimCoord finalCoords;
|
|
|
|
// Sample the simulation (first time)
|
|
ComputeWaterUVs(tapCoords[0].xy, waterCoord[0]);
|
|
ComputeWaterUVs(tapCoords[1].xy, waterCoord[1]);
|
|
AggregateWaterSimCoords(waterCoord, currentData, true, finalCoords);
|
|
|
|
float2 surfaceGradient0 = 0.0;
|
|
float2 lowFrequencySurfaceGradient0 = 0.0;
|
|
float jacobianSurface0 = 0.0;
|
|
float jacobianDeep0 = 0.0;
|
|
SampleSimulation_PS(finalCoords, waterMask, distanceToCamera, texSize,
|
|
surfaceGradient0, lowFrequencySurfaceGradient0, jacobianSurface0, jacobianDeep0);
|
|
|
|
// Sample the simulation (second time)
|
|
ComputeWaterUVs(tapCoords[0].zw, waterCoord[0]);
|
|
ComputeWaterUVs(tapCoords[1].zw, waterCoord[1]);
|
|
AggregateWaterSimCoords(waterCoord, currentData, false, finalCoords);
|
|
|
|
float2 surfaceGradient1 = 0.0;
|
|
float2 lowFrequencySurfaceGradient1 = 0.0;
|
|
float jacobianSurface1 = 0.0;
|
|
float jacobianDeep1 = 0.0;
|
|
SampleSimulation_PS(finalCoords, waterMask, distanceToCamera, texSize,
|
|
surfaceGradient1, lowFrequencySurfaceGradient1, jacobianSurface1, jacobianDeep1);
|
|
|
|
// Combine both contributions
|
|
surfaceGradient = surfaceGradient0 + surfaceGradient1;
|
|
lFSurfaceGradient = lowFrequencySurfaceGradient0 + lowFrequencySurfaceGradient1;
|
|
jacobianSurface = jacobianSurface0 + jacobianSurface1;
|
|
jacobianDeep = jacobianDeep0 + jacobianDeep1;
|
|
#endif
|
|
|
|
#if defined(SUPPORT_WATER_DEFORMATION) || defined(WATER_POST_INCLUDE_DEFORMATION)
|
|
// Apply the deformation data
|
|
float2 deformationUV = EvaluateDeformationUV(transformedAWS);
|
|
float2 deformationSG = SAMPLE_TEXTURE2D_LOD(_WaterDeformationSGBuffer, s_linear_clamp_sampler, deformationUV, 0);
|
|
lFSurfaceGradient += deformationSG;
|
|
surfaceGradient += deformationSG;
|
|
#endif
|
|
#endif
|
|
|
|
// Evaluate the normals
|
|
float3 lowFrequencyNormalOS = SurfaceGradientResolveNormal(meshNormalOS, float3(lFSurfaceGradient.x, 0, lFSurfaceGradient.y));
|
|
waterAdditionalData.lowFrequencyNormalWS = TransformObjectToWorldDir_Water(lowFrequencyNormalOS);
|
|
float3 normalOS = SurfaceGradientResolveNormal(meshNormalOS, float3(surfaceGradient.x, 0, surfaceGradient.y));
|
|
waterAdditionalData.normalWS = TransformObjectToWorldDir_Water(normalOS);
|
|
|
|
#ifdef WATER_DISPLACEMENT
|
|
// Attenuate using the foam mask
|
|
float foamMask = EvaluateFoamMask(positionOS);
|
|
|
|
// Evaluate the foam from the jacobian
|
|
waterAdditionalData.surfaceFoam = SURFACE_FOAM_BRIGHTNESS * foamMask * EvaluateFoam(jacobianSurface, _SimulationFoamAmount);
|
|
waterAdditionalData.deepFoam = SCATTERING_FOAM_BRIGHTNESS * foamMask * EvaluateFoam(jacobianDeep, _SimulationFoamAmount * WATER_DEEP_FOAM_JACOBIAN_OVER_ESTIMATION);
|
|
#else
|
|
waterAdditionalData.surfaceFoam = 0;
|
|
waterAdditionalData.deepFoam = 0;
|
|
#endif
|
|
|
|
#if !defined(IGNORE_FOAM_REGION)
|
|
// Evaluate the foam region coordinates
|
|
float2 foamUV = EvaluateFoamUV(transformedAWS);
|
|
if (_WaterFoamRegionResolution > 0 && all(foamUV == saturate(foamUV)))
|
|
{
|
|
float2 foamRegion = SAMPLE_TEXTURE2D(_WaterFoamBuffer, s_linear_clamp_sampler, foamUV).xy;
|
|
waterAdditionalData.surfaceFoam += foamRegion.x;
|
|
waterAdditionalData.deepFoam += foamRegion.y;
|
|
}
|
|
#endif
|
|
|
|
// Final foam value
|
|
waterAdditionalData.deepFoam = FoamErosion(1.0 - waterAdditionalData.deepFoam, positionOS.xz, false, 4);
|
|
}
|
|
#endif
|
|
|
|
// Iteratively search water height
|
|
|
|
struct TapData
|
|
{
|
|
float3 currentDisplacement;
|
|
float3 displacedPoint;
|
|
float2 offset;
|
|
float distance;
|
|
float height;
|
|
};
|
|
|
|
TapData EvaluateDisplacementData(float3 currentLocation, float3 referencePosition)
|
|
{
|
|
TapData data;
|
|
|
|
// Evaluate the displacement at the current point
|
|
WaterDisplacementData displacementData;
|
|
EvaluateWaterDisplacement(currentLocation, displacementData);
|
|
data.currentDisplacement = displacementData.displacement;
|
|
|
|
// Evaluate the complete position
|
|
data.displacedPoint = currentLocation + data.currentDisplacement;
|
|
|
|
// Evaluate the distance to the reference point
|
|
data.offset = data.displacedPoint.xz - referencePosition.xz;
|
|
|
|
// Length of the offset vector
|
|
data.distance = length(data.offset);
|
|
|
|
// Simulation height of the position of the offset vector
|
|
data.height = displacementData.displacement.y;
|
|
|
|
return data;
|
|
}
|
|
|
|
float FindVerticalDisplacement(float3 positionWS, int iterationCount, float distanceThreshold, out int stepCount, out float currentError
|
|
#if !defined(WATER_SIMULATION)
|
|
, out float3 normal
|
|
, out float2 current
|
|
#endif
|
|
)
|
|
{
|
|
// The point we will be looking for needs to be converted into the local space of the water simulation
|
|
float3 targetPosition = mul(_WaterCustomTransform_Inverse, float4(positionWS, 1.0)).xyz;
|
|
|
|
// Initialize the search data
|
|
bool found = false;
|
|
TapData tapData = EvaluateDisplacementData(targetPosition, targetPosition);
|
|
float3 currentLocation = targetPosition;
|
|
float2 stepSize = tapData.offset;
|
|
float currentHeight = tapData.height;
|
|
|
|
currentError = tapData.distance;
|
|
stepCount = 0;
|
|
|
|
while (stepCount < iterationCount)
|
|
{
|
|
bool progress = false;
|
|
// Is the point close enough to target position?
|
|
if (currentError < distanceThreshold)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
// Keep track of the step size that will be use for the 4 samples
|
|
float2 localSearchStepSize = stepSize;
|
|
|
|
float3 candidateLocation = currentLocation - float3(localSearchStepSize.x, 0, localSearchStepSize.y);
|
|
TapData tapData = EvaluateDisplacementData(candidateLocation, targetPosition);
|
|
if (tapData.distance < currentError)
|
|
{
|
|
currentLocation = candidateLocation;
|
|
stepSize = tapData.offset;
|
|
currentError = tapData.distance;
|
|
currentHeight = tapData.height;
|
|
progress = true;
|
|
}
|
|
|
|
// If we didn't make any progress in this step, this means our steps are probably too big make them smaller
|
|
if (!progress)
|
|
stepSize *= 0.25;
|
|
|
|
// If none of the 4 steps managed to get closer, we need a smaller step
|
|
stepCount++;
|
|
}
|
|
|
|
#ifdef WATER_POST_INCLUDE_DEFORMATION
|
|
currentHeight += EvaluateWaterDeformation(positionWS);
|
|
#endif
|
|
|
|
#if !defined(WATER_SIMULATION)
|
|
WaterAdditionalData waterAdditionalData;
|
|
EvaluateWaterAdditionalData(currentLocation, GetCameraRelativePositionWS(positionWS), float3(0, 1, 0), waterAdditionalData);
|
|
normal = waterAdditionalData.normalWS;
|
|
|
|
current = OrientationToDirection(_PatchOrientation.x);
|
|
|
|
#ifdef WATER_LOCAL_CURRENT
|
|
CurrentData currentData;
|
|
EvaluateGroup0CurrentData(currentLocation.xz, currentData);
|
|
float2 currentDir = OrientationToDirection(currentData.angle);
|
|
current = float2(dot(current, float2(currentDir.x, -currentDir.y)), dot(current, currentDir.yx));
|
|
#endif
|
|
#endif
|
|
|
|
return targetPosition.y - currentHeight;
|
|
}
|
|
|
|
#endif
|