From 97ee1dcf26b62f48e351b6392c11a30775619442 Mon Sep 17 00:00:00 2001 From: yum Date: Wed, 21 Jan 2026 16:03:52 -0800 Subject: Fur: add domain warping --- 2ner.cginc | 18 ++++++++---------- 2ner.shader | 6 ++++++ features.cginc | 1 + globals.cginc | 5 +++++ interpolators.cginc | 1 + math.cginc | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++-- ssao.cginc | 4 ++-- yum_pbr.cginc | 11 +++++++++-- 8 files changed, 84 insertions(+), 16 deletions(-) diff --git a/2ner.cginc b/2ner.cginc index 0df4f17..3835002 100644 --- a/2ner.cginc +++ b/2ner.cginc @@ -257,7 +257,7 @@ void geom(triangle v2f input[3], inout TriangleStream stream) { o.vertexLight.w = t; stream.Append(o); } - stream.RestartStrip(); + // We do not restart strips. Looks a little nicer. } #else stream.Append(input[0]); @@ -294,6 +294,11 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace f.binormal = cross(i.tangent, i.normal); f.eyeVec = i.worldPos - _WorldSpaceCameraPos; f.viewDir = normalize(f.eyeVec); + f.tbn = float3x3( + i.tangent, + f.binormal, + i.normal + ); #if defined(_RAYMARCHED_FOG) { @@ -429,19 +434,12 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace #endif #endif - float4x4 tangentToWorld = float4x4( - float4(i.tangent, 0), - float4(f.binormal, 0), - float4(i.normal, 0), - float4(0, 0, 0, 1) - ); - float ssao = 1; #if defined(_SSAO) float2 debug; - ssao = get_ssao(i, tangentToWorld, debug); + ssao = get_ssao(i, f, debug); #endif - YumPbr pbr = GetYumPbr(i, f, tangentToWorld); + YumPbr pbr = GetYumPbr(i, f); pbr.albedo.rgb *= ssao; #if defined(META_PASS) diff --git a/2ner.shader b/2ner.shader index 357f372..6cac4f9 100644 --- a/2ner.shader +++ b/2ner.shader @@ -121,6 +121,12 @@ Shader "yum_food/2ner" _Fur_Mask("Mask", 2D) = "white" {} [HideInInspector] m_end_Fur_Mask("Mask", Float) = 0 + [HideInInspector] m_start_Fur_Warping("Warping", Float) = 0 + [ThryToggle(_FUR_WARPING)]_Fur_Warping_Enabled("Enable", Float) = 0 + _Fur_Warping_Strength("Strength", Range(0, 10)) = 1 + _Fur_Warping_Frequency("Frequency", Float) = 1 + [HideInInspector] m_end_Fur_Warping("Warping", Float) = 0 + // Shit for thry [HideInInspector] GeometryShader_Enabled("Enabled", Float) = 1 [HideInInspector] GeometryShader_EnabledForwardBase("Enabled (ForwardBase)", Float) = 1 diff --git a/features.cginc b/features.cginc index c774103..ab45306 100644 --- a/features.cginc +++ b/features.cginc @@ -77,6 +77,7 @@ //ifex _Fur_Enabled==0 #pragma shader_feature_local _FUR #pragma shader_feature_local _FUR_MASK +#pragma shader_feature_local _FUR_WARPING //endex //ifex _Matcap0_Enabled==0 diff --git a/globals.cginc b/globals.cginc index 4bc39b4..00f9a31 100644 --- a/globals.cginc +++ b/globals.cginc @@ -157,6 +157,11 @@ texture2D _Fur_Mask; float4 _Fur_Mask_ST; #endif +#if defined(_FUR_WARPING) +float _Fur_Warping_Strength; +float _Fur_Warping_Frequency; +#endif + #define MATCAP_MODE_REPLACE 0 #define MATCAP_MODE_ADD 1 #define MATCAP_MODE_MULTIPLY 2 diff --git a/interpolators.cginc b/interpolators.cginc index bb08c4e..020c80f 100644 --- a/interpolators.cginc +++ b/interpolators.cginc @@ -47,6 +47,7 @@ struct f2f { float3 binormal; float3 eyeVec; float3 viewDir; + float3x3 tbn; }; #endif // __INTERPOLATORS_INC diff --git a/math.cginc b/math.cginc index 3112418..cbf162c 100644 --- a/math.cginc +++ b/math.cginc @@ -307,7 +307,57 @@ float2 hex_to_cart(float3 cart) { (cart[1] - cart[2]) * SQRT_3_OVER_2); } -// Rotate 45 degrees. -float2 rot45(float2 v) { return float2(v.x - v.y, v.x + v.y) * RCP_SQRT_2; } +// Rotate 45 degrees. +float2 rot45(float2 v) { return float2(v.x - v.y, v.x + v.y) * RCP_SQRT_2; } + +// p = point to get noise for +float valueNoise2D( + float2 p) { + // quantized part + float2 q = floor(p); + // fractional part + float2 f = frac(p); + + float l00 = rand2(q); + float l01 = rand2(q + float2(0, 1)); + float l10 = rand2(q + float2(1, 0)); + float l11 = rand2(q + float2(1, 1)); + + // Cubic interpolation. + f = f * f * (3.0f - 2.0f * f); + + float l0 = lerp(l00, l01, f.y); + float l1 = lerp(l10, l11, f.y); + return lerp(l0, l1, f.x); +} + +// p = point to get noise for +float valueNoise3D( + float3 p) { + // quantized part + float3 q = floor(p); + // fractional part + float3 f = frac(p); + + float l000 = rand3(q); + float l001 = rand3(q + float3(0, 0, 1)); + float l010 = rand3(q + float3(0, 1, 0)); + float l011 = rand3(q + float3(0, 1, 1)); + float l100 = rand3(q + float3(1, 0, 0)); + float l101 = rand3(q + float3(1, 0, 1)); + float l110 = rand3(q + float3(1, 1, 0)); + float l111 = rand3(q + float3(1, 1, 1)); + + // Cubic interpolation. + f = f * f * (3.0f - 2.0f * f); + + float l00 = lerp(l000, l001, f.z); + float l01 = lerp(l010, l011, f.z); + float l10 = lerp(l100, l101, f.z); + float l11 = lerp(l110, l111, f.z); + float l0 = lerp(l00, l01, f.y); + float l1 = lerp(l10, l11, f.y); + return lerp(l0, l1, f.x); +} #endif // __MATH_INC diff --git a/ssao.cginc b/ssao.cginc index f8d7e0d..753c4ee 100644 --- a/ssao.cginc +++ b/ssao.cginc @@ -6,7 +6,7 @@ #include "interpolators.cginc" #if defined(_SSAO) -float get_ssao(v2f i, float3x3 tangentToWorld, out float2 debug) { +float get_ssao(v2f i, f2f f, out float2 debug) { float3 objPos = mul(unity_WorldToObject, float4(i.worldPos, 1)); float4 clipPos = UnityObjectToClipPos(objPos); float4 screenPos = ComputeScreenPos(clipPos); @@ -47,7 +47,7 @@ float get_ssao(v2f i, float3x3 tangentToWorld, out float2 debug) { sample_point.xy = mul(ssao_rot, sample_point.xy); // Remap to world space. - sample_point = mul(sample_point, tangentToWorld); + sample_point = mul(sample_point, f.tbn); float scale = (ii * 1.0f) / _SSAO_Samples; sample_point *= lerp(0.1f, 1.0f, scale * scale) * _SSAO_Radius; diff --git a/yum_pbr.cginc b/yum_pbr.cginc index f9a29c3..515aef9 100644 --- a/yum_pbr.cginc +++ b/yum_pbr.cginc @@ -142,6 +142,13 @@ float FurClip(v2f i, f2f f, inout YumPbr result) { #if defined(_FUR) float fur_layer = i.vertexLight.w; float2 fur_uv = i.uv01.xy * _Fur_Heightmap_ST.xy; + +#if defined(_FUR_WARPING) + float2 vnoise = valueNoise3D(i.objPos * _Fur_Warping_Frequency); + float3 vnoise_tbn = mul(vnoise, f.tbn); + fur_uv += vnoise_tbn.xy * (_Fur_Warping_Strength / _Fur_Warping_Frequency); +#endif + float fur_thickness = _Fur_Heightmap.SampleBias( trilinear_aniso4_repeat_s, fur_uv, _Fur_Heightmap_Mip_Bias).r; @@ -152,7 +159,7 @@ float FurClip(v2f i, f2f f, inout YumPbr result) { #endif } -YumPbr GetYumPbr(v2f i, f2f f, float3x3 tangentToWorld) { +YumPbr GetYumPbr(v2f i, f2f f) { YumPbr result = (YumPbr)0; float fur_thickness = FurClip(i, f, result); @@ -280,7 +287,7 @@ YumPbr GetYumPbr(v2f i, f2f f, float3x3 tangentToWorld) { result.albedo.rgb = OKLABtoLRGB(lab); #endif - result.normal = normalize(mul(normal_tangent, tangentToWorld)); + result.normal = normalize(mul(normal_tangent, f.tbn)); #if defined(_GRADIENT_NORMALS) applyGradientNormals(i, result); -- cgit v1.2.3