diff options
| author | yum <yum.food.vr@gmail.com> | 2025-06-14 20:48:03 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2025-06-14 20:48:03 -0700 |
| commit | fbcd6a84b64018a93a3fd4e3e15260d921e93d8e (patch) | |
| tree | 24a762c1a0f2d8d1dace3418193d838b657e33cd | |
| parent | 60e1e2010ab5eaa01dfd00c30f91384f95a78aa2 (diff) | |
Add meta pass, limit fog to forward base, add fog dir/indir knobs
| -rw-r--r-- | 2ner.cginc | 16 | ||||
| -rw-r--r-- | 2ner.shader | 19 | ||||
| -rw-r--r-- | Scripts/BakeVertexData.py | 2 | ||||
| -rw-r--r-- | UnityStandardMeta.cginc | 169 | ||||
| -rw-r--r-- | fog.cginc | 60 | ||||
| -rw-r--r-- | globals.cginc | 2 |
6 files changed, 249 insertions, 19 deletions
@@ -34,6 +34,9 @@ v2f vert(appdata v) { // hide outlines when not locked.
return (v2f) (0.0/0.0);
#endif
+#if defined(_RAYMARCHED_FOG) && !defined(FORWARD_BASE_PASS)
+ return (v2f) (0.0/0.0);
+#endif
#if defined(DEPTH_PREPASS) && !defined(_DEPTH_PREPASS)
return (v2f) (0.0/0.0);
#endif
@@ -221,7 +224,7 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace i.tangent = UnityObjectToWorldNormal(i.tangent);
i.binormal = UnityObjectToWorldNormal(i.binormal);
-#if defined(_RAYMARCHED_FOG) && defined(FORWARD_BASE_PASS)
+#if defined(_RAYMARCHED_FOG)
{
// Many fields are overspecified as .rgb or .xyz. This is because thry's
// shader locker will inline those fields (incorrectly) as float4. Unity's
@@ -229,6 +232,8 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace // Overspecifying gets around the issue.
FogParams fog_params = {
_Raymarched_Fog_Color.rgb,
+ _Raymarched_Fog_Direct_Light_Intensity,
+ _Raymarched_Fog_Indirect_Light_Intensity,
_Raymarched_Fog_Steps,
_Raymarched_Fog_Y_Cutoff,
_Raymarched_Fog_Dithering_Noise,
@@ -301,6 +306,7 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace float4(i.tangent.z, i.binormal.z, i.normal.z, 0),
float4(0, 0, 0, 1)
);
+
#if defined(_CUSTOM30)
#if defined(FORWARD_BASE_PASS) || (!defined(_DEPTH_PREPASS) && defined(SHADOW_CASTER_PASS))
#if defined(_CUSTOM30_BASICCUBE)
@@ -340,6 +346,14 @@ float4 frag(v2f i, uint facing : SV_IsFrontFace YumPbr pbr = GetYumPbr(i, tangentToWorld);
pbr.ao *= ssao;
+#if defined(META_PASS)
+#if defined(_EMISSION)
+ return pbr.emission;
+#else
+ return 0;
+#endif
+#endif
+
#if defined(_HARNACK_TRACING)
HarnackTracingOutput harnack_output = HarnackTracing(i);
pbr.albedo = float4(1, 1, 1, 0.2);
diff --git a/2ner.shader b/2ner.shader index 3472187..8a8485c 100644 --- a/2ner.shader +++ b/2ner.shader @@ -830,6 +830,8 @@ Shader "yum_food/2ner" [ThryToggle(_RAYMARCHED_FOG)] _Raymarched_Fog_Enabled("Enable", Float) = 0 _Raymarched_Fog_Steps("Steps", Range(1, 32)) = 32 _Raymarched_Fog_Color("Color", Color) = (0.3, 0.3, 0.3, 1) + _Raymarched_Fog_Direct_Light_Intensity("Direct light intensity", Float) = 1 + _Raymarched_Fog_Indirect_Light_Intensity("Indirect light intensity", Float) = 1 _Raymarched_Fog_Dithering_Noise("Dithering noise", 2D) = "black" {} _Raymarched_Fog_Density_Noise("Density noise", 3D) = "black" {} _Raymarched_Fog_Density_Noise_Scale("Density noise scale", Vector) = (1, 1, 1, 0) @@ -2441,6 +2443,23 @@ Shader "yum_food/2ner" ENDCG } + Pass { + Name "META" + Tags { "LightMode" = "Meta" } + + Cull Off + + CGPROGRAM + #pragma vertex vert_meta + #pragma fragment frag_meta + #pragma shader_feature _EMISSION + #pragma shader_feature _METALLICGLOSSMAP + #pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + + #define META_PASS + #include "UnityStandardMeta.cginc" + ENDCG + } } CustomEditor "Thry.ShaderEditor" } diff --git a/Scripts/BakeVertexData.py b/Scripts/BakeVertexData.py index 670e087..47225a4 100644 --- a/Scripts/BakeVertexData.py +++ b/Scripts/BakeVertexData.py @@ -1061,7 +1061,7 @@ class MESH_OT_smart_uv_project_normal_groups(BaseSubmeshOperator, UVOperatorMixi island_margin: FloatProperty( name="Island Margin", description="Margin between UV islands", - default=0.01, + default=0.003, min=0.0, max=0.5, precision=3 diff --git a/UnityStandardMeta.cginc b/UnityStandardMeta.cginc new file mode 100644 index 0000000..0fb21eb --- /dev/null +++ b/UnityStandardMeta.cginc @@ -0,0 +1,169 @@ +#ifndef UNITY_STANDARD_META_INCLUDED +#define UNITY_STANDARD_META_INCLUDED + +// Functionality for Standard shader "meta" pass +// (extracts albedo/emission for lightmapper etc.) + +#include "UnityCG.cginc" +#include "UnityMetaPass.cginc" + +#include "custom30.cginc" +#include "eyes.cginc" +#include "face_me.cginc" +#include "false_color_visualization.cginc" +#include "features.cginc" +#include "fog.cginc" +#include "globals.cginc" +#include "harnack_tracing.cginc" +#include "interpolators.cginc" +#include "letter_grid.cginc" +#include "matcaps.cginc" +#include "math.cginc" +#include "poi.cginc" +#include "shatter_wave.cginc" +#include "ssao.cginc" +#include "ssfd.cginc" +#include "tessellation.cginc" +#include "unigram_letter_grid.cginc" +#include "vertex_domain_warping.cginc" +#include "yum_brdf.cginc" +#include "yum_pbr.cginc" +#include "yum_lighting.cginc" + +struct v2f_meta +{ + float4 pos : SV_POSITION; + float4 uv01 : TEXCOORD0; + float4 uv23 : TEXCOORD1; + float3 worldPos : TEXCOORD2; + float3 objPos : TEXCOORD3; + float3 normal : TEXCOORD4; + float3 tangent : TEXCOORD5; + float3 binormal : TEXCOORD6; + float4 color : COLOR; +#ifdef EDITOR_VISUALIZATION + float2 vizUV : TEXCOORD7; + float4 lightCoord : TEXCOORD8; +#endif +}; + +v2f_meta vert_meta (appdata v) +{ + v2f_meta o; + o.pos = UnityMetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST); + + o.uv01.xy = v.uv0; +#if defined(LIGHTMAP_ON) + o.uv01.zw = v.uv1 * unity_LightmapST.xy + unity_LightmapST.zw; +#else + o.uv01.zw = v.uv1; +#endif + o.uv23.xy = v.uv2; + o.uv23.zw = v.uv3; + + o.worldPos = mul(unity_ObjectToWorld, v.vertex); + o.objPos = v.vertex; + + o.normal = v.normal; + o.tangent = v.tangent.xyz; + o.binormal = cross(o.normal, o.tangent) * v.tangent.w; + + o.color = v.color; + +#ifdef EDITOR_VISUALIZATION + o.vizUV = 0; + o.lightCoord = 0; + if (unity_VisualizationMode == EDITORVIZ_TEXTURE) + o.vizUV = UnityMetaVizUV(unity_EditorViz_UVIndex, v.uv0.xy, v.uv1.xy, v.uv2.xy, unity_EditorViz_Texture_ST); + else if (unity_VisualizationMode == EDITORVIZ_SHOWLIGHTMASK) + { + o.vizUV = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; + o.lightCoord = mul(unity_EditorViz_WorldToLight, mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1))); + } +#endif + return o; +} + +float4 frag_meta (v2f_meta i) : SV_Target +{ + i.normal = normalize(UnityObjectToWorldNormal(i.normal)); + i.tangent = normalize(UnityObjectToWorldNormal(i.tangent)); + i.binormal = normalize(UnityObjectToWorldNormal(i.binormal)); + + float4x4 tangentToWorld = float4x4( + float4(i.tangent.x, i.binormal.x, i.normal.x, 0), + float4(i.tangent.y, i.binormal.y, i.normal.y, 0), + float4(i.tangent.z, i.binormal.z, i.normal.z, 0), + float4(0, 0, 0, 1) + ); + + // Convert v2f_meta to v2f structure expected by YumPbr + v2f pbr_input; + pbr_input.uv01 = i.uv01; + pbr_input.uv23 = i.uv23; + pbr_input.worldPos = i.worldPos; + pbr_input.objPos = float4(i.objPos, 1.0); + pbr_input.normal = i.normal; + pbr_input.tangent = i.tangent; + pbr_input.binormal = i.binormal; + pbr_input.color = i.color; + + YumPbr pbr = GetYumPbr(pbr_input, tangentToWorld); + +#if defined(_CUSTOM30) +#if defined(_CUSTOM30_BASICCUBE) + Custom30Output c30_out = BasicCube(pbr_input, tangentToWorld); +#elif defined(_CUSTOM30_BASICWEDGE) + Custom30Output c30_out = BasicWedge(pbr_input, tangentToWorld); +#elif defined(_CUSTOM30_BASICPLATFORM) + Custom30Output c30_out = BasicPlatform(pbr_input, tangentToWorld); +#elif defined(_CUSTOM30_RAINBOW) + Custom30Output c30_out = Rainbow(pbr_input, tangentToWorld); +#else + Custom30Output c30_out = (Custom30Output) 0; + c30_out.normal = pbr_input.normal; + c30_out.objPos = pbr_input.objPos.xyz; +#endif + // Update surface properties with volumetric results + pbr_input.normal = c30_out.normal; + pbr_input.worldPos = mul(unity_ObjectToWorld, float4(c30_out.objPos, 1)); + + // Recalculate tangent space with new normal + tangentToWorld = float4x4( + float4(i.tangent.x, i.binormal.x, pbr_input.normal.x, 0), + float4(i.tangent.y, i.binormal.y, pbr_input.normal.y, 0), + float4(i.tangent.z, i.binormal.z, pbr_input.normal.z, 0), + float4(0, 0, 0, 1) + ); + + // Get PBR properties with updated surface + pbr = GetYumPbr(pbr_input, tangentToWorld); +#endif + + UnityMetaInput o; + UNITY_INITIALIZE_OUTPUT(UnityMetaInput, o); + +#ifdef EDITOR_VISUALIZATION + o.Albedo = pbr.albedo.rgb; + o.VizUV = i.vizUV; + o.LightCoord = i.lightCoord; +#else + // For lightmapping, we want the diffuse albedo with some contribution from rough metals + half roughness = pbr.roughness_perceptual; + half3 res = pbr.albedo.rgb; + res += pbr.metallic * roughness * 0.5; + o.Albedo = res; +#endif + + o.SpecularColor = lerp(0.04, pbr.albedo.rgb, pbr.metallic); + +#if defined(_EMISSION) + o.Emission = pbr.emission; +#else + o.Emission = 0; +#endif + + return UnityMetaFragment(o); +} + +#endif // UNITY_STANDARD_META_INCLUDED @@ -11,6 +11,8 @@ struct FogParams { float3 color; + float direct_light_intensity; + float indirect_light_intensity; float steps; float y_cutoff; texture2D dithering_noise; @@ -97,11 +99,11 @@ FogResult raymarched_fog(v2f i, FogParams p) // Get intersection with plane at elevation y. float plane_y = p.y_cutoff; - float distance_to_y = 1E3; + float distance_to_y = 1E5; if (abs(rd.y) > 1E-6) { float t = (plane_y - ro.y) / rd.y; if (t > 0) { - distance_to_y = min(t, 1E3); + distance_to_y = min(t, 1E5); } } linearZ = min(linearZ, distance_to_y); @@ -113,6 +115,16 @@ FogResult raymarched_fog(v2f i, FogParams p) const float frame = ((float) AudioLinkData(ALPASS_GENERALVU + int2(1, 0)).x); dither = frac(dither + PHI * frame); + // ----------------------------------------------------------------------- + // Loop-invariant values + float inv_mean_free_path = 1.0 / max(p.mean_free_path, 1e-4); + float turb_lo = 1.0 - 0.5 * p.turbulence; + float turb_hi = 1.0 + 0.5 * p.turbulence; + float3 time_offset = _Time[0] * p.velocity; + + // Golden-ratio LCG seed + float dither_seq = frac(dither + PHI); + // Exponential stepping parameters float step_size = p.step_size; float step_growth = p.step_growth; @@ -128,7 +140,7 @@ FogResult raymarched_fog(v2f i, FogParams p) for (uint ii = 0; ii < p.steps && traveled < max_dist; ++ii) { // Apply dithering to this step - float cur_dither = frac(dither + (ii + 1) * PHI); + float cur_dither = dither_seq; float dithered_step = step_size * (cur_dither + 0.5); float remaining = max_dist - traveled; remaining = max(remaining, 0.1); @@ -139,42 +151,52 @@ FogResult raymarched_fog(v2f i, FogParams p) traveled += dithered_step; // --- Density ---------------------------------------------------------- - float3 noise_coord = (pp + _Time[0] * p.velocity) * p.density_noise_scale.xyz; + float3 noise_coord = (pp + time_offset) * p.density_noise_scale.xyz; float noise_sample = p.density_noise.SampleLevel(bilinear_repeat_s, noise_coord, 0).r; - float noise_factor = lerp(1.0 - 0.5 * p.turbulence, 1.0 + 0.5 * p.turbulence, noise_sample); + float fbm_f = 2.0f; + float fbm_a = 0.5f; + noise_sample += p.density_noise.SampleLevel(bilinear_repeat_s, noise_coord * fbm_f, 0).r * fbm_a; + fbm_f *= 2.0f; + fbm_a *= 0.5f; + noise_sample += p.density_noise.SampleLevel(bilinear_repeat_s, noise_coord * fbm_f, 0).r * fbm_a; + noise_sample *= 0.55f; + + noise_sample *= noise_sample; + + float noise_factor = lerp(turb_lo, turb_hi, noise_sample); float height_factor = exp(-max(pp.y - p.height_offset, 0.0) / p.height_scale); - float sigma_t = noise_factor * height_factor / max(p.mean_free_path, 1e-4); + float sigma_t = noise_factor * height_factor * inv_mean_free_path; float sigma_s = sigma_t * p.albedo; // Analytic integration over the segment float exp_term = exp(-sigma_t * dithered_step); - // If the segment is almost transparent, skip expensive work - if (sigma_t < 1e-6) - { - T *= exp_term; - continue; - } - // --- Incoming radiance ------------------------------------------------ float3 L_in; #if defined(_RAYMARCHED_FOG_EMITTER_TEXTURE) L_in = getEmitterData(p, pp); #else - // Indirect from SH / light volumes +#if 1 + float3 l00 = LightVolumeSH_L0(pp); + float3 l01r = 0; + float3 l01g = 0; + float3 l01b = 0; +#else float3 l00, l01r, l01g, l01b; LightVolumeSH(pp, l00, l01r, l01g, l01b); +#endif float3 indirect = LightVolumeEvaluate(float3(0, 1, 0), l00, l01r, l01g, l01b); // Direct from the dominant realtime light float3 to_light = (_WorldSpaceLightPos0.w == 0.0) ? normalize(_WorldSpaceLightPos0.xyz) : normalize(_WorldSpaceLightPos0.xyz - pp); - float phase = PhaseHG(dot(to_light, -rd), p.g); + float phase = PhaseHG(dot(to_light, rd), p.g); float3 direct = _LightColor0.rgb * phase; - L_in = (direct + indirect) * p.color; + L_in = (direct * p.direct_light_intensity + + indirect * p.indirect_light_intensity) * p.color; #endif // --- Accumulate radiance --------------------------------------------- @@ -185,9 +207,13 @@ FogResult raymarched_fog(v2f i, FogParams p) T *= exp_term; // Early exit if virtually opaque - if (T < 1e-3) + if (T < 1e-7) break; + // Advance LCG for the next step + dither_seq += PHI; + if (dither_seq >= 1.0) dither_seq -= 1.0; + // Grow step size exponentially step_size *= step_growth; } diff --git a/globals.cginc b/globals.cginc index e18e796..5ff5286 100644 --- a/globals.cginc +++ b/globals.cginc @@ -555,6 +555,8 @@ float _SSAO_Bias; #if defined(_RAYMARCHED_FOG)
float3 _Raymarched_Fog_Color;
+float _Raymarched_Fog_Direct_Light_Intensity;
+float _Raymarched_Fog_Indirect_Light_Intensity;
float _Raymarched_Fog_Steps;
float _Raymarched_Fog_Density;
texture2D _Raymarched_Fog_Dithering_Noise;
|
