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.
227 lines
8.1 KiB
227 lines
8.1 KiB
#ifndef WATER_DECAL_UTILITIES_H
|
|
#define WATER_DECAL_UTILITIES_H
|
|
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Water/ShaderVariablesWater.cs.hlsl"
|
|
|
|
float2 GetGradient(float2 intPos)
|
|
{
|
|
float rand = frac(sin(dot(intPos, float2(12.9898, 78.233))) * 43758.5453);;
|
|
float angle = 6.283185 * rand;
|
|
return float2(cos(angle), sin(angle));
|
|
}
|
|
|
|
float DeformerNoise2D(float2 pos)
|
|
{
|
|
float2 i = floor(pos);
|
|
float2 f = pos - i;
|
|
float2 blend = f * f * (3.0 - 2.0 * f);
|
|
float g0 = dot(GetGradient(i + float2(0, 0)), f - float2(0, 0));
|
|
float g1 = dot(GetGradient(i + float2(1, 0)), f - float2(1, 0));
|
|
float g2 = dot(GetGradient(i + float2(0, 1)), f - float2(0, 1));
|
|
float g3 = dot(GetGradient(i + float2(1, 1)), f - float2(1, 1));
|
|
float noiseVal = lerp(lerp(g0, g1, blend.x), lerp(g2, g3, blend.x), blend.y);
|
|
return saturate(noiseVal / 0.7 * 0.5 + 0.5); // normalize to about [0:1]
|
|
}
|
|
|
|
// Distance to a parabola by IQ
|
|
// https://iquilezles.org/articles/distfunctions2d/
|
|
float sdParabola(float2 pos, float k )
|
|
{
|
|
pos.x = abs(pos.x);
|
|
float ik = 1.0/k;
|
|
float p = ik*(pos.y - 0.5*ik)/3.0;
|
|
float q = 0.25*ik*ik*pos.x;
|
|
float h = q*q - p*p*p;
|
|
float r = sqrt(abs(h));
|
|
float x = (h>0.0) ? pow(q+r,1.0/3.0) - pow(abs(q-r), 1.0/3.0)*sign(r-q) : 2.0*cos(atan2(r, q)/3.0)*sqrt(p);
|
|
return length(pos-float2(x,k*x*x)) * sign(pos.x-x);
|
|
}
|
|
|
|
struct WaveData
|
|
{
|
|
float position;
|
|
int bellIndex;
|
|
};
|
|
|
|
WaveData EvaluateWaveData(float position)
|
|
{
|
|
WaveData waveData;
|
|
|
|
// We need to know in which bell we are.
|
|
waveData.bellIndex = position > 0.0 ? floor(position) : ceil(-position);
|
|
|
|
// We're only interested in the fractional part of the position
|
|
waveData.position = 1.0 - frac(position);
|
|
|
|
// Return the wave data
|
|
return waveData;
|
|
}
|
|
|
|
float BreakingRegionFactor(float2 breakingRange, float2 positionOS)
|
|
{
|
|
return saturate((positionOS.x - breakingRange.x) / (breakingRange.y - breakingRange.x));
|
|
}
|
|
|
|
float2 EvaluateBlendRegion(float2 blendRegion, float2 breakingRange, float2 positionOS)
|
|
{
|
|
return lerp(blendRegion, float2(0.1, 0.9), BreakingRegionFactor(breakingRange, positionOS));
|
|
}
|
|
|
|
float ShoreWaveFirstShape(WaveData waveData)
|
|
{
|
|
return 0.5 * sin((waveData.position - 1.25) * 2.0 * PI) + 0.5;
|
|
}
|
|
|
|
float ShoreWaveSecondShape(WaveData waveData)
|
|
{
|
|
return waveData.position < 0.2 ? waveData.position * waveData.position * 25.0 : 0.5 * cos(4 * (waveData.position - 0.2)) + 0.5;
|
|
}
|
|
|
|
float ShoreWaveBlendShapes(float firstLobe, float secondLobe, float2 breakingRange, float normalizedWidth)
|
|
{
|
|
// Variable that goes from 0 to 1 and reaches 1.0 when the
|
|
float shapePicking = saturate(normalizedWidth / breakingRange.x);
|
|
float amplitude = lerp(firstLobe * shapePicking, secondLobe, shapePicking);
|
|
if (normalizedWidth >= breakingRange.x)
|
|
{
|
|
if (normalizedWidth <= breakingRange.y)
|
|
{
|
|
float range = BreakingRegionFactor(breakingRange, normalizedWidth);
|
|
amplitude *= lerp(1.0, 0.3, range);
|
|
}
|
|
else
|
|
{
|
|
float range = (normalizedWidth - breakingRange.y) / (1.0 - breakingRange.y);
|
|
amplitude *= lerp(0.3, 0.0, range);
|
|
}
|
|
}
|
|
return amplitude;
|
|
}
|
|
|
|
|
|
float EvaluateSineWaveActivation(uint bellIndex, uint skippedWaves)
|
|
{
|
|
// Based on the requested frequency, return the activation function
|
|
return bellIndex % skippedWaves == 0 ? 1.0 : 0.0;
|
|
}
|
|
|
|
void EvaluateBoxAmplitude_float(float2 uv, float2 blendRegion, bool cubicBlend, out float amplitude)
|
|
{
|
|
// Apply the edge attenuation
|
|
float2 distanceToEdges = 1 - abs(uv * 2 - 1);
|
|
if (blendRegion.x != 0.0f) distanceToEdges.x /= blendRegion.x;
|
|
if (blendRegion.y != 0.0f) distanceToEdges.y /= blendRegion.y;
|
|
|
|
float2 lerpFactor = saturate(distanceToEdges);
|
|
if (cubicBlend) lerpFactor *= lerpFactor;
|
|
|
|
amplitude = min(lerpFactor.x, lerpFactor.y);
|
|
}
|
|
|
|
void EvaluateBowWaveAmplitude_float(float2 uv, float elevation, out float amplitude)
|
|
{
|
|
float2 normPos = uv * 2 - 1;
|
|
float transitionSize = 0.1;
|
|
|
|
normPos.y = normPos.y * 0.5 + 0.5;
|
|
float2 parabolaPos = normPos;
|
|
parabolaPos.y -= transitionSize;
|
|
|
|
float dist = sdParabola(parabolaPos, 1);
|
|
|
|
if (dist > 0.0)
|
|
{
|
|
float transition = smoothstep(0, 1, saturate(dist / transitionSize));
|
|
amplitude = lerp(elevation, 0.0, transition);
|
|
}
|
|
else
|
|
{
|
|
float transition = smoothstep(0, 1, saturate(-dist / (transitionSize)));
|
|
amplitude = lerp(elevation, 1, transition);
|
|
}
|
|
|
|
// Apply attenuation so that the tail has less deformation with a cubic profile
|
|
float lengthAttenuation = (1.0 - saturate(normPos.y));
|
|
amplitude *= lengthAttenuation * lengthAttenuation;
|
|
}
|
|
|
|
float EvaluateWaveBlendAttenuation(float2 blendRegion, float2 breakingRange, float2 positionOS)
|
|
{
|
|
float2 region = EvaluateBlendRegion(blendRegion, breakingRange, positionOS);
|
|
// Apply the edge attenuation
|
|
float leftFactor = saturate((positionOS.y) / region.x);
|
|
float rightFactor = saturate((1.0 - positionOS.y) / (1.0 - region.y));
|
|
float factor = leftFactor * rightFactor;
|
|
return factor * factor;
|
|
}
|
|
|
|
float EvaluateDeepFoamAmount(float2 deepFoamRange, float positionOS)
|
|
{
|
|
float rangeSize = max(deepFoamRange.y - deepFoamRange.x, 0.001);
|
|
float midPoint = deepFoamRange.x + rangeSize * 0.5;
|
|
float appartitionFactor = saturate((positionOS - deepFoamRange.x) / (midPoint - deepFoamRange.x));
|
|
float fadeFactor = saturate((deepFoamRange.y - positionOS) / (deepFoamRange.y - midPoint));
|
|
return appartitionFactor * fadeFactor;
|
|
}
|
|
|
|
float EvaluateSurfaceFoamAmount(float2 blendRegion, float2 breakingRange, float2 positionOS)
|
|
{
|
|
// Evaluate the region where the foam happens
|
|
float2 region = EvaluateBlendRegion(blendRegion, breakingRange, positionOS);
|
|
|
|
// Wave breaking point
|
|
float positionInRange = saturate((positionOS.y - region.x) / (region.y - region.x));
|
|
float v = positionInRange > 0.5 ? 1.0 - positionInRange : positionInRange;
|
|
float breakingFactor = saturate(v / 0.2);
|
|
float appartitionFactor = saturate((positionOS.x - breakingRange.x) / 0.05);
|
|
float fadeFactor = saturate((breakingRange.y - positionOS.x) / 0.05);
|
|
return appartitionFactor * fadeFactor * breakingFactor;
|
|
|
|
}
|
|
|
|
void EvaluateShoreWaveDecal_float(float2 uv, float waveLength, uint skippedWaves, float2 waveBlend,
|
|
float waveOffset, float2 breakingRange, float2 deepFoamRange, out float amplitude, out float2 foam)
|
|
{
|
|
// Compute the overall position (takes into account wave speed and wave length)
|
|
float t = ((uv.x * 2 - 1) - waveOffset) / waveLength;
|
|
|
|
// Evaluate the wave data
|
|
WaveData waveData = EvaluateWaveData(t);
|
|
float waveActivation = EvaluateSineWaveActivation(waveData.bellIndex, skippedWaves);
|
|
float attenuation = EvaluateWaveBlendAttenuation(waveBlend, breakingRange, uv);
|
|
float noise2D = DeformerNoise2D(uv * 0.25);
|
|
|
|
// Evaluate the round lobe
|
|
float firstShape = ShoreWaveFirstShape(waveData);
|
|
|
|
// Evaluate the breaking lobe
|
|
float secondShape = ShoreWaveSecondShape(waveData);
|
|
|
|
// Start from the target amplitude
|
|
amplitude = (0.8 + 0.2 * noise2D) * 0.5;
|
|
|
|
// Blend the lobes
|
|
amplitude *= ShoreWaveBlendShapes(firstShape, secondShape, breakingRange, uv.x);
|
|
|
|
// Apply the edge attenuation and skip wave
|
|
amplitude *= waveActivation * attenuation;
|
|
|
|
|
|
// Define where the foam appears on the wave
|
|
float surfacefoamWaveLocation = saturate((waveData.position - 0.1) / 0.1) * (1.0 - saturate((waveData.position - 0.5) / 0.02));
|
|
float deepFoamWaveLocation = saturate((waveData.position - 0.1) / 0.1) * (1.0 - saturate((waveData.position - 0.3) / 0.1));
|
|
|
|
// Define what amount of foam appears
|
|
float deepfoamAmount = EvaluateDeepFoamAmount(deepFoamRange, uv.x);
|
|
float surfaceFoamAmount = EvaluateSurfaceFoamAmount(waveBlend, breakingRange, uv);
|
|
|
|
// Evaluate the perlin noise
|
|
float perlinNoise = 0.2 + noise2D;
|
|
|
|
// Combine to generate the foam
|
|
foam.x = surfaceFoamAmount * surfacefoamWaveLocation * 4;
|
|
foam.y = deepfoamAmount * deepFoamWaveLocation * 2;
|
|
foam *= perlinNoise * waveActivation * attenuation;
|
|
}
|
|
|
|
#endif // WATER_DECAL_UTILITIES_H
|