// 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 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