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.
 
 
 
 

656 lines
23 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));
}
float2 EvaluateDecalUV(float3 transformedPositionAWS)
{
return (transformedPositionAWS.xz - _DecalRegionOffset) * _DecalRegionScale + 0.5f;
}
float3 EvaluateInverseDecalUV(float2 uv)
{
float2 posWS = (uv - 0.5f) / _DecalRegionScale + _DecalRegionOffset;
return float3(posWS.x, 0, posWS.y);
}
// Water Mask
TEXTURE2D(_WaterMask);
SAMPLER(sampler_WaterMask);
float4 EvaluateWaterMask(float3 positionAWS)
{
#ifdef WATER_DECAL_COMPLETE
float2 maskUV = (positionAWS.xz - _DecalRegionOffset) * _DecalRegionScale + 0.5f;
float4 mask = all(maskUV == saturate(maskUV)) ? SAMPLE_TEX2D(_WaterMask, s_linear_clamp_sampler, maskUV) : 1;
return float4(mask.xyz, lerp(1, mask.w, _SimulationFoamMaskScale.x));
#else
float2 maskUV = RotateUV(positionAWS.xz - _WaterMaskOffset) * _WaterMaskScale + 0.5f;
float4 waterMask = SAMPLE_TEX2D(_WaterMask, sampler_WaterMask, maskUV);
return float4(_WaterMaskRemap.xxx + waterMask.xyz * _WaterMaskRemap.yyy, 1);
#endif
}
// Deformation region
Texture2D<float4> _WaterDeformationBuffer;
Texture2D<float2> _WaterDeformationSGBuffer;
float4 EvaluateWaterDeformation(float3 positionAWS)
{
float2 deformationUV = EvaluateDecalUV(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, float distanceToCamera, out float2 horizontalDisplacement, out float3 verticalDisplacements)
{
// Initialize the output
horizontalDisplacement = 0.0;
verticalDisplacements = 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)
{
// 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) * currentData.blend;
// Apply the camera distance attenuation
rawDisplacement *= distanceFade;
// Swizzle the displacement and add it
horizontalDisplacement += float2(dot(rawDisplacement.yz, currentData.swizzle.xy), dot(rawDisplacement.yz, currentData.swizzle.zw));
verticalDisplacements[bandIdx] = rawDisplacement.x;
}
}
}
// Evaluate Water displacement
void EvaluateSimulationDisplacement(float3 positionOS, out float2 horizontalDisplacement, out float3 verticalDisplacements)
{
// Evaluate the pre-displaced absolute position
float3 positionRWS = TransformObjectToWorld_Water(positionOS);
// Evaluate the distance to the camera
float distanceToCamera = length(positionRWS);
#if !defined(WATER_LOCAL_CURRENT)
// Compute the simulation coordinates
WaterSimCoord waterCoord;
ComputeWaterUVs(positionOS.xz, waterCoord);
// Sample the simulation
SampleSimulation_VS(waterCoord, distanceToCamera, horizontalDisplacement, verticalDisplacements);
#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 horizontalDisplacement0;
float3 verticalDisplacements0;
SampleSimulation_VS(finalCoords, distanceToCamera, horizontalDisplacement0, verticalDisplacements0);
// Sample the simulation (second time)
ComputeWaterUVs(tapCoords[0].zw, waterCoord[0]);
ComputeWaterUVs(tapCoords[1].zw, waterCoord[1]);
AggregateWaterSimCoords(waterCoord, currentData, false, finalCoords);
float2 horizontalDisplacement1;
float3 verticalDisplacements1;
SampleSimulation_VS(finalCoords, distanceToCamera, horizontalDisplacement1, verticalDisplacements1);
// Combine both contributions
horizontalDisplacement = horizontalDisplacement0 + horizontalDisplacement1;
verticalDisplacements = verticalDisplacements0 + verticalDisplacements1;
#endif
// We apply the choppiness to all bands
horizontalDisplacement *= -WATER_SYSTEM_CHOPPINESS;
}
void EvaluateDisplacement(float3 positionOS, float3 verticalDisplacements, out float verticalDisplacement, out float2 horizontalDisplacement, out float lowFrequencyHeight)
{
// Compute the position that will be used to sample decals
float3 positionAWS = GetAbsolutePositionWS(TransformObjectToWorld_Water(positionOS));
// Compute water mask
float3 waterMask = EvaluateWaterMask(positionAWS).xyz;
// Compute final vertical deformation
verticalDisplacement = dot(verticalDisplacements, waterMask);
lowFrequencyHeight = dot(verticalDisplacements.xy, waterMask.xy);
horizontalDisplacement = float2(0, 0);
#if defined(SUPPORT_WATER_DEFORMATION)
// Apply the deformation data
float4 deformation = EvaluateWaterDeformation(positionAWS + verticalDisplacements);
horizontalDisplacement = deformation.yz;
verticalDisplacement += deformation.x;
lowFrequencyHeight += deformation.x;
#endif
}
struct WaterDisplacementData
{
float3 displacement;
float lowFrequencyHeight;
};
void EvaluateWaterDisplacement(float3 positionOS, out WaterDisplacementData displacementData)
{
float2 simulationHorizontalDisplacement;
float2 deformationHorizontalDisplacement;
float3 verticalDisplacements;
EvaluateSimulationDisplacement(positionOS, simulationHorizontalDisplacement, verticalDisplacements);
float lowFrequencyHeight;
float3 displacement = float3(simulationHorizontalDisplacement.x, 0, simulationHorizontalDisplacement.y);
EvaluateDisplacement(positionOS + displacement, verticalDisplacements, displacement.y, deformationHorizontalDisplacement, lowFrequencyHeight);
displacement.xz += deformationHorizontalDisplacement.xy;
displacementData.displacement = displacement;
displacementData.lowFrequencyHeight = lowFrequencyHeight;
#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 positionOS)
{
return positionOS * _SimulationFoamMaskScale - _SimulationFoamMaskOffset * _SimulationFoamMaskScale + 0.5f;
}
float EvaluateFoam(float jacobian, float foamAmount)
{
return saturate(-jacobian + foamAmount);
}
float EvaluateFoamMask(float3 positionOS, float4 waterMask)
{
#ifdef WATER_DECAL_COMPLETE
float foamMask = waterMask.w;
#else
float2 maskUV = EvaluateFoamMaskUV(positionOS.xz);
float foamMask = SAMPLE_TEX2D(_SimulationFoamMask, sampler_SimulationFoamMask, maskUV).x;
#endif
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, float2 horizontalDisplacement, out WaterAdditionalData waterAdditionalData)
{
ZERO_INITIALIZE(WaterAdditionalData, waterAdditionalData);
if (_GridSize.x < 0)
return;
// Evaluate the pre-displaced absolute position
#if defined(WATER_DISPLACEMENT)
float3 positionRWS = positionOS;
#else
float3 positionRWS = TransformObjectToWorld_Water(positionOS);
#endif
// Evaluate the distance to the camera
float distanceToCamera = length(positionRWS);
// Get the world space transformed postion
float3 transformedAWS = GetAbsolutePositionWS(transformedPosition);
float2 decalUV = EvaluateDecalUV(transformedAWS - float3(horizontalDisplacement.x, 0.0f, horizontalDisplacement.y));
// 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
float4 waterMask = EvaluateWaterMask(transformedAWS);
// 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.xyz, 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.xyz, 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.xyz, 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)
// Apply the deformation data
if (all(decalUV == saturate(decalUV)))
{
float2 deformationSG = SAMPLE_TEXTURE2D_LOD(_WaterDeformationSGBuffer, s_linear_clamp_sampler, decalUV, 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 simulation foam mask
float foamMask = EvaluateFoamMask(positionOS, waterMask);
// 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
if (all(decalUV == saturate(decalUV)))
{
float2 foamRegion = SAMPLE_TEXTURE2D(_WaterFoamBuffer, s_linear_clamp_sampler, decalUV).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
{
float2 offset;
float distance;
float2 horizontalDisplacement;
float3 verticalDisplacements;
};
TapData EvaluateDisplacementData(float3 currentLocation, float3 referencePosition)
{
TapData data;
// Evaluate the displacement at the current point
EvaluateSimulationDisplacement(currentLocation, data.horizontalDisplacement, data.verticalDisplacements);
// Evaluate the distance to the reference point
data.offset = (currentLocation.xz + data.horizontalDisplacement) - referencePosition.xz;
data.distance = length(data.offset);
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;
float3 currentVertical = tapData.verticalDisplacements;
float2 stepSize = tapData.offset;
currentError = tapData.distance;
stepCount = 0;
while (stepCount < iterationCount)
{
if (currentError < distanceThreshold)
{
found = true;
break;
}
float3 candidateLocation = currentLocation - float3(stepSize.x, 0, stepSize.y);
TapData tapData = EvaluateDisplacementData(candidateLocation, targetPosition);
if (tapData.distance < currentError)
{
currentLocation = candidateLocation;
stepSize = tapData.offset;
currentError = tapData.distance;
currentVertical = tapData.verticalDisplacements;
}
else // If we didn't make any progress in this step, this means our steps are probably too big make them smaller
stepSize *= 0.25;
stepCount++;
}
float currentHeight;
float2 horizontalDisplacement;
float lowFrequencyHeight;
EvaluateDisplacement(currentLocation, currentVertical, currentHeight, horizontalDisplacement, lowFrequencyHeight);
#if !defined(WATER_SIMULATION)
WaterAdditionalData waterAdditionalData;
EvaluateWaterAdditionalData(currentLocation, GetCameraRelativePositionWS(positionWS), float3(0, 1, 0), float2(0,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