Files
Fishing2/Packages/com.waveharmonic.crest/Runtime/Shaders/Data/Input/ShapeWavesFromGeometry.shader
2026-01-08 22:30:55 +08:00

193 lines
6.8 KiB
Plaintext

// Crest Water System
// Copyright © 2024 Wave Harmonic. All rights reserved.
// Generates waves from geometry that is rendered into the water simulation from a top down camera. Expects
// following data on verts:
// - POSITION: Vert positions as normal.
// - TEXCOORD0: Axis - direction for waves to travel. "Forward vector" for waves.
// - TEXCOORD1: X - 0 at start of waves, 1 at end of waves
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ uv1.x = 0 |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | uv0 - wave direction vector
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | \|/
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ uv1.x = 1
// ------------------- shoreline --------------------
//
Shader "Crest/Inputs/Shape Waves/Add From Geometry"
{
Properties
{
[Enum(UnityEngine.Rendering.BlendMode)]
_Crest_BlendModeSource("Source Blend Mode", Int) = 1
[Enum(UnityEngine.Rendering.BlendMode)]
_Crest_BlendModeTarget("Target Blend Mode", Int) = 1
// Controls ramp distance over which waves grow/fade as they move forwards
_Crest_FeatherWaveStart( "Feather wave start (0-1)", Range( 0.0, 10 ) ) = 0.1
[Toggle(d_Feather)]
_Crest_Feather("Feather At UV Extents", Float) = 0
_Crest_FeatherWidth("Feather Width", Range(0.001, 1)) = 0.1
[HideInInspector]
_Crest_Version("Version", Integer) = 0
}
CGINCLUDE
#pragma vertex Vertex
#pragma fragment Fragment
// #pragma enable_d3d11_debug_symbols
#pragma shader_feature_local_fragment d_Feather
#include "UnityCG.cginc"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Macros.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Globals.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/InputsDriven.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Cascade.hlsl"
#include "Packages/com.waveharmonic.crest/Runtime/Shaders/Library/Helpers.hlsl"
Texture2DArray _Crest_WaveBuffer;
CBUFFER_START(CrestPerWaterInput)
float _Crest_RespectShallowWaterAttenuation;
int _Crest_WaveBufferSliceIndex;
float _Crest_AverageWavelength;
float _Crest_AttenuationInShallows;
float _Crest_Weight;
float2 _Crest_AxisX;
half _Crest_MaximumAttenuationDepth;
half _Crest_FeatherWidth;
half _Crest_FeatherWaveStart;
CBUFFER_END
m_CrestNameSpace
struct Attributes
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float3 uv_slice : TEXCOORD1;
float2 axis : TEXCOORD2;
float3 worldPosScaled : TEXCOORD3;
float2 worldPosXZ : TEXCOORD5;
};
Varyings Vertex(Attributes v)
{
Varyings o;
const float3 positionOS = v.vertex.xyz;
o.vertex = UnityObjectToClipPos(positionOS);
const float3 worldPos = mul( unity_ObjectToWorld, float4(positionOS, 1.0) ).xyz;
// UV coordinate into the cascade we are rendering into
o.uv_slice = Cascade::MakeAnimatedWaves(_Crest_LodIndex).WorldToUV(worldPos.xz);
o.worldPosXZ = worldPos.xz;
o.uv = v.uv;
// World pos prescaled by wave buffer size, suitable for using as UVs in fragment shader
const float waveBufferSize = 0.5f * (1 << _Crest_WaveBufferSliceIndex);
o.worldPosScaled = worldPos / waveBufferSize;
// Rotate forward axis around y-axis into world space
o.axis = unity_ObjectToWorld._m00_m20.xy;
o.axis = _Crest_AxisX.x * o.axis + _Crest_AxisX.y * float2(-o.axis.y, o.axis.x);
return o;
}
float4 Fragment(Varyings input)
{
float wt = _Crest_Weight;
// Feature at away from shore.
wt *= saturate(input.uv.x / _Crest_FeatherWaveStart);
#if d_Feather
wt *= FeatherWeightFromUV(input.uv, _Crest_FeatherWidth);
#endif
float alpha = wt;
// Attenuate if depth is less than half of the average wavelength
const half depth = Cascade::MakeDepth(_Crest_LodIndex).SampleSignedDepthFromSeaLevel(input.worldPosXZ) +
Cascade::MakeLevel(_Crest_LodIndex).SampleLevel(input.worldPosXZ);
half depth_wt = saturate(2.0 * depth / _Crest_AverageWavelength);
if (_Crest_MaximumAttenuationDepth < k_Crest_MaximumWaveAttenuationDepth)
{
depth_wt = lerp(depth_wt, 1.0, saturate(depth / _Crest_MaximumAttenuationDepth));
}
const float attenuationAmount = _Crest_AttenuationInShallows * _Crest_RespectShallowWaterAttenuation;
wt *= attenuationAmount * depth_wt + (1.0 - attenuationAmount);
// Quantize wave direction and interpolate waves
float axisHeading = atan2( input.axis.y, input.axis.x ) + 2.0 * 3.141592654;
const float dTheta = 0.5*0.314159265;
float angle0 = axisHeading;
const float rem = fmod( angle0, dTheta );
angle0 -= rem;
const float angle1 = angle0 + dTheta;
float2 axisX0; sincos( angle0, axisX0.y, axisX0.x );
float2 axisX1; sincos( angle1, axisX1.y, axisX1.x );
float2 axisZ0; axisZ0.x = -axisX0.y; axisZ0.y = axisX0.x;
float2 axisZ1; axisZ1.x = -axisX1.y; axisZ1.y = axisX1.x;
const float2 uv0 = float2(dot( input.worldPosScaled.xz, axisX0 ), dot( input.worldPosScaled.xz, axisZ0 ));
const float2 uv1 = float2(dot( input.worldPosScaled.xz, axisX1 ), dot( input.worldPosScaled.xz, axisZ1 ));
// Sample displacement, rotate into frame
float3 disp0 = _Crest_WaveBuffer.SampleLevel( sampler_Crest_linear_repeat, float3(uv0, _Crest_WaveBufferSliceIndex), 0 ).xyz;
float3 disp1 = _Crest_WaveBuffer.SampleLevel( sampler_Crest_linear_repeat, float3(uv1, _Crest_WaveBufferSliceIndex), 0 ).xyz;
disp0.xz = disp0.x * axisX0 + disp0.z * axisZ0;
disp1.xz = disp1.x * axisX1 + disp1.z * axisZ1;
float3 disp = lerp( disp0, disp1, rem / dTheta );
disp *= wt;
return float4(disp, alpha);
}
m_CrestNameSpaceEnd
m_CrestVertex
m_CrestFragment(float4)
ENDCG
SubShader
{
ZWrite Off
ZTest Always
Cull Off
Pass
{
// Either additive or alpha blend for geometry waves.
Blend [_Crest_BlendModeSource] [_Crest_BlendModeTarget]
CGPROGRAM
ENDCG
}
Pass
{
// Subsequent draws need to be additive. We cannot change render state with command
// buffer and changing on material is not aligned with command buffer usage.
Blend One One
CGPROGRAM
ENDCG
}
}
CustomEditor "WaveHarmonic.Crest.Editor.CustomShaderGUI"
}