summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2025-11-07 18:50:45 -0800
committeryum <yum.food.vr@gmail.com>2025-11-07 18:50:45 -0800
commite7008baac77c82d2865e0d54928269528be034d2 (patch)
tree32e1f427a7b84102e8d7aea969517b1836d34381
parent0e0641580d9b492c90e6257baad4d28670d0bae2 (diff)
meow
-rw-r--r--2ner.cginc6
-rw-r--r--2ner.shader11
-rw-r--r--decals.cginc4
-rw-r--r--features.cginc1
-rw-r--r--globals.cginc3
-rw-r--r--yum_brdf.cginc105
-rw-r--r--yum_pbr.cginc7
7 files changed, 117 insertions, 20 deletions
diff --git a/2ner.cginc b/2ner.cginc
index 112f12f..39d0fa8 100644
--- a/2ner.cginc
+++ b/2ner.cginc
@@ -494,12 +494,6 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace
float4 lit = YumBRDF(i, l, pbr);
#endif
- [branch]
- if (_UdonLightVolumeEnabled) {
- lit.rgb += LightVolumeSpecular(pbr.albedo, pbr.smoothness, pbr.metallic,
- pbr.normal, l.view_dir, l.L00, l.L01r, l.L01g, l.L01b);
- }
-
#if defined(_HARNACK_TRACING)
pbr.albedo = harnack_output.color;
pbr.smoothness = 0;
diff --git a/2ner.shader b/2ner.shader
index 59c7bbe..236138e 100644
--- a/2ner.shader
+++ b/2ner.shader
@@ -63,6 +63,7 @@ Shader "yum_food/2ner"
//ifex _Detail_Maps_Enabled==0
[HideInInspector] m_start_Detail_Maps("Detail maps", Float) = 0
[ThryToggle(_DETAIL_MAPS)]_Detail_Maps_Enabled("Enable", Float) = 0
+ _Detail_Maps_UV_Channel("UV channel", Range(0, 3.1)) = 0
_DetailMask("Mask", 2D) = "white" {}
_DetailAlbedoMap("Base color", 2D) = "white" {}
[Normal]_DetailNormalMap("Normals", 2D) = "bump" {}
@@ -83,7 +84,9 @@ Shader "yum_food/2ner"
//ifex _Clearcoat_Enabled==0
[HideInInspector] m_start_Clearcoat("Clearcoat", Float) = 0
[ThryToggle(_CLEARCOAT)]_Clearcoat_Enabled("Enable", Float) = 0
- _Clearcoat_Strength("Strength", Range(0, 1)) = 1
+ [ThryToggle(_CLEARCOAT_GEOMETRIC_NORMALS)]_Clearcoat_Geometric_Normals_Enabled("Use geometric normals", Float) = 1
+ _Clearcoat_Mask("Mask", 2D) = "white" {}
+ _Clearcoat_Strength("Strength", Range(0, 10)) = 1
_Clearcoat_Roughness("Roughness", Range(0.089, 1)) = 0.089
[HideInInspector] m_end_Clearcoat("Clearcoat", Float) = 0
//endex
@@ -1059,9 +1062,9 @@ Shader "yum_food/2ner"
//ifex _Oklch_Correction_Enabled==0
[HideInInspector] m_start_Oklch_Correction("Oklch", Float) = 0
[ThryToggle(_OKLCH_CORRECTION)] _Oklch_Correction_Enabled("Enable", Float) = 0
- _Oklch_Correction_L("L", Float) = 1
- _Oklch_Correction_C("C", Float) = 1
- _Oklch_Correction_H("H", Float) = 1
+ _Oklch_Correction_L("L", Range(0,1)) = 1
+ _Oklch_Correction_C("C", Range(0,1)) = 1
+ _Oklch_Correction_H("H", Range(0,1)) = 1
[HideInInspector] m_end_Oklch_Correction("Oklch", Float) = 0
//endex
//ifex _Oklab_Brightness_Clamp_Enabled==0
diff --git a/decals.cginc b/decals.cginc
index 80f5a96..ecfe156 100644
--- a/decals.cginc
+++ b/decals.cginc
@@ -82,7 +82,7 @@ float2 applyDomainWarping(DecalParams params, float2 uv) {
[loop]
for (uint ii = 0; ii < (uint) params.domain_warping_octaves; ii++) {
float2 noise_uv = warped_uv * frequency + time_vec * frequency;
- float2 noise_sample = params.domain_warping_noise.SampleLevel(trilinear_repeat_s, noise_uv, 0);
+ float2 noise_sample = params.domain_warping_noise.SampleLevel(linear_repeat_s, noise_uv, 0);
float2 noise_offset = (noise_sample.xy * 2.0 - 1.0);
total_offset += noise_offset * amplitude;
frequency *= 2.0;
@@ -178,7 +178,7 @@ float4 getCmykWarpingPlanesColor(DecalParams params, float2 uv) {
#define APPLY_DECAL_SDF_OFF(i, albedo, normal_tangent, metallic, smoothness, emission, params) \
float4 decal_albedo; \
{ \
- decal_albedo = params.mainTex.Sample(trilinear_repeat_s, decal_uv); \
+ decal_albedo = params.mainTex.Sample(trilinear_aniso4_repeat_s, decal_uv); \
decal_albedo *= params.color; \
}
diff --git a/features.cginc b/features.cginc
index a25bdce..8467c62 100644
--- a/features.cginc
+++ b/features.cginc
@@ -60,6 +60,7 @@
//ifex _Clearcoat_Enabled==0
#pragma shader_feature_local _CLEARCOAT
+#pragma shader_feature_local _CLEARCOAT_GEOMETRIC_NORMALS
//endex
//ifex _Metallics_Enabled==0
diff --git a/globals.cginc b/globals.cginc
index 4132e88..25b5fc6 100644
--- a/globals.cginc
+++ b/globals.cginc
@@ -26,6 +26,7 @@ SamplerState linear_repeat_s;
SamplerState bilinear_repeat_s;
SamplerState linear_clamp_s;
SamplerState trilinear_repeat_s;
+SamplerState trilinear_aniso4_repeat_s;
sampler2D _MainTex;
float4 _MainTex_ST;
@@ -69,6 +70,7 @@ float _OcclusionStrength;
#if defined(_DETAIL_MAPS)
texture2D _DetailMask;
sampler2D _DetailAlbedoMap;
+float _Detail_Maps_UV_Channel;
float4 _DetailAlbedoMap_ST;
sampler2D _DetailNormalMap;
float4 _DetailNormalMap_ST;
@@ -120,6 +122,7 @@ float4 _MetallicGlossMap_ST;
#endif
#if defined(_CLEARCOAT)
+texture2D _Clearcoat_Mask;
float _Clearcoat_Strength;
float _Clearcoat_Roughness;
#endif
diff --git a/yum_brdf.cginc b/yum_brdf.cginc
index 6a9031f..5cf962b 100644
--- a/yum_brdf.cginc
+++ b/yum_brdf.cginc
@@ -89,6 +89,19 @@ float4 YumBRDF(v2f i, const YumLighting light, YumPbr pbr) {
const float NoH = saturate(dot(pbr.normal, h));
const float VoL = saturate(dot(light.view_dir, light.dir));
+#if defined(_CLEARCOAT) && (defined(FORWARD_BASE_PASS) || defined(FORWARD_ADD_PASS))
+ // Clearcoat uses geometric normal (not perturbed by normal maps)
+#if defined(_CLEARCOAT_GEOMETRIC_NORMALS)
+ const float3 cc_normal = normalize(i.normal);
+#else
+ const float3 cc_normal = pbr.normal;
+#endif
+ const float NoH_cc = saturate(dot(cc_normal, h));
+ const float NoL_cc = saturate(dot(cc_normal, light.dir));
+ const float NoV_cc = max(1E-4, dot(cc_normal, light.view_dir));
+ const float cc_mask = _Clearcoat_Mask.SampleLevel(linear_repeat_s, i.uv01.xy, 0);
+#endif
+
#if defined(_MATERIAL_TYPE_CLOTH)
// Cloth specific BRDF
float3 direct_cloth;
@@ -118,6 +131,24 @@ float4 YumBRDF(v2f i, const YumLighting light, YumPbr pbr) {
float3 direct_standard;
{
+ float remainder = 1.0f;
+
+#if defined(_CLEARCOAT) && (defined(FORWARD_BASE_PASS) || defined(FORWARD_ADD_PASS))
+ float cc_f0 = 0.04f;
+ float cc_roughness = _Clearcoat_Roughness * _Clearcoat_Roughness; // Convert perceptual to linear
+
+ float Fcc = F_Schlick(cc_f0, LoH).x * cc_mask * _Clearcoat_Strength;
+ float Dcc = D_GGX(cc_roughness, NoH_cc, h);
+ float Vcc = V_SmithGGXCorrelated_Fast(cc_roughness, NoV_cc, NoL_cc);
+
+ float3 direct_specular_cc = Dcc * Vcc * Fcc * light.direct * NoL_cc * PI * light.attenuation;
+ direct_specular_cc = max(0, direct_specular_cc);
+
+ // Energy conservation: reduce base layer contribution by clearcoat Fresnel
+ remainder -= Fcc * _Clearcoat_Strength;
+ remainder = max(0, remainder);
+#endif
+
const float dielectric_f0 = computeDielectricF0(_reflectance);
const float3 f0 = lerp(dielectric_f0, pbr.albedo, pbr.metallic);
const float3 dfg = PrefilteredDFG_LUT(pbr.roughness_perceptual, NoV);
@@ -129,13 +160,16 @@ float4 YumBRDF(v2f i, const YumLighting light, YumPbr pbr) {
// Fd_Burley already includes 1/PI, so multiply by PI to match Unity intensities
float3 Fd = diffuseColor * Fd_Burley(pbr.roughness, NoV, NoL_wrapped_d, LoH) * PI;
- Fd *= light.attenuation * pbr.ao;
+ Fd *= light.attenuation * pbr.ao * remainder;
// Multiply by PI to match Unity intensities (same as Filament's implementation)
- float3 Fr = specularLobe(pbr, f0, h, LoH, NoH, NoV, NoL_wrapped_s) * PI * light.attenuation;
+ float3 Fr = specularLobe(pbr, f0, h, LoH, NoH, NoV, NoL_wrapped_s) * PI * light.attenuation * remainder;
// Apply energy compensation to specular term
float3 color = Fd * NoL_wrapped_d + Fr * energy_compensation * NoL_wrapped_s;
+#if defined(_CLEARCOAT) && (defined(FORWARD_BASE_PASS) || defined(FORWARD_ADD_PASS))
+ color += direct_specular_cc;
+#endif
direct_standard = color * light.direct;
}
@@ -159,6 +193,49 @@ float4 YumBRDF(v2f i, const YumLighting light, YumPbr pbr) {
float3 indirect_standard;
{
+ float remainder = 1.0f;
+
+#if defined(_CLEARCOAT) && (defined(FORWARD_BASE_PASS) || defined(FORWARD_ADD_PASS))
+ // Clearcoat indirect specular
+ float cc_f0 = 0.04f;
+ float cc_roughness_perceptual = _Clearcoat_Roughness;
+
+ // Sample environment for clearcoat reflection using geometric normal
+#if defined(_CLEARCOAT_GEOMETRIC_NORMALS)
+ float3 cc_reflect_dir = reflect(-light.view_dir, normalize(i.normal));
+#else
+ float3 cc_reflect_dir = reflect(-light.view_dir, cc_normal);
+#endif
+
+ UnityGIInput cc_data;
+ cc_data.worldPos = i.worldPos;
+ cc_data.worldViewDir = light.view_dir;
+ cc_data.probeHDR[0] = unity_SpecCube0_HDR;
+ cc_data.probeHDR[1] = unity_SpecCube1_HDR;
+#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
+ cc_data.boxMin[0] = unity_SpecCube0_BoxMin;
+#endif
+#ifdef UNITY_SPECCUBE_BOX_PROJECTION
+ cc_data.boxMax[0] = unity_SpecCube0_BoxMax;
+ cc_data.probePosition[0] = unity_SpecCube0_ProbePosition;
+ cc_data.boxMax[1] = unity_SpecCube1_BoxMax;
+ cc_data.boxMin[1] = unity_SpecCube1_BoxMin;
+ cc_data.probePosition[1] = unity_SpecCube1_ProbePosition;
+#endif
+
+ float3 cc_env_refl = UnityGI_prefilteredRadiance(cc_data, cc_roughness_perceptual, cc_reflect_dir);
+#if defined(_BRIGHTNESS_CONTROL)
+ cc_env_refl *= _Brightness_Multiplier;
+#endif
+
+ // Clearcoat Fresnel for view angle
+ float Fcc = F_Schlick(cc_f0, NoV_cc).x * cc_mask * _Clearcoat_Strength;
+ float3 indirect_specular_cc = Fcc * cc_env_refl;
+
+ // Energy conservation
+ remainder *= (1.0f - Fcc * _Clearcoat_Strength);
+#endif
+
const float dielectric_f0 = computeDielectricF0(_reflectance);
const float3 f0 = lerp(dielectric_f0, pbr.albedo, pbr.metallic);
const float3 dfg = PrefilteredDFG_LUT(pbr.roughness_perceptual, NoV);
@@ -170,11 +247,14 @@ float4 YumBRDF(v2f i, const YumLighting light, YumPbr pbr) {
// Use proper diffuse color calculation
float3 diffuseColor = computeDiffuseColor(pbr.albedo, pbr.metallic);
- float3 Fd = diffuseColor * light.diffuse * (1.0 - E) * pbr.ao;
+ float3 Fd = diffuseColor * light.diffuse * (1.0 - E) * pbr.ao * remainder;
- float3 Fr = E * light.specular;
+ float3 Fr = E * light.specular * remainder;
indirect_standard = Fr + Fd;
+#if defined(_CLEARCOAT) && (defined(FORWARD_BASE_PASS) || defined(FORWARD_ADD_PASS))
+ indirect_standard += indirect_specular_cc;
+#endif
}
#if defined(_MATERIAL_TYPE_CLOTH)
@@ -186,7 +266,22 @@ float4 YumBRDF(v2f i, const YumLighting light, YumPbr pbr) {
float3 indirect = indirect_standard;
#endif
- return float4(direct + indirect, pbr.albedo.a);
+ float4 lit = float4(direct + indirect, pbr.albedo.a);
+
+ float3 lv_specular = 0;
+ [branch]
+ if (_UdonLightVolumeEnabled) {
+ float3 lv_specular = LightVolumeSpecular(pbr.albedo, pbr.smoothness, pbr.metallic,
+ pbr.normal, light.view_dir, light.L00, light.L01r, light.L01g, light.L01b);
+ lit.rgb += lv_specular;
+
+#if defined(_CLEARCOAT) && (defined(FORWARD_BASE_PASS) || defined(FORWARD_ADD_PASS))
+ float Fcc = F_Schlick(0.04f, NoV_cc) * cc_mask * _Clearcoat_Strength;
+ lit.rgb += lv_specular * Fcc;
+#endif
+ }
+
+ return lit;
}
#endif // __YUM_BRDF_INC
diff --git a/yum_pbr.cginc b/yum_pbr.cginc
index 5baff19..b6969f7 100644
--- a/yum_pbr.cginc
+++ b/yum_pbr.cginc
@@ -195,12 +195,13 @@ YumPbr GetYumPbr(v2f i, float3x3 tangentToWorld) {
tex2D(_BumpMap, UV_SCOFF_IMPL(raw_uv, _BumpMap_ST)), _BumpScale);
#if defined(_DETAIL_MAPS)
- float detail_mask = _DetailMask.SampleLevel(point_repeat_s, i.uv01.xy, 0);
+ float2 detail_uv = get_uv_by_channel(i, _Detail_Maps_UV_Channel);
+ float detail_mask = _DetailMask.SampleLevel(point_repeat_s, detail_uv, 0);
float4 detail_albedo = tex2D(_DetailAlbedoMap,
- UV_SCOFF_IMPL(raw_uv, _DetailNormalMap_ST));
+ UV_SCOFF_IMPL(detail_uv, _DetailAlbedoMap_ST));
float3 detail_normal = UnpackScaleNormal(
tex2D(_DetailNormalMap,
- UV_SCOFF_IMPL(raw_uv, _DetailNormalMap_ST)),
+ UV_SCOFF_IMPL(detail_uv, _DetailNormalMap_ST)),
_DetailNormalMapScale);
result.albedo = lerp(result.albedo, result.albedo * detail_albedo, detail_mask);
//result.albedo.a *= detail_albedo.a;