2025-10-21 14:18:31 +09:00

117 lines
3.8 KiB
HLSL

// Stylized Water 3 by Staggart Creations (http://staggart.xyz)
// COPYRIGHT PROTECTED UNDER THE UNITY ASSET STORE EULA (https://unity.com/legal/as-terms)
// • Copying or referencing source code for the production of new asset store, or public, content is strictly prohibited!
// • Uploading this file to a public repository will subject it to an automated DMCA takedown request.
#ifndef WATER_GERSTNER_INCLUDED
#define WATER_GERSTNER_INCLUDED
#define MAX_AMPLITUDE 5.0
#define GRAVITY 9.8f
float3 _GlobalWaveOriginOffset;
#if !defined(UNITY_CORE_SAMPLERS_INCLUDED)
//Do not want linear interpolation between texels, forcing the usage of a point sampler
SamplerState sampler_PointClamp;
#endif
struct WaveParameters
{
uint enabled;
float amplitude;
float waveLength;
float steepness;
uint mode;
float direction;
float2 origin;
};
//Sample parameters from LUT, stored in two horizontal rows
void SampleWaveParameters(inout WaveParameters data, uint index, Texture2D tex, uint columns)
{
//Each layer's data is stored in a texel, from left to right. The horizontal position corresponds to the array element, so that's the UV
const float2 lutUV = float2((float)index / (float)columns, 0);
const float4 row0 = SAMPLE_TEXTURE2D_LOD(tex, sampler_PointClamp, lutUV, 0);
data.amplitude = row0.x;
data.waveLength = row0.y;
data.direction = row0.z; //Rotation angle in radians
data.enabled = row0.w;
const float4 row1 = SAMPLE_TEXTURE2D_LOD(tex, sampler_PointClamp, lutUV + float2(0, 0.5), 0);
data.origin = row1.xy + _GlobalWaveOriginOffset.xz;
data.mode = row1.z;
data.steepness = row1.w;
}
//LUT texture is passed in as a parameter, since it may differ on a per-material basis
void CalculateGerstnerWaves_float(in Texture2D<float4> lutTex, in uint layerCount, in float2 position, in float frequency, in float time, in float normalStrength, in float2 baseDirection, in uint count, out float3 offset, out float3 tangent, out float3 bitangent)
{
//Defaults
offset = float3(0,0,0);
tangent = float3(1,0,0);
bitangent = float3(0,0,1);
//Clamp to maximum number of layers
count = min(count - 1, layerCount);
WaveParameters layer = (WaveParameters)0;
uint waveCount = 0;
for(uint i = 0; i <= count; i++)
{
SampleWaveParameters(layer, i, lutTex, layerCount);
if(layer.enabled > 0)
{
waveCount += 1;
const float w = TWO_PI / (layer.waveLength * frequency);
const float freq = sqrt(GRAVITY * w);
//As amplitude scales down, so should the steepness
half ampRCP = (layer.amplitude/MAX_AMPLITUDE);
//Both divide and scale by amplitude
float steepness = (layer.steepness / layer.amplitude) * ampRCP;
//Rotation already pre-converted into radians
float2 direction = float2(sin(layer.direction), cos(layer.direction)) * baseDirection;
//Radial mode
if(layer.mode == 1)
{
direction = (position - layer.origin);
direction = normalize(direction);
}
const float dir = dot(direction, position - (layer.origin * layer.mode));
const float t = dir * w + (freq * -time);
float proximalSine = sin(t); //Y
float lateralSine = cos(t); //XZ
//Relative XYZ offsets
offset.x += direction.x * layer.amplitude * lateralSine * steepness;
offset.y += proximalSine * layer.amplitude;
offset.z += direction.y * layer.amplitude * lateralSine * steepness;
tangent += float3(
-direction.x * direction.x * (steepness * proximalSine),
offset.x,
-direction.x * direction.y * (steepness * proximalSine)
);
bitangent += float3(
-direction.x * direction.y * (steepness * proximalSine),
offset.z,
-direction.y * -direction.y * (steepness * proximalSine)
);
}
}
waveCount = max(waveCount, 1);
tangent = lerp(float3(1,0,0), tangent, normalStrength / waveCount);
bitangent = lerp(float3(0,0,1), bitangent, normalStrength / waveCount);
}
#endif