diff options
| author | yum <yum.food.vr@gmail.com> | 2024-08-20 13:45:54 -0700 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2024-08-20 13:45:54 -0700 |
| commit | b7407fa9d7a917f7d62a7a2e12f96e90af11215c (patch) | |
| tree | b370eee4fb844036ac767eeb62ce166359225682 | |
| parent | bf9496af5f27d548224689a123e97546fc2053b7 (diff) | |
Add normals replace option to matcap
Also add mix factor slider so you can animate matcap opacity. This is
useful for adding things like bodysuits.
| -rw-r--r-- | Editor/tooner.cs | 28 | ||||
| -rw-r--r-- | feature_macros.cginc | 2 | ||||
| -rw-r--r-- | globals.cginc | 12 | ||||
| -rw-r--r-- | tooner.shader | 8 | ||||
| -rw-r--r-- | tooner_lighting.cginc | 133 |
5 files changed, 148 insertions, 35 deletions
diff --git a/Editor/tooner.cs b/Editor/tooner.cs index 4e96e61..4d96d76 100644 --- a/Editor/tooner.cs +++ b/Editor/tooner.cs @@ -480,6 +480,11 @@ public class ToonerGUI : ShaderGUI { bc, "Matcap strength"); + bc = FindProperty($"_Matcap{i}MixFactor"); + editor.RangeProperty( + bc, + "Mix factor"); + bc = FindProperty($"_Matcap{i}Emission"); editor.FloatProperty( bc, @@ -490,6 +495,29 @@ public class ToonerGUI : ShaderGUI { bc, "Quantization"); + bc = FindProperty($"_Matcap{i}Normal_Enabled"); + enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Replace normals", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + SetKeyword($"_MATCAP{i}_NORMAL", enabled); + + if (enabled) { + EditorGUI.indentLevel += 1; + bc = FindProperty($"_Matcap{i}Normal"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Normal map"), + bc); + if (bc.textureValue) { + editor.TextureScaleOffsetProperty(bc); + + bc = FindProperty($"_Matcap{i}Normal_Str"); + editor.RangeProperty(bc, "Strength"); + } + EditorGUI.indentLevel -= 1; + } + bc = FindProperty($"_Matcap{i}Distortion0"); enabled = bc.floatValue > 1E-6; EditorGUI.BeginChangeCheck(); diff --git a/feature_macros.cginc b/feature_macros.cginc index 29d3859..bdc1369 100644 --- a/feature_macros.cginc +++ b/feature_macros.cginc @@ -20,9 +20,11 @@ #pragma shader_feature_local _ _MATCAP0 #pragma shader_feature_local _ _MATCAP0_MASK #pragma shader_feature_local _ _MATCAP0_MASK2 +#pragma shader_feature_local _ _MATCAP0_NORMAL #pragma shader_feature_local _ _MATCAP1 #pragma shader_feature_local _ _MATCAP1_MASK #pragma shader_feature_local _ _MATCAP1_MASK2 +#pragma shader_feature_local _ _MATCAP1_NORMAL #pragma shader_feature_local _ _RIM_LIGHTING0 #pragma shader_feature_local _ _RIM_LIGHTING0_MASK #pragma shader_feature_local _ _RIM_LIGHTING0_GLITTER diff --git a/globals.cginc b/globals.cginc index d77b5e9..4bedf19 100644 --- a/globals.cginc +++ b/globals.cginc @@ -305,9 +305,15 @@ float _Matcap0_Mask_Invert; texture2D _Matcap0_Mask2; float _Matcap0_Mask2_Invert; float _Matcap0Str; +float _Matcap0MixFactor; float _Matcap0Quantization; float _Matcap0Mode; float _Matcap0Emission; +#if defined(_MATCAP0_NORMAL) +texture2D _Matcap0Normal; +float4 _Matcap0Normal_ST; +float _Matcap0Normal_Str; +#endif #endif #if defined(_MATCAP1) @@ -318,9 +324,15 @@ float _Matcap1_Mask_Invert; texture2D _Matcap1_Mask2; float _Matcap1_Mask2_Invert; float _Matcap1Str; +float _Matcap1MixFactor; float _Matcap1Quantization; float _Matcap1Mode; float _Matcap1Emission; +#if defined(_MATCAP1_NORMAL) +texture2D _Matcap1Normal; +float4 _Matcap1Normal_ST; +float _Matcap1Normal_Str; +#endif #endif #if defined(_RIM_LIGHTING0) diff --git a/tooner.shader b/tooner.shader index 01f50d1..7fb8751 100644 --- a/tooner.shader +++ b/tooner.shader @@ -218,9 +218,13 @@ Shader "yum_food/tooner" _Matcap0_Mask2_Invert("Invert mask", Float) = 0.0 _Matcap0Mode("Matcap mode", Float) = 0 _Matcap0Str("Matcap strength", Float) = 1 + _Matcap0MixFactor("Matcap mix factor", Range(0, 1)) = 1 _Matcap0Emission("Matcap emission", Float) = 0 _Matcap0Quantization("Matcap quantization", Float) = -1 _Matcap0Distortion0("Matcap distortion0", Float) = 0 + _Matcap0Normal_Enabled("Enable normal replacement", Float) = 0 + _Matcap0Normal("Matcap normals", 2D) = "bump" {} + _Matcap0Normal_Str("Matcap normals", Range(0, 10)) = 1 _Matcap1("Matcap", 2D) = "black" {} _Matcap1_Mask("Matcap mask", 2D) = "white" {} @@ -229,9 +233,13 @@ Shader "yum_food/tooner" _Matcap1_Mask2_Invert("Invert mask", Float) = 0.0 _Matcap1Mode("Matcap mode", Float) = 0 _Matcap1Str("Matcap strength", Float) = 1 + _Matcap1MixFactor("Matcap mix factor", Range(0, 1)) = 1 _Matcap1Emission("Matcap emission", Float) = 0 _Matcap1Quantization("Matcap quantization", Float) = -1 _Matcap1Distortion0("Matcap distortion0", Float) = 0 + _Matcap1Normal_Enabled("Enable normal replacement", Float) = 0 + _Matcap1Normal("Matcap normals", 2D) = "bump" {} + _Matcap1Normal_Str("Matcap normals", Range(0, 10)) = 1 _Rim_Lighting0_Enabled("Enable rim lighting", Float) = 0 _Rim_Lighting0_Mode("Rim lighting mode", Float) = 0 diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc index 1f840b7..10383df 100644 --- a/tooner_lighting.cginc +++ b/tooner_lighting.cginc @@ -828,7 +828,8 @@ void applyDecal(inout float4 albedo, } void mixOverlayAlbedoRoughnessMetallic(inout float4 albedo, - inout float roughness, inout float metallic, PbrOverlay ov) { + inout float roughness, inout float metallic, PbrOverlay ov, + float mask) { // Calculate alpha masks before we start mutating alpha. #if defined(_PBR_OVERLAY0) float a0 = saturate(ov.ov0_albedo.a * _PBR_Overlay0_Alpha_Multiplier); @@ -837,6 +838,7 @@ void mixOverlayAlbedoRoughnessMetallic(inout float4 albedo, (albedo.a < _PBR_Overlay0_Constrain_By_Alpha_Max); a0 *= in_range; } + a0 *= mask; #endif #if defined(_PBR_OVERLAY1) float a1 = saturate(ov.ov1_albedo.a * _PBR_Overlay1_Alpha_Multiplier); @@ -845,6 +847,7 @@ void mixOverlayAlbedoRoughnessMetallic(inout float4 albedo, (albedo.a < _PBR_Overlay1_Constrain_By_Alpha_Max); a1 *= in_range; } + a1 *= mask; #endif #if defined(_PBR_OVERLAY2) float a2 = saturate(ov.ov2_albedo.a * _PBR_Overlay2_Alpha_Multiplier); @@ -853,6 +856,7 @@ void mixOverlayAlbedoRoughnessMetallic(inout float4 albedo, (albedo.a < _PBR_Overlay2_Constrain_By_Alpha_Max); a2 *= in_range; } + a2 *= mask; #endif #if defined(_PBR_OVERLAY3) float a3 = saturate(ov.ov3_albedo.a * _PBR_Overlay3_Alpha_Multiplier); @@ -861,6 +865,7 @@ void mixOverlayAlbedoRoughnessMetallic(inout float4 albedo, (albedo.a < _PBR_Overlay3_Constrain_By_Alpha_Max); a3 *= in_range; } + a3 *= mask; #endif #if defined(_PBR_OVERLAY0) @@ -1068,8 +1073,8 @@ float4 pixellate_color(int2 px_res, float2 uv, float4 c) float4 effect(inout v2f i) { - float iddx = ddx(i.uv0.x) * _Mip_Multiplier; - float iddy = ddx(i.uv0.y) * _Mip_Multiplier; + float iddx = (ddx(i.uv0.x) + ddx(i.uv0.y)) * _Mip_Multiplier; + float iddy = (ddy(i.uv0.x) + ddy(i.uv0.y)) * _Mip_Multiplier; const float3 view_dir = normalize(_WorldSpaceCameraPos - i.worldPos); // Not necessarily normalized after interpolation. i.normal = normalize(i.normal); @@ -1204,35 +1209,25 @@ float4 effect(inout v2f i) { const float3 cam_normal = normalize(mul(UNITY_MATRIX_V, float4(normal, 0))); const float3 cam_view_dir = normalize(mul(UNITY_MATRIX_V, float4(view_dir, 0))); - const float3 refl = -reflect(cam_view_dir, cam_normal); + const float3 cam_refl = -reflect(cam_view_dir, cam_normal); float m = 2.0 * sqrt( - refl.x * refl.x + - refl.y * refl.y + - (refl.z + 1) * (refl.z + 1)); - matcap_uv = refl.xy / m + 0.5; + cam_refl.x * cam_refl.x + + cam_refl.y * cam_refl.y + + (cam_refl.z + 1) * (cam_refl.z + 1)); + matcap_uv = cam_refl.xy / m + 0.5; matcap_radius = length(matcap_uv - 0.5); matcap_theta = atan2(matcap_uv.y - 0.5, matcap_uv.x - 0.5); } #endif + float matcap_overwrite_mask = 0; #if defined(_MATCAP0) || defined(_MATCAP1) { float iddx = ddx(i.uv0.x); float iddy = ddy(i.uv0.y); #if defined(_MATCAP0) { -#if defined(_MATCAP0_DISTORTION0) - float2 distort_uv = matcap_distortion0(matcap_uv); - float2 matcap_uv = distort_uv; -#endif - float3 matcap = _Matcap0.SampleGrad(linear_repeat_s, matcap_uv, iddx, iddy) * _Matcap0Str; - - float q = _Matcap0Quantization; - if (q > 0) { - matcap = ceil(matcap * q) / q; - } - #if defined(_MATCAP0_MASK) - float4 matcap_mask_raw = _Matcap0_Mask.SampleGrad(linear_repeat_s, i.uv0.xy, iddx, iddy); + float4 matcap_mask_raw = _Matcap0_Mask.SampleLevel(linear_repeat_s, i.uv0.xy, 0); float matcap_mask = matcap_mask_raw.r; matcap_mask = (bool) round(_Matcap0_Mask_Invert) ? 1 - matcap_mask : matcap_mask; matcap_mask *= matcap_mask_raw.a; @@ -1241,13 +1236,50 @@ float4 effect(inout v2f i) #endif #if defined(_MATCAP0_MASK2) { - float4 matcap_mask2_raw = _Matcap0_Mask2.SampleGrad(linear_repeat_s, i.uv0.xy, iddx, iddy); + float4 matcap_mask2_raw = _Matcap0_Mask2.SampleLevel(linear_repeat_s, i.uv0.xy, 0); float matcap_mask2 = matcap_mask2_raw.r; matcap_mask2 = (bool) round(_Matcap0_Mask2_Invert) ? 1 - matcap_mask2 : matcap_mask2; matcap_mask2 *= matcap_mask2_raw.a; matcap_mask *= matcap_mask2; } #endif +#if defined(_MATCAP0_NORMAL) + float3 matcap_normal = UnpackScaleNormal( + _Matcap0Normal.SampleGrad(linear_repeat_s, + UV_SCOFF(i, _Matcap0Normal_ST, /*uv_channel=*/0), + iddx * _Matcap0Normal_ST.x, + iddy * _Matcap0Normal_ST.y), + _Matcap0Normal_Str); + raw_normal = (round(matcap_mask) == 1 ? matcap_normal : raw_normal); + normal = float3( + raw_normal.x * i.tangent + + raw_normal.y * binormal + + raw_normal.z * i.normal + ); + { + const float3 cam_normal = normalize(mul(UNITY_MATRIX_V, float4(normal, 0))); + const float3 cam_view_dir = normalize(mul(UNITY_MATRIX_V, float4(view_dir, 0))); + const float3 cam_refl = -reflect(cam_view_dir, cam_normal); + float m = 2.0 * sqrt( + cam_refl.x * cam_refl.x + + cam_refl.y * cam_refl.y + + (cam_refl.z + 1) * (cam_refl.z + 1)); + matcap_uv = cam_refl.xy / m + 0.5; + matcap_radius = length(matcap_uv - 0.5); + matcap_theta = atan2(matcap_uv.y - 0.5, matcap_uv.x - 0.5); + } +#endif + +#if defined(_MATCAP0_DISTORTION0) + float2 distort_uv = matcap_distortion0(matcap_uv); + float2 matcap_uv = distort_uv; +#endif + float3 matcap = _Matcap0.SampleGrad(linear_repeat_s, matcap_uv, iddx, iddy) * _Matcap0Str; + + float q = _Matcap0Quantization; + if (q > 0) { + matcap = ceil(matcap * q) / q; + } int mode = round(_Matcap0Mode); switch (mode) { @@ -1260,6 +1292,7 @@ float4 effect(inout v2f i) albedo.rgb *= lerp(1, matcap, matcap_mask); break; case 2: + matcap_overwrite_mask = max(matcap_mask, matcap_overwrite_mask); albedo.rgb = lerp(albedo.rgb, matcap, matcap_mask); matcap_emission = lerp(albedo.rgb, matcap, matcap_mask) * _Matcap0Emission; break; @@ -1282,19 +1315,8 @@ float4 effect(inout v2f i) #endif // _MATCAP0 #if defined(_MATCAP1) { -#if defined(_MATCAP1_DISTORTION0) - float2 distort_uv = matcap_distortion0(matcap_uv); - float2 matcap_uv = distort_uv; -#endif - float3 matcap = _Matcap1.SampleGrad(linear_repeat_s, matcap_uv, iddx, iddy) * _Matcap1Str; - - float q = _Matcap1Quantization; - if (q > 0) { - matcap = ceil(matcap * q) / q; - } - #if defined(_MATCAP1_MASK) - float4 matcap_mask_raw = _Matcap1_Mask.SampleGrad(linear_repeat_s, i.uv0.xy, iddx, iddy); + float4 matcap_mask_raw = _Matcap1_Mask.SampleLevel(linear_repeat_s, i.uv0.xy, 0); float matcap_mask = matcap_mask_raw.r; matcap_mask = (bool) round(_Matcap1_Mask_Invert) ? 1 - matcap_mask : matcap_mask; matcap_mask *= matcap_mask_raw.a; @@ -1303,13 +1325,51 @@ float4 effect(inout v2f i) #endif #if defined(_MATCAP1_MASK2) { - float4 matcap_mask2_raw = _Matcap1_Mask2.SampleGrad(linear_repeat_s, i.uv0.xy, iddx, iddy); + float4 matcap_mask2_raw = _Matcap1_Mask2.SampleLevel(linear_repeat_s, i.uv0.xy, 0); float matcap_mask2 = matcap_mask2_raw.r; matcap_mask2 = (bool) round(_Matcap1_Mask2_Invert) ? 1 - matcap_mask2 : matcap_mask2; matcap_mask2 *= matcap_mask2_raw.a; matcap_mask *= matcap_mask2; } #endif +#if defined(_MATCAP1_NORMAL) + float3 matcap_normal = UnpackScaleNormal( + _Matcap1Normal.SampleGrad(linear_repeat_s, + UV_SCOFF(i, _Matcap1Normal_ST, /*uv_channel=*/0), + iddx * _Matcap1Normal_ST.x, + iddy * _Matcap1Normal_ST.y), + _Matcap1Normal_Str * _Matcap1MixFactor); + raw_normal = (round(matcap_mask) == 1 ? matcap_normal : raw_normal); + normal = float3( + raw_normal.x * i.tangent + + raw_normal.y * binormal + + raw_normal.z * i.normal + ); + { + const float3 cam_normal = normalize(mul(UNITY_MATRIX_V, float4(normal, 0))); + const float3 cam_view_dir = normalize(mul(UNITY_MATRIX_V, float4(view_dir, 0))); + const float3 cam_refl = -reflect(cam_view_dir, cam_normal); + float m = 2.0 * sqrt( + cam_refl.x * cam_refl.x + + cam_refl.y * cam_refl.y + + (cam_refl.z + 1) * (cam_refl.z + 1)); + matcap_uv = cam_refl.xy / m + 0.5; + matcap_radius = length(matcap_uv - 0.5); + matcap_theta = atan2(matcap_uv.y - 0.5, matcap_uv.x - 0.5); + } +#endif +#if defined(_MATCAP1_DISTORTION0) + float2 distort_uv = matcap_distortion0(matcap_uv); + float2 matcap_uv = distort_uv; +#endif + float3 matcap = _Matcap1.SampleGrad(linear_repeat_s, matcap_uv, iddx, iddy) * _Matcap1Str; + + float q = _Matcap1Quantization; + if (q > 0) { + matcap = ceil(matcap * q) / q; + } + + matcap_mask *= _Matcap1MixFactor; int mode = round(_Matcap1Mode); switch (mode) { @@ -1322,6 +1382,7 @@ float4 effect(inout v2f i) albedo.rgb *= lerp(1, matcap, matcap_mask); break; case 2: + matcap_overwrite_mask = max(matcap_mask, matcap_overwrite_mask); albedo.rgb = lerp(albedo.rgb, matcap, matcap_mask); matcap_emission = lerp(albedo.rgb, matcap, matcap_mask) * _Matcap1Emission; break; @@ -1345,7 +1406,9 @@ float4 effect(inout v2f i) } #endif // _MATCAP0 || _MATCAP1 - mixOverlayAlbedoRoughnessMetallic(albedo, roughness, metallic, ov); + // TODO get rid of the pow. It's a hack to make matcap replace mode look + // better with overlay tattoos. + mixOverlayAlbedoRoughnessMetallic(albedo, roughness, metallic, ov, 1 - pow(matcap_overwrite_mask, 4)); #if defined(_DECAL0) || defined(_DECAL1) || defined(_DECAL2) || defined(_DECAL3) float3 decal_emission = 0; applyDecal(albedo, roughness, metallic, decal_emission, i); |
