From 1705cd25f5bcd796a560bcce22ef91d190a94900 Mon Sep 17 00:00:00 2001 From: yum Date: Thu, 24 Oct 2024 18:45:29 -0700 Subject: add water stuff --- Editor/tooner.cs | 21 +++++++++++ clones.cginc | 4 ++- feature_macros.cginc | 1 + gerstner.cginc | 88 ++++++++++++++++++++++++++++++++++++---------- globals.cginc | 9 +++++ math.cginc | 5 +++ mochie_shadow_caster.cginc | 8 +++++ pbr.cginc | 2 +- tooner.shader | 5 +++ tooner_lighting.cginc | 27 ++++++++------ tooner_outline_pass.cginc | 5 ++- 11 files changed, 144 insertions(+), 31 deletions(-) diff --git a/Editor/tooner.cs b/Editor/tooner.cs index 2a6d805..bd98d37 100644 --- a/Editor/tooner.cs +++ b/Editor/tooner.cs @@ -2136,6 +2136,27 @@ public class ToonerGUI : ShaderGUI { int num_octaves = (int) Math.Floor((bc.floatValue-1)/4); SetKeyword("_GIMMICK_GERSTNER_WATER_OCTAVE_1", num_octaves >= 1); + bc = FindProperty("_Gimmick_Gerstner_Water_Color_Ramp"); + TexturePropertySingleLine( + MakeLabel(bc, "Color ramp"), + bc); + SetKeyword("_GIMMICK_GERSTNER_WATER_COLOR_RAMP", bc.textureValue); + + if (bc.textureValue) { + EditorGUI.indentLevel += 1; + + bc = FindProperty("_Gimmick_Gerstner_Water_Color_Ramp_Offset"); + FloatProperty(bc, "Offset"); + bc = FindProperty("_Gimmick_Gerstner_Water_Color_Ramp_Scale"); + FloatProperty(bc, "Scale"); + bc = FindProperty("_Gimmick_Gerstner_Water_Color_Ramp_Mask"); + VectorProperty(bc, "Mask (octave 0)"); + bc = FindProperty("_Gimmick_Gerstner_Water_Color_Ramp_Mask1"); + VectorProperty(bc, "Mask (octave 1)"); + + EditorGUI.indentLevel -= 1; + } + { LabelField("Octave 0", EditorStyles.boldLabel); EditorGUI.indentLevel += 1; diff --git a/clones.cginc b/clones.cginc index 00612f3..9b43b80 100644 --- a/clones.cginc +++ b/clones.cginc @@ -12,10 +12,12 @@ void add_clones(in v2f clone_verts[3], inout TriangleStream tri_out) return; } +#if 0 float factor = _Tess_Factor; if (_Clones_Dist_Cutoff > 0 && length(_WorldSpaceCameraPos - clone_verts[0].worldPos) > _Clones_Dist_Cutoff) { factor = 1; } +#endif uint n_clones = (uint) round(_Clones_Count); for (uint i = 0; i < (uint) n_clones; i++) { @@ -26,7 +28,7 @@ void add_clones(in v2f clone_verts[3], inout TriangleStream tri_out) offset = ((offset % 2) * 2 - 1) * (((offset) / 2) + 1) * _Clones_dx; objPos.x += offset; ii.worldPos = mul(unity_ObjectToWorld, float4(objPos, 1)).xyz; - ii.clipPos = UnityObjectToClipPos(objPos); + ii.pos = UnityObjectToClipPos(objPos); tri_out.Append(ii); } tri_out.RestartStrip(); diff --git a/feature_macros.cginc b/feature_macros.cginc index 7c826aa..1cb3233 100644 --- a/feature_macros.cginc +++ b/feature_macros.cginc @@ -174,6 +174,7 @@ #pragma shader_feature_local _ _GIMMICK_AURORA #pragma shader_feature_local _ _GIMMICK_GERSTNER_WATER #pragma shader_feature_local _ _GIMMICK_GERSTNER_WATER_OCTAVE_1 +#pragma shader_feature_local _ _GIMMICK_GERSTNER_WATER_COLOR_RAMP #endif // __FEATURE_MACROS_INC diff --git a/gerstner.cginc b/gerstner.cginc index e6ed3c2..47843a7 100644 --- a/gerstner.cginc +++ b/gerstner.cginc @@ -1,3 +1,5 @@ +#include "globals.cginc" +#include "math.cginc" #include "pema99.cginc" #ifndef __GERSTNER_INC @@ -17,12 +19,18 @@ struct GerstnerParams { float4 k_y; // time factor float4 t_f; +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) + float4 ramp_mask; +#endif #if defined(_GIMMICK_GERSTNER_WATER_OCTAVE_1) float4 a1; float4 p1; float4 k_x1; float4 k_y1; float4 t_f1; +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) + float4 ramp_mask1; +#endif #endif // mean water depth float h; @@ -31,6 +39,14 @@ struct GerstnerParams { float3 scale; }; +struct GerstnerFragResult { + float4 tangent; + float3 normal; +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) + float3 color; +#endif +}; + GerstnerParams getGerstnerParams() { GerstnerParams p; p.M = _Gimmick_Gerstner_Water_M; @@ -44,6 +60,9 @@ GerstnerParams getGerstnerParams() { p.g = _Gimmick_Gerstner_Water_g; p.scale = _Gimmick_Gerstner_Water_Scale; p.t_f = _Gimmick_Gerstner_Water_t_f; +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) + p.ramp_mask = _Gimmick_Gerstner_Water_Color_Ramp_Mask; +#endif #if defined(_GIMMICK_GERSTNER_WATER_OCTAVE_1) p.a1 = _Gimmick_Gerstner_Water_a1; p.p1 = _Gimmick_Gerstner_Water_p1; @@ -51,17 +70,26 @@ GerstnerParams getGerstnerParams() { p.k_x1 += k_x_time_distortion; p.k_y1 = _Gimmick_Gerstner_Water_k_y1; p.t_f1 = _Gimmick_Gerstner_Water_t_f1; +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) + p.ramp_mask1 = _Gimmick_Gerstner_Water_Color_Ramp_Mask1; +#endif #endif return p; } -float3 compute_gerstner(float3 pp, GerstnerParams p) +struct GerstnerInternalResult { + float3 world_pos; + float color_ramp_pos; +}; + +GerstnerInternalResult compute_gerstner(float3 pp, GerstnerParams p) { const float g_alpha = pp.x * p.scale.x; const float g_beta = pp.y * p.scale.y; float g_xi = g_alpha; float g_eta = g_beta; float g_zeta = 0; + float g_zeta_color_ramp = 0; for (uint i = 0; i < p.M; i++) { uint i_mod_4 = glsl_mod(i, 4); @@ -79,6 +107,9 @@ float3 compute_gerstner(float3 pp, GerstnerParams p) g_xi -= (p.k_x[i] / g_k) * (p.a[i] / tanh(g_k * p.h)) * sin(g_theta); g_eta -= (p.k_y[i] / g_k) * (p.a[i] / tanh(g_k * p.h)) * sin(g_theta); g_zeta += p.a[i] * cos(g_theta); +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) + g_zeta_color_ramp += p.a[i] * cos(g_theta) * p.ramp_mask[i]; +#endif break; } #if defined(_GIMMICK_GERSTNER_WATER_OCTAVE_1) @@ -94,51 +125,72 @@ float3 compute_gerstner(float3 pp, GerstnerParams p) g_xi -= (p.k_x1[i_mod_4] / g_k) * (p.a1[i_mod_4] / tanh(g_k * p.h)) * sin(g_theta); g_eta -= (p.k_y1[i_mod_4] / g_k) * (p.a1[i_mod_4] / tanh(g_k * p.h)) * sin(g_theta); g_zeta += p.a1[i_mod_4] * cos(g_theta); +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) + g_zeta_color_ramp += p.a1[i_mod_4] * cos(g_theta) * p.ramp_mask1[i_mod_4]; +#endif break; } #endif } - } const float3 raw_result = float3(g_xi / p.scale.x, g_eta / p.scale.y, g_zeta * p.scale.z); + g_zeta_color_ramp *= p.scale.z; const float3 raw_result_world = mul(unity_ObjectToWorld, float4(raw_result, 1)).xyz; float3 result_world = raw_result_world; if (_Gimmick_Gerstner_Water_Origin_Damping_Direction > 0) { - result_world.y = max(_Gimmick_Gerstner_Water_Origin_Damping_Direction, result_world.y); + result_world.y = dmax(_Gimmick_Gerstner_Water_Origin_Damping_Direction, result_world.y, 1); } else { - result_world.y = min(_Gimmick_Gerstner_Water_Origin_Damping_Direction, result_world.y); + result_world.y = dmin(_Gimmick_Gerstner_Water_Origin_Damping_Direction, result_world.y, 1); } - result_world.y = lerp(result_world.y, raw_result_world.y, - // If within 20m cylindrical distance, apply 100m wide damping. + float3 result_obj = mul(unity_WorldToObject, float4(result_world, 1)).xyz; + + result_obj = lerp(result_obj, raw_result, + // If within 3m cylindrical distance, apply 100m wide damping. // TODO parameterize this! - saturate((length(raw_result_world.xz) - 20) * 0.01) * + dsaturate((length(raw_result_world.xz) - 20), 1) * // Only enable if mesh is on the wrong side of the damping vector. - (sign(raw_result_world.y - _Gimmick_Gerstner_Water_Origin_Damping_Direction) != sign(_Gimmick_Gerstner_Water_Origin_Damping_Direction))); + // TODO make this differentiable. As is, there's a visible seam. + dsaturate(-(raw_result_world.y - _Gimmick_Gerstner_Water_Origin_Damping_Direction) * sign(_Gimmick_Gerstner_Water_Origin_Damping_Direction), 1)); - float3 result = mul(unity_WorldToObject, float4(result_world, 1)).xyz; - return result; + GerstnerInternalResult r; + r.world_pos = result_obj; + r.color_ramp_pos = g_zeta_color_ramp; + return r; } float3 gerstner_vert(float3 pp, GerstnerParams p) { - return compute_gerstner(pp, p); + return compute_gerstner(pp, p).world_pos; } -float3 gerstner_frag(float3 pp, GerstnerParams p) +GerstnerFragResult gerstner_frag(float3 pp, GerstnerParams p) { - const float3 g0 = compute_gerstner(pp, p); - const float3 e = float3(1E-8, 0, 0); - const float3 g0_da = compute_gerstner(pp + e.xyz, p); - const float3 g0_db = compute_gerstner(pp + e.yxz, p); + const GerstnerInternalResult r0 = compute_gerstner(pp, p); + const float3 g0 = r0.world_pos; + const float3 e = float3(1E-7, 0, 0); + const float3 g0_da = compute_gerstner(pp + e.xyz, p).world_pos; + const float3 g0_db = compute_gerstner(pp + e.yxz, p).world_pos; const float3 ds_da = g0_da - g0; const float3 ds_db = g0_db - g0; - const float3 n = normalize(cross( + GerstnerFragResult r; + r.normal = normalize(cross( ds_da, ds_db)); - return n; + r.tangent = float4(normalize(ds_da), 1); + +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) + float ramp_phase = r0.color_ramp_pos; + ramp_phase *= _Gimmick_Gerstner_Water_Color_Ramp_Scale; + ramp_phase += _Gimmick_Gerstner_Water_Color_Ramp_Offset; + float3 ramp_color = _Gimmick_Gerstner_Water_Color_Ramp.Sample(linear_clamp_s, float2(ramp_phase, 0.5)); + + r.color = ramp_color; +#endif + + return r; } #endif // _GIMMICK_GERSTNER_WATER diff --git a/globals.cginc b/globals.cginc index 6800b7b..3a9616b 100644 --- a/globals.cginc +++ b/globals.cginc @@ -753,6 +753,9 @@ float4 _Gimmick_Gerstner_Water_k_x; float4 _Gimmick_Gerstner_Water_k_y; float4 _Gimmick_Gerstner_Water_t_f; float _Gimmick_Gerstner_Water_Origin_Damping_Direction; +texture2D _Gimmick_Gerstner_Water_Color_Ramp; +float _Gimmick_Gerstner_Water_Color_Ramp_Offset; +float _Gimmick_Gerstner_Water_Color_Ramp_Scale; #if defined(_GIMMICK_GERSTNER_WATER_OCTAVE_1) float4 _Gimmick_Gerstner_Water_a1; float4 _Gimmick_Gerstner_Water_p1; @@ -760,6 +763,12 @@ float4 _Gimmick_Gerstner_Water_k_x1; float4 _Gimmick_Gerstner_Water_k_y1; float4 _Gimmick_Gerstner_Water_t_f1; #endif +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) +float4 _Gimmick_Gerstner_Water_Color_Ramp_Mask; +#if defined(_GIMMICK_GERSTNER_WATER_OCTAVE_1) +float4 _Gimmick_Gerstner_Water_Color_Ramp_Mask1; +#endif +#endif #endif #endif diff --git a/math.cginc b/math.cginc index bfbe653..8aaa5ea 100644 --- a/math.cginc +++ b/math.cginc @@ -125,6 +125,11 @@ float dabs(float a, float k) return log2(exp2(k * a) + exp2(-1.0 * k * a)); } +float dsaturate(float x, float k) +{ + return dmin(dmax(x, 0, k), 1, k); +} + float rand(uint seed) { seed = seed * 747796405 + 2891336453; uint result = ((seed >> ((seed >> 28) + 4)) ^ seed) * 277803737; diff --git a/mochie_shadow_caster.cginc b/mochie_shadow_caster.cginc index 9e8ee1e..028cc31 100644 --- a/mochie_shadow_caster.cginc +++ b/mochie_shadow_caster.cginc @@ -1,3 +1,5 @@ +#include "gerstner.cginc" + #ifndef __MOCHIE_SHADOW_CASTER_INC #define __MOCHIE_SHADOW_CASTER_INC @@ -54,6 +56,12 @@ v2f vert (appdata v){ if (_Discard_Enable_Dynamic) { return (v2f) (0.0 / 0.0); } +#endif +#if !defined(_SCROLL) && defined(_GIMMICK_GERSTNER_WATER) + { + GerstnerParams p = getGerstnerParams(); + v.vertex.xyz = gerstner_vert(v.vertex.xyz, p); + } #endif v2f o = (v2f)0; UNITY_SETUP_INSTANCE_ID(v); diff --git a/pbr.cginc b/pbr.cginc index d575093..002c387 100644 --- a/pbr.cginc +++ b/pbr.cginc @@ -346,7 +346,7 @@ float4 getLitColor( screenPos = float4(i.screenPos, 0, i.pos.w); #endif -#if 1 +#if 0 float reflection_strength = _ReflectionStrength; #if defined(_REFLECTION_STRENGTH_TEX) reflection_strength *= _ReflectionStrengthTex.SampleLevel(linear_repeat_s, i.uv0, 0); diff --git a/tooner.shader b/tooner.shader index f6beeee..55ec40c 100644 --- a/tooner.shader +++ b/tooner.shader @@ -663,17 +663,22 @@ Shader "yum_food/tooner" _Gimmick_Gerstner_Water_k_x("Wavenumbers (x)", Vector) = (1, 1, 1, 1) _Gimmick_Gerstner_Water_k_y("Wavenumbers (y)", Vector) = (1, 1, 1, 1) _Gimmick_Gerstner_Water_t_f("Time factor", Vector) = (1, 1, 1, 1) + _Gimmick_Gerstner_Water_Color_Ramp_Mask("Color ramp mask", Vector) = (1, 1, 1, 1) _Gimmick_Gerstner_Water_a1("Amplitudes", Vector) = (0, 0, 0, 0) _Gimmick_Gerstner_Water_p1("Phases", Vector) = (0, 0, 0, 0) _Gimmick_Gerstner_Water_k_x1("Wavenumbers (x)", Vector) = (1, 1, 1, 1) _Gimmick_Gerstner_Water_k_y1("Wavenumbers (y)", Vector) = (1, 1, 1, 1) _Gimmick_Gerstner_Water_t_f1("Time factor", Vector) = (1, 1, 1, 1) + _Gimmick_Gerstner_Water_Color_Ramp_Mask1("Color ramp mask", Vector) = (1, 1, 1, 1) _Gimmick_Gerstner_Water_h("Mean water depth", Float) = 10 _Gimmick_Gerstner_Water_g("Gravity", Float) = 9.8 _Gimmick_Gerstner_Water_Scale("Scale", Vector) = (1000, 1000, .1) _Gimmick_Gerstner_Water_Origin_Damping_Direction("Origin damping direction", Float) = 1 + _Gimmick_Gerstner_Water_Color_Ramp("Color ramp", 2D) = "white" + _Gimmick_Gerstner_Water_Color_Ramp_Offset("Color ramp offset", Float) = 0.5 + _Gimmick_Gerstner_Water_Color_Ramp_Scale("Color ramp offset", Float) = 1 } SubShader { diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc index 87cf2e4..bcad86a 100644 --- a/tooner_lighting.cginc +++ b/tooner_lighting.cginc @@ -219,7 +219,7 @@ v2f vert(appdata v) // maxvertexcount == the number of vertices we create #if defined(_CLONES) -[maxvertexcount(45)] +[maxvertexcount(15)] #else [maxvertexcount(3)] #endif @@ -1296,15 +1296,6 @@ float4 effect(inout v2f i, out float depth) i.objPos.xyz = trochoid_map(theta, r0, z); } #endif -#if defined(_GIMMICK_GERSTNER_WATER) -#if defined(_EXPLODE) - if (_Explode_Phase < 1E-6) -#endif - { - GerstnerParams p = getGerstnerParams(); - i.normal = UnityObjectToWorldNormal(gerstner_frag(i.objPos.xyz, p)); - } -#endif #if defined(_UVSCROLL) float2 orig_uv = i.uv0; @@ -1319,6 +1310,22 @@ float4 effect(inout v2f i, out float depth) float4 albedo = _Color; #endif // _BASECOLOR_MAP +#if defined(_GIMMICK_GERSTNER_WATER) +#if defined(_EXPLODE) + if (_Explode_Phase < 1E-6) +#endif + { + GerstnerParams p = getGerstnerParams(); + GerstnerFragResult r = gerstner_frag(i.objPos.xyz, p); + i.normal = UnityObjectToWorldNormal(r.normal); + i.tangent = float4(UnityObjectToWorldDir(r.tangent.xyz), r.tangent.w); +#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP) + albedo.xyz *= r.color; + albedo.w = 1; +#endif + } +#endif + #if defined(_UVSCROLL) if (uv_scroll_mask) { float uv_scroll_alpha = _UVScroll_Alpha.SampleBias(linear_repeat_s, orig_uv, _Global_Sample_Bias); diff --git a/tooner_outline_pass.cginc b/tooner_outline_pass.cginc index 93ba73c..46a03f0 100644 --- a/tooner_outline_pass.cginc +++ b/tooner_outline_pass.cginc @@ -50,13 +50,16 @@ v2f vert(appdata v) float4 objPos = v.vertex; +#if defined(_OUTLINES) #if !defined(_SCROLL) && defined(_GIMMICK_GERSTNER_WATER) { GerstnerParams p = getGerstnerParams(); objPos.xyz = gerstner_vert(objPos.xyz, p); - v.normal = gerstner_frag(objPos.xyz, p); + GerstnerFragResult r = gerstner_frag(objPos.xyz, p); + v.normal = r.normal; } #endif +#endif #if defined(_OUTLINES) float outline_mask = _Outline_Mask.SampleLevel(linear_repeat_s, v.uv0.xy, /*lod=*/0); -- cgit v1.2.3