summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2025-06-14 20:48:03 -0700
committeryum <yum.food.vr@gmail.com>2025-06-14 20:48:03 -0700
commitfbcd6a84b64018a93a3fd4e3e15260d921e93d8e (patch)
tree24a762c1a0f2d8d1dace3418193d838b657e33cd
parent60e1e2010ab5eaa01dfd00c30f91384f95a78aa2 (diff)
Add meta pass, limit fog to forward base, add fog dir/indir knobs
-rw-r--r--2ner.cginc16
-rw-r--r--2ner.shader19
-rw-r--r--Scripts/BakeVertexData.py2
-rw-r--r--UnityStandardMeta.cginc169
-rw-r--r--fog.cginc60
-rw-r--r--globals.cginc2
6 files changed, 249 insertions, 19 deletions
diff --git a/2ner.cginc b/2ner.cginc
index e6d2433..dad0c84 100644
--- a/2ner.cginc
+++ b/2ner.cginc
@@ -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
diff --git a/fog.cginc b/fog.cginc
index adef303..62be8e0 100644
--- a/fog.cginc
+++ b/fog.cginc
@@ -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;