diff options
| author | yum <yum.food.vr@gmail.com> | 2025-11-07 18:50:45 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2025-11-07 18:50:45 -0800 |
| commit | e7008baac77c82d2865e0d54928269528be034d2 (patch) | |
| tree | 32e1f427a7b84102e8d7aea969517b1836d34381 | |
| parent | 0e0641580d9b492c90e6257baad4d28670d0bae2 (diff) | |
meow
| -rw-r--r-- | 2ner.cginc | 6 | ||||
| -rw-r--r-- | 2ner.shader | 11 | ||||
| -rw-r--r-- | decals.cginc | 4 | ||||
| -rw-r--r-- | features.cginc | 1 | ||||
| -rw-r--r-- | globals.cginc | 3 | ||||
| -rw-r--r-- | yum_brdf.cginc | 105 | ||||
| -rw-r--r-- | yum_pbr.cginc | 7 |
7 files changed, 117 insertions, 20 deletions
@@ -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; |
