From ffb4b6b861a7f4a5c2468824e16872883f64c290 Mon Sep 17 00:00:00 2001 From: yum Date: Tue, 20 Jan 2026 22:01:22 -0800 Subject: Add fur shader, and begin slimming interpolators --- 2ner.cginc | 51 +++++++++++++++++++++++++++++++++++++---- 2ner.shader | 57 ++++++++++++++++++++++++++++++++++++++++++++++ UnityStandardMeta.cginc | 3 ++- decals.cginc | 2 +- features.cginc | 13 +++++++++++ globals.cginc | 13 +++++++++++ interpolators.cginc | 18 ++++++++------- mochie_shadow_caster.cginc | 2 ++ tessellation.cginc | 12 ++++++---- yum_lighting.cginc | 7 +++--- yum_pbr.cginc | 6 +++++ 11 files changed, 162 insertions(+), 22 deletions(-) diff --git a/2ner.cginc b/2ner.cginc index a4ef84a..714930f 100644 --- a/2ner.cginc +++ b/2ner.cginc @@ -193,7 +193,6 @@ v2f vert(appdata v) { // These are used to convert normals from tangent space to world space. o.normal = v.normal; o.tangent = v.tangent.xyz; - o.binormal = cross(o.normal, o.tangent) * v.tangent.w; UNITY_TRANSFER_LIGHTING(o, v.uv1); UNITY_TRANSFER_FOG_COMBINED_WITH_EYE_VEC(o, o.pos); @@ -202,8 +201,10 @@ v2f vert(appdata v) { TRANSFER_SHADOW_CASTER_NORMALOFFSET(o); #endif +#if defined(V2F_COLOR) // Vertex color o.color = v.color; +#endif // Calculate vertex lights #ifdef VERTEXLIGHT_ON @@ -225,6 +226,50 @@ v2f vert(appdata v) { return o; } +//ifex _Fur_Enabled==0 +[maxvertexcount(3 * 9)] +void geom(triangle v2f input[3], inout TriangleStream stream) { +#if defined(_FUR) +#if defined(_FUR_MASK) + float fur_mask = _Fur_Mask.SampleLevel(bilinear_repeat_s, input[0].uv01.xy * _Fur_Mask_ST.xy, 0); +#else + float fur_mask = 1; +#endif + [branch] + if (fur_mask < 0.5) { + stream.Append(input[0]); + stream.Append(input[1]); + stream.Append(input[2]); + stream.RestartStrip(); + return; + } + + [loop] + for (int layer = 0; layer < _Fur_Layers; layer++) { + float t = (float) layer / (float) max(_Fur_Layers - 1, 1); + float offset = t * _Fur_Thickness; + + [unroll] + for (int i = 0; i < 3; i++) { + v2f o = input[i]; + float3 normal_ws = UnityObjectToWorldNormal(o.normal); + o.worldPos.xyz += normal_ws * offset; + o.objPos.xyz += o.normal * offset; + o.pos = UnityWorldToClipPos(o.worldPos); + o.vertexLight.w = layer; + stream.Append(o); + } + stream.RestartStrip(); + } +#else + stream.Append(input[0]); + stream.Append(input[1]); + stream.Append(input[2]); + stream.RestartStrip(); +#endif // _FUR +} +//endex + float4 frag(v2f i, uint facing : SV_IsFrontFace #if defined(_HARNACK_TRACING) || defined(_SHATTER_WAVE) || defined(_VERTEX_DOMAIN_WARPING) || (defined(_CUSTOM30) && !defined(_DEPTH_PREPASS)) || defined(_RAYMARCHED_FOG) || defined(_TESSELLATION_HEIGHTMAP) , out float depth : SV_DepthLessEqual @@ -242,12 +287,10 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace i.normal *= facing ? 1 : -1; i.normal = UnityObjectToWorldNormal(i.normal); i.tangent = mul(unity_ObjectToWorld, i.tangent); - i.binormal = mul(unity_ObjectToWorld, i.binormal); // Not necessarily normalized after interpolation i.normal = normalize(i.normal); i.tangent = normalize(i.tangent); - i.binormal = normalize(i.binormal); #if defined(_RAYMARCHED_FOG) { @@ -385,7 +428,7 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace float4x4 tangentToWorld = float4x4( float4(i.tangent, 0), - float4(i.binormal, 0), + float4(cross(i.tangent, i.normal), 0), float4(i.normal, 0), float4(0, 0, 0, 1) ); diff --git a/2ner.shader b/2ner.shader index d5e0d6c..987a990 100644 --- a/2ner.shader +++ b/2ner.shader @@ -107,6 +107,27 @@ Shader "yum_food/2ner" [HideInInspector] m_end_Outlines("Outlines", Float) = 0 //endex + //ifex _Fur_Enabled==0 + [HideInInspector] m_start_Fur("Fur", Float) = 0 + [ThryToggle(_FUR)]_Fur_Enabled("Enable", Float) = 0 + _Fur_Thickness("Thickness", Float) = 1 + [IntRange] _Fur_Layers("Layers", Range(1, 12)) = 1 + _Fur_Heightmap("Heightmap", 2D) = "black" {} + _Fur_Heightmap_Mip_Bias("Heightmap mip bias", Range(-4, 4)) = 0 + + [HideInInspector] m_start_Fur_Mask("Mask", Float) = 0 + [ThryToggle(_FUR_MASK)]_Fur_Mask_Enabled("Enable", Float) = 0 + _Fur_Mask("Mask", 2D) = "white" {} + [HideInInspector] m_end_Fur_Mask("Mask", Float) = 0 + + // Shit for thry + [HideInInspector] GeometryShader_Enabled("Enabled", Float) = 1 + [HideInInspector] GeometryShader_EnabledForwardBase("Enabled (ForwardBase)", Float) = 1 + [HideInInspector] GeometryShader_EnabledForwardAdd("Enabled (ForwardAdd)", Float) = 1 + [HideInInspector] GeometryShader_EnabledShadowCaster("Enabled (ShadowCaster)", Float) = 1 + [HideInInspector] m_end_Fur("Fur", Float) = 0 + //endex + //ifex _Custom30_Enabled==0 [HideInInspector] m_start_Custom30("Custom 30", Float) = 0 [ThryToggle(_CUSTOM30)]_Custom30_Enabled("Enable", Float) = 0 @@ -2450,6 +2471,10 @@ Shader "yum_food/2ner" #pragma domain domain //endex + //ifex _Fur_Enabled==0 + #pragma geometry geom + //endex + #define DEPTH_PREPASS #include "2ner.cginc" @@ -2497,6 +2522,10 @@ Shader "yum_food/2ner" #pragma vertex vert #pragma fragment frag + //ifex _Fur_Enabled==0 + #pragma geometry geom + //endex + #define MASKED_STENCIL1_PASS #include "2ner.cginc" @@ -2544,6 +2573,10 @@ Shader "yum_food/2ner" #pragma vertex vert #pragma fragment frag + //ifex _Fur_Enabled==0 + #pragma geometry geom + //endex + #define MASKED_STENCIL2_PASS #include "2ner.cginc" @@ -2591,6 +2624,10 @@ Shader "yum_food/2ner" #pragma vertex vert #pragma fragment frag + //ifex _Fur_Enabled==0 + #pragma geometry geom + //endex + #define MASKED_STENCIL3_PASS #include "2ner.cginc" @@ -2638,6 +2675,10 @@ Shader "yum_food/2ner" #pragma vertex vert #pragma fragment frag + //ifex _Fur_Enabled==0 + #pragma geometry geom + //endex + #define MASKED_STENCIL4_PASS #include "2ner.cginc" @@ -2699,6 +2740,10 @@ Shader "yum_food/2ner" #pragma domain domain //endex + //ifex _Fur_Enabled==0 + #pragma geometry geom + //endex + #define FORWARD_BASE_PASS #include "2ner.cginc" @@ -2754,6 +2799,10 @@ Shader "yum_food/2ner" #pragma domain domain //endex + //ifex _Fur_Enabled==0 + #pragma geometry geom + //endex + #define FORWARD_ADD_PASS #include "2ner.cginc" @@ -2800,6 +2849,10 @@ Shader "yum_food/2ner" #pragma vertex vert #pragma fragment frag + //ifex _Fur_Enabled==0 + #pragma geometry geom + //endex + #define EXTRA_STENCIL_COLOR_PASS #include "2ner.cginc" @@ -2857,6 +2910,10 @@ Shader "yum_food/2ner" #pragma domain domain //endex + //ifex _Fur_Enabled==0 + #pragma geometry geom + //endex + #define OUTLINE_PASS #include "2ner.cginc" diff --git a/UnityStandardMeta.cginc b/UnityStandardMeta.cginc index 0fb21eb..89fcb61 100644 --- a/UnityStandardMeta.cginc +++ b/UnityStandardMeta.cginc @@ -105,8 +105,9 @@ float4 frag_meta (v2f_meta i) : SV_Target pbr_input.objPos = float4(i.objPos, 1.0); pbr_input.normal = i.normal; pbr_input.tangent = i.tangent; - pbr_input.binormal = i.binormal; +#if defined(V2F_COLOR) pbr_input.color = i.color; +#endif YumPbr pbr = GetYumPbr(pbr_input, tangentToWorld); diff --git a/decals.cginc b/decals.cginc index a26e045..1f50ce8 100644 --- a/decals.cginc +++ b/decals.cginc @@ -235,7 +235,7 @@ float3 calculateSdfSsn(DecalParams params, float2 decal_uv, float4 decal_albedo) #define DS_CLAMP_OFF(i, albedo, normal_tangent, metallic, smoothness, emission, params) {} #define DS_MASK_ON(i, albedo, normal_tangent, metallic, smoothness, emission, params) \ - float decal_mask = params.mask.SampleLevel(trilinear_aniso4_repeat_s, raw_decal_uv, params.mip_bias); \ + float decal_mask = params.mask.SampleBias(trilinear_aniso4_repeat_s, raw_decal_uv, params.mip_bias); \ decal_albedo.a *= decal_mask; #define DS_MASK_OFF(i, albedo, normal_tangent, metallic, smoothness, emission, params) \ diff --git a/features.cginc b/features.cginc index 803b7c6..c774103 100644 --- a/features.cginc +++ b/features.cginc @@ -74,6 +74,11 @@ #pragma shader_feature_local _OUTLINE_MASK //endex +//ifex _Fur_Enabled==0 +#pragma shader_feature_local _FUR +#pragma shader_feature_local _FUR_MASK +//endex + //ifex _Matcap0_Enabled==0 #pragma shader_feature_local _MATCAP0 #pragma shader_feature_local _MATCAP0_MASK @@ -523,5 +528,13 @@ #pragma shader_feature_local _LIGHT_VOLUMES_BRIGHTNESS //endex +#if defined(_CUSTOM30) +#define V2F_COLOR +#endif + +#if defined(_TROCHOID) +#define V2F_ORIG_POS +#endif + #endif // __FEATURES_INC diff --git a/globals.cginc b/globals.cginc index 39160bc..cfb7f07 100644 --- a/globals.cginc +++ b/globals.cginc @@ -143,6 +143,19 @@ float _Outline_Mask_Invert; #endif #endif +#if defined(_FUR) +float _Fur_Thickness; +int _Fur_Layers; +texture2D _Fur_Heightmap; +float4 _Fur_Heightmap_ST; +float _Fur_Heightmap_Mip_Bias; +#endif + +#if defined(_FUR_MASK) +texture2D _Fur_Mask; +float4 _Fur_Mask_ST; +#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 4e222e8..33bc0bc 100644 --- a/interpolators.cginc +++ b/interpolators.cginc @@ -27,14 +27,16 @@ struct v2f { float3 worldPos : TEXCOORD3; float3 normal : TEXCOORD4; float3 tangent : TEXCOORD5; - float3 binormal : TEXCOORD6; - float4 eyeVec : TEXCOORD7; // eyeVec.xyz | fogCoord - float4 color : TEXCOORD8; - float3 vertexLight : TEXCOORD9; - UNITY_LIGHTING_COORDS(10,11) - -#if defined(_TROCHOID) - float3 orig_pos : TEXCOORD12; + float4 eyeVec : TEXCOORD6; // eyeVec.xyz | fogCoord + float4 vertexLight : TEXCOORD7; // vertexLight.xyz | furLayer + UNITY_LIGHTING_COORDS(8,9) + +#if defined(V2F_ORIG_POS) + float3 orig_pos : TEXCOORD10; +#endif + +#if defined(V2F_COLOR) + float4 color : TEXCOORD11; #endif UNITY_VERTEX_INPUT_INSTANCE_ID diff --git a/mochie_shadow_caster.cginc b/mochie_shadow_caster.cginc index 8a6ab59..6e8d19a 100644 --- a/mochie_shadow_caster.cginc +++ b/mochie_shadow_caster.cginc @@ -22,7 +22,9 @@ v2f vert(appdata v) o.uv23.xy = v.uv2; o.uv23.zw = v.uv3; o.objPos = v.vertex; +#if defined(V2F_COLOR) o.color = v.color; +#endif return o; } diff --git a/tessellation.cginc b/tessellation.cginc index c964598..1aba684 100644 --- a/tessellation.cginc +++ b/tessellation.cginc @@ -28,8 +28,9 @@ bool cullPatch(float4 p0, float4 p1, float4 p2, float bias) { #define _TESSELLATION_HEIGHTMAP #endif -float4 applyHeightmap(float4 objPos, float2 uv, float3 normal, float3 tangent, float3 binormal) { +float4 applyHeightmap(float4 objPos, float2 uv, float3 normal, float3 tangent) { #if defined(_TESSELLATION) && defined(_TESSELLATION_HEIGHTMAP) + float3 binormal = cross(tangent, normal); float3 height = 0; #if defined(_TESSELLATION_HEIGHTMAP_0) float3 heightmap_0_sample = _Tessellation_Heightmap_0.SampleLevel(bilinear_repeat_s, @@ -168,12 +169,13 @@ v2f domain( #endif o.normal = DOMAIN_INTERP(normal); o.tangent = DOMAIN_INTERP(tangent); - o.binormal = DOMAIN_INTERP(binormal); o.uv01 = DOMAIN_INTERP(uv01); o.uv23 = DOMAIN_INTERP(uv23); - o.color = DOMAIN_INTERP(color); o.vertexLight = DOMAIN_INTERP(vertexLight); -#if defined(_TROCHOID) +#if defined(V2F_COLOR) + o.color = DOMAIN_INTERP(color); +#endif +#if defined(V2F_ORIG_POS) o.orig_pos = DOMAIN_INTERP(orig_pos); #endif @@ -189,7 +191,7 @@ v2f domain( #endif #endif - o.objPos = applyHeightmap(o.objPos, o.uv01.xy, o.normal, o.tangent, o.binormal); + o.objPos = applyHeightmap(o.objPos, o.uv01.xy, o.normal, o.tangent); o.pos = UnityObjectToClipPos(o.objPos); o.worldPos = mul(unity_ObjectToWorld, o.objPos).xyz; diff --git a/yum_lighting.cginc b/yum_lighting.cginc index a0a4a2e..b8dcf31 100644 --- a/yum_lighting.cginc +++ b/yum_lighting.cginc @@ -347,8 +347,9 @@ YumLighting GetYumLighting(v2f i, YumPbr pbr) { // Calculate attenuation first, before diffuse lighting light.attenuation = getShadowAttenuation(i); - float3 tangentNormal = mul(pbr.normal, transpose(float3x3(i.tangent, i.binormal, i.normal))); - float3x3 tangentToWorld = float3x3(i.tangent, i.binormal, i.normal); + float3 binormal = cross(i.tangent, i.normal); + float3 tangentNormal = mul(pbr.normal, transpose(float3x3(i.tangent, binormal, i.normal))); + float3x3 tangentToWorld = float3x3(i.tangent, binormal, i.normal); // Use Bakery-aware irradiance function #if defined(LIGHTMAP_ON) @@ -367,7 +368,7 @@ YumLighting GetYumLighting(v2f i, YumPbr pbr) { light.diffuse.gb = light.diffuse.r; #endif #else - light.diffuse = getIndirectDiffuse(i, pbr.normal, float4(i.vertexLight, 0), light); + light.diffuse = getIndirectDiffuse(i, pbr.normal, float4(i.vertexLight.xyz, 0), light); light.occlusion = 1; #endif diff --git a/yum_pbr.cginc b/yum_pbr.cginc index cec42d2..e19c931 100644 --- a/yum_pbr.cginc +++ b/yum_pbr.cginc @@ -140,6 +140,12 @@ void applySeaFoam(v2f i, inout YumPbr pbr) { YumPbr GetYumPbr(v2f i, float3x3 tangentToWorld) { YumPbr result = (YumPbr)0; +#if defined(_FUR) + float fur_layer = i.vertexLight.w; + float fur_thickness = _Fur_Heightmap.SampleBias(trilinear_aniso4_repeat_s, i.uv01.xy * _Fur_Heightmap_ST.xy, _Fur_Heightmap_Mip_Bias).r; + clip(fur_thickness - fur_layer / _Fur_Layers); +#endif + float2 raw_uv = i.uv01.xy; #if defined(_UV_DOMAIN_WARPING) { -- cgit v1.2.3