diff options
| -rw-r--r-- | Editor/tooner.cs | 20 | ||||
| -rw-r--r-- | cnlohr.cginc | 35 | ||||
| -rw-r--r-- | feature_macros.cginc | 3 | ||||
| -rw-r--r-- | fog.cginc | 124 | ||||
| -rw-r--r-- | globals.cginc | 2 | ||||
| -rw-r--r-- | interpolators.cginc | 8 | ||||
| -rw-r--r-- | math.cginc | 24 | ||||
| -rw-r--r-- | noise.cginc | 92 | ||||
| -rw-r--r-- | tooner.shader | 2 | ||||
| -rw-r--r-- | tooner_lighting.cginc | 36 |
10 files changed, 334 insertions, 12 deletions
diff --git a/Editor/tooner.cs b/Editor/tooner.cs index 8824de5..5fc26bd 100644 --- a/Editor/tooner.cs +++ b/Editor/tooner.cs @@ -2002,6 +2002,25 @@ public class ToonerGUI : ShaderGUI { EditorGUI.indentLevel -= 1; } + void DoGimmickFog0() { + MaterialProperty bc; + + bc = FindProperty("_Gimmick_Fog_00_Enable_Static"); + bool enabled = (bc.floatValue != 0.0); + EditorGUI.BeginChangeCheck(); + enabled = Toggle("Fog 00", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + SetKeyword("_GIMMICK_FOG_00", enabled); + + if (!enabled) { + return; + } + + EditorGUI.indentLevel += 1; + EditorGUI.indentLevel -= 1; + } + void DoGimmicks() { show_ui.Add(AddCollapsibleMenu("Gimmicks", "_Gimmicks")); EditorGUI.indentLevel += 1; @@ -2021,6 +2040,7 @@ public class ToonerGUI : ShaderGUI { DoGimmickMirrorUVFlip(); DoGimmickLetterGrid(); DoGimmickAudiolinkChroma00(); + DoGimmickFog0(); DoClones(); DoExplosion(); DoGeoScroll(); diff --git a/cnlohr.cginc b/cnlohr.cginc index bed117d..c3163d2 100644 --- a/cnlohr.cginc +++ b/cnlohr.cginc @@ -50,4 +50,39 @@ float3 getCenterCamPos() { #endif } +float GetLinearZFromZDepth_WorksWithMirrors(float zDepthFromMap, float2 screenUV) +{ + #if defined(UNITY_REVERSED_Z) + zDepthFromMap = 1 - zDepthFromMap; + + // When using a mirror, the far plane is whack. This just checks for it and aborts. + if( zDepthFromMap >= 1.0 ) return _ProjectionParams.z; + #endif + + float4 clipPos = float4(screenUV.xy, zDepthFromMap, 1.0); + clipPos.xyz = 2.0f * clipPos.xyz - 1.0f; + float4 camPos = mul(unity_CameraInvProjection, clipPos); + return -camPos.z / camPos.w; +} + +float GetDepthOfWorldPos(float3 worldPos) +{ + float3 full_vec_eye_to_geometry = worldPos - _WorldSpaceCameraPos; + float3 world_dir = normalize(worldPos - _WorldSpaceCameraPos); + float4 objPos = mul(unity_WorldToObject, float4(worldPos, 1)); + float4 clipPos = UnityObjectToClipPos(objPos); + + float2 suv = clipPos * float2(0.5, 0.5 * _ProjectionParams.x); + float2 screenPos = TransformStereoScreenSpaceTex(suv + 0.5 * clipPos.w, clipPos.w); + + float perspective_divide = 1.0 / clipPos.w; + float perspective_factor = length(full_vec_eye_to_geometry * perspective_divide); + float2 screen_uv = screenPos.xy * perspective_divide; + float eye_depth_world = + GetLinearZFromZDepth_WorksWithMirrors( + SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, screen_uv), + screen_uv) * perspective_factor; + return eye_depth_world; +} + #endif // __CNLOHR_INC diff --git a/feature_macros.cginc b/feature_macros.cginc index 0dcaced..65220e8 100644 --- a/feature_macros.cginc +++ b/feature_macros.cginc @@ -1,6 +1,8 @@ #ifndef __FEATURE_MACROS_INC #define __FEATURE_MACROS_INC +#define EXPERIMENT__CUSTOM_DEPTH + #pragma shader_feature_local _ _BASECOLOR_MAP #pragma shader_feature_local _ _NORMAL_MAP #pragma shader_feature_local _ _METALLIC_MAP @@ -164,6 +166,7 @@ #pragma shader_feature_local _ _GIMMICK_AL_CHROMA_00_HUE_SHIFT #pragma shader_feature_local _ SSR_ENABLED #pragma shader_feature_local _ SSR_MASK +#pragma shader_feature_local _ _GIMMICK_FOG_00 #endif // __FEATURE_MACROS_INC diff --git a/fog.cginc b/fog.cginc new file mode 100644 index 0000000..c0eabf7 --- /dev/null +++ b/fog.cginc @@ -0,0 +1,124 @@ +#include "globals.cginc" +#include "interpolators.cginc" +#include "math.cginc" +#include "noise.cginc" +#include "cnlohr.cginc" + +#ifndef __FOG_INC +#define __FOG_INC + +#if defined(_GIMMICK_FOG_00) + +struct Fog00PBR { + float4 albedo; + float3 normal; + float depth; +}; + +#define FOG_MAX_RAY 10 +#define FOG_RADIUS 25 +#define FOG_NOISE_SCALE 2 +float map(float3 p) { + float density = 0; + float t = _Time[1]; + density += perlin_noise_3d(p * FOG_NOISE_SCALE * 1.0 + t) * saturate(FOG_RADIUS - length(p)) / 2.0; + density += perlin_noise_3d(p * FOG_NOISE_SCALE * 1.7 + t) * saturate(FOG_RADIUS - length(p)) / 4.0; + density += perlin_noise_3d(p * FOG_NOISE_SCALE * 2.9 + t) * saturate(FOG_RADIUS - length(p)) / 8.0; + density += perlin_noise_3d(p * FOG_NOISE_SCALE * 4.3 + t) * saturate(FOG_RADIUS - length(p)) / 16.0; + + return density; +} + +float3 get_normal(float3 p) { + float3 e = float3(0.01, 0, 0); + return normalize(float3( + map(p + e.xyz) - map(p), + map(p + e.yxz) - map(p), + map(p + e.zyx) - map(p))); +} + +Fog00PBR getFog00(v2f i) { + + float3 cam_pos = _WorldSpaceCameraPos; + float3 obj_pos = i.worldPos; + + float3 world_pos_depth_hit; + float2 screen_uv; + { + float3 full_vec_eye_to_geometry = i.worldPos - _WorldSpaceCameraPos; + float3 world_dir = normalize(i.worldPos - _WorldSpaceCameraPos); + float perspective_divide = 1.0 / i.pos.w; + float perspective_factor = length(full_vec_eye_to_geometry * perspective_divide); + screen_uv = i.screenPos.xy * perspective_divide; + float eye_depth_world = + GetLinearZFromZDepth_WorksWithMirrors( + SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, screen_uv), + screen_uv) * perspective_factor; + world_pos_depth_hit = _WorldSpaceCameraPos + eye_depth_world * world_dir; + } + + float3 rd = normalize(obj_pos - cam_pos); + float3 ro = cam_pos; + + bool no_intersection = false; + if (length(ro) > FOG_RADIUS) { + float3 l = ro; + float a = 1; + float b = 2 * dot(rd, l); + float c = dot(l, l) - FOG_RADIUS * FOG_RADIUS; + float t0, t1; + if (solveQuadratic(a, b, c, t0, t1)) { + no_intersection = (t0 < 0) * (t1 < 0); + ro += min(max(t0, 0), max(t1, 0)) * rd; + } else { + no_intersection = true; + } + } + + // Factor of 10 on `screen_uv*10` eliminates visible striping artifact that + // is visible with no factor. + float dither = rand2(screen_uv*10) - 0.5; + ro += rd * (1.0 + dither); + + float world_pos_depth_hit_l = length(world_pos_depth_hit - ro); + + float4 acc = 0; + float step_size = 0.5; + uint step_count = floor(min( + FOG_MAX_RAY / step_size, + world_pos_depth_hit_l / step_size)); + step_count *= (1 - no_intersection); + float density = 0.5; + + float3 normal_weighted_sum = 0; + for (uint ii = 0; ii < step_count; ii++) { + float3 p = ro + (rd * step_size) * ii; + float4 c = float4(1, 1, 1, map(p)); +#if 1 + float3 n = get_normal(p); + normal_weighted_sum += n * c.a; +#endif + c *= density; + acc += c * (1.0 - acc.a); + } + + Fog00PBR pbr; + pbr.albedo = saturate(acc); + pbr.albedo.rgb = saturate(pow(pbr.albedo.rgb, 3.0) * 5); + +#if 0 + pbr.normal = normalize(normal_weighted_sum); +#else + pbr.normal = i.normal; +#endif + + float4 clip_pos = mul(UNITY_MATRIX_VP, float4(ro, 1.0)); + pbr.depth = clip_pos.z / clip_pos.w; + + return pbr; +} + +#endif // _GIMMICK_FOG_00 + +#endif // __FOG_INC + diff --git a/globals.cginc b/globals.cginc index 9f73932..906ee1c 100644 --- a/globals.cginc +++ b/globals.cginc @@ -3,6 +3,8 @@ #ifndef __GLOBALS_INC #define __GLOBALS_INC +UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture); + SamplerState linear_repeat_s; SamplerState linear_clamp_s; SamplerState bilinear_repeat_s; diff --git a/interpolators.cginc b/interpolators.cginc index 5942922..9763bca 100644 --- a/interpolators.cginc +++ b/interpolators.cginc @@ -23,7 +23,7 @@ struct appdata struct v2f { - float4 pos : SV_POSITION; + linear noperspective centroid float4 pos : SV_POSITION; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; @@ -42,7 +42,7 @@ struct v2f float3 objPos : TEXCOORD11; float3 centerCamPos : TEXCOORD12; - float4 screenPos : TEXCOORD13; + float2 screenPos : TEXCOORD13; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO @@ -69,7 +69,7 @@ struct appdata struct v2f { - float4 pos : SV_POSITION; + linear noperspective centroid float4 pos : SV_POSITION; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; @@ -89,7 +89,7 @@ struct v2f float3 objPos : TEXCOORD12; float3 centerCamPos : TEXCOORD13; - float4 screenPos : TEXCOORD14; + float2 screenPos : TEXCOORD14; #if defined(VERTEXLIGHT_ON) float3 vertexLightColor : TEXCOORD15; @@ -197,5 +197,29 @@ float median(float3 x) return median(x.x, x.y, x.z); } +// Yoinked from here +// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection.html +bool solveQuadratic(float a, float b, float c, out float x0, out float x1) +{ + float discriminant = b * b - 4 * a * c; + if (discriminant < 0) { + return false; + } else if (discriminant == 0) { + x0 = -0.5 * b / a; + x1 = x0; + } else { + float q = (b > 0) ? + -0.5 * (b + sqrt(discriminant)) : + -0.5 * (b - sqrt(discriminant)); + x0 = q/a; + x1 = c/q; + } + float tmp_min = min(x0, x1); + float tmp_max = max(x0, x1); + x0 = tmp_min; + x1 = tmp_max; + return true; +} + #endif // __MATH_INC diff --git a/noise.cginc b/noise.cginc new file mode 100644 index 0000000..a58e56d --- /dev/null +++ b/noise.cginc @@ -0,0 +1,92 @@ +#include "math.cginc" + +#ifndef __NOISE_INC +#define __NOISE_INC + +float cubic_interp(float x) +{ + return x * x * (3.0 - 2.0 * x); +} + +float2 cubic_interp(float2 x) +{ + return x * x * (3.0 - 2.0 * x); +} + +float3 cubic_interp(float3 x) +{ + return x * x * (3.0 - 2.0 * x); +} + +float quintic_interp(float x) +{ + return x * x * x * (x * (x * 6 - 15) + 10); +} + +float2 quintic_interp(float2 x) +{ + return x * x * x * (x * (x * 6 - 15) + 10); +} + +float perlin_noise(float2 p) +{ + float2 sq = floor(p); + float2 sqi = frac(p); + + float r0 = rand2(sq + float2(0,0)); + float r1 = rand2(sq + float2(1,0)); + float r2 = rand2(sq + float2(0,1)); + float r3 = rand2(sq + float2(1,1)); + + float2 u = cubic_interp(sqi); + + return lerp(r0, r1, u.x) + + (r2 - r0) * u.y * (1.0 - u.x) + + (r3 - r1) * u.x * u.y; +} + +float perlin_noise_3d(float3 p) +{ + float3 sq = floor(p); + float3 sqi = frac(p); + + float r0 = rand3(sq + float3(0,0,0)); + float r1 = rand3(sq + float3(1,0,0)); + float r2 = rand3(sq + float3(0,1,0)); + float r3 = rand3(sq + float3(1,1,0)); + float r4 = rand3(sq + float3(0,0,1)); + float r5 = rand3(sq + float3(1,0,1)); + float r6 = rand3(sq + float3(0,1,1)); + float r7 = rand3(sq + float3(1,1,1)); + + float3 u = cubic_interp(sqi); + + return lerp( + lerp(r0, r1, u.x) + + (r2 - r0) * u.y * (1.0 - u.x) + + (r3 - r1) * u.x * u.y, + lerp(r4, r5, u.x) + + (r6 - r4) * u.y * (1.0 - u.x) + + (r7 - r5) * u.x * u.y, + u.z); +} + +float simplex_noise(float2 p) +{ + float2 sq = floor(p); + float2 sqi = frac(p); + + float r0 = rand2(sq + float2(0,0)); + float r1 = rand2(sq + float2(1,0)); + float r2 = rand2(sq + float2(0,1)); + float r3 = rand2(sq + float2(1,1)); + + float2 u = quintic_interp(sqi); + + return lerp(r0, r1, u.x) + + (r2 - r0) * u.y * (1.0 - u.x) + + (r3 - r1) * u.x * u.y; +} + +#endif // __NOISE_INC + diff --git a/tooner.shader b/tooner.shader index 5a3abba..79286c9 100644 --- a/tooner.shader +++ b/tooner.shader @@ -617,6 +617,8 @@ Shader "yum_food/tooner" _Hue_Shift_HSV_UI_Show("UI show", Float) = 0 _Clones_UI_Show("UI show", Float) = 0 _Mochie_UI_Show("UI show", Float) = 0 + + _Gimmick_Fog_00_Enable_Static("Enable fog 00", Float) = 0 } SubShader { diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc index 6d70dbc..fb7899d 100644 --- a/tooner_lighting.cginc +++ b/tooner_lighting.cginc @@ -7,6 +7,7 @@ #include "cnlohr.cginc" #include "disinfo.cginc" #include "eyes.cginc" +#include "fog.cginc" #include "globals.cginc" #include "halos.cginc" #include "interpolators.cginc" @@ -169,10 +170,6 @@ v2f vert(appdata v) o.worldPos = mul(unity_ObjectToWorld, v.vertex); o.objPos = v.vertex; -#if defined(SSR_ENABLED) - o.screenPos = ComputeGrabScreenPos(o.pos); -#endif - #if defined(_FACE_ME_WORLD_Y) if (!_FaceMeWorldY_Enable_Dynamic) { o.normal = UnityObjectToWorldNormal(v.normal); @@ -212,7 +209,8 @@ v2f vert(appdata v) TRANSFER_SHADOW(o); #endif - o.screenPos = ComputeGrabScreenPos(o.pos); + float2 suv = o.pos * float2(0.5, 0.5 * _ProjectionParams.x); + o.screenPos = TransformStereoScreenSpaceTex(suv + 0.5 * o.pos.w, o.pos.w); getVertexLightColor(o); @@ -1271,8 +1269,14 @@ float4 pixellate_color(int2 px_res, float2 uv, float4 c) } #endif -float4 effect(inout v2f i) +float4 effect(inout v2f i, out float depth) { +#if defined(EXPERIMENT__CUSTOM_DEPTH) + { + float4 clip_pos = mul(UNITY_MATRIX_VP, float4(i.worldPos, 1.0)); + depth = clip_pos.z / clip_pos.w; + } +#endif const float3 view_dir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos); const float3 view_dir_c = normalize(i.centerCamPos - i.worldPos); #define VIEW_DIR(center_eye_fix) (center_eye_fix == 1 ? view_dir_c : view_dir) @@ -1386,6 +1390,15 @@ float4 effect(inout v2f i) } #endif +#if defined(_GIMMICK_FOG_00) + { + Fog00PBR pbr = getFog00(i); + albedo = pbr.albedo; + normal = pbr.normal; + depth = pbr.depth; + } +#endif + #if defined(_RENDERING_CUTOUT) #if defined(_RENDERING_CUTOUT_STOCHASTIC) float ar = rand2(i.uv0); @@ -2301,12 +2314,19 @@ float4 effect(inout v2f i) return result; } -fixed4 frag(v2f i) : SV_Target +fixed4 frag(v2f i +#if defined(EXPERIMENT__CUSTOM_DEPTH) +, out float depth: SV_DepthGreaterEqual +#endif + ) : SV_Target { +#if !defined(EXPERIMENT__CUSTOM_DEPTH) + float depth; +#endif UNITY_APPLY_DITHER_CROSSFADE(i.pos.xy); UNITY_SETUP_INSTANCE_ID(i); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); - return effect(i); + return effect(i, depth); } #endif // TOONER_LIGHTING |
