summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2024-08-20 13:45:54 -0700
committeryum <yum.food.vr@gmail.com>2024-08-20 13:45:54 -0700
commitb7407fa9d7a917f7d62a7a2e12f96e90af11215c (patch)
treeb370eee4fb844036ac767eeb62ce166359225682
parentbf9496af5f27d548224689a123e97546fc2053b7 (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.cs28
-rw-r--r--feature_macros.cginc2
-rw-r--r--globals.cginc12
-rw-r--r--tooner.shader8
-rw-r--r--tooner_lighting.cginc133
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);