diff options
| -rw-r--r-- | Editor/tooner.cs | 745 | ||||
| -rw-r--r-- | audiolink.cginc | 13 | ||||
| -rw-r--r-- | clones.cginc | 34 | ||||
| -rw-r--r-- | globals.cginc | 105 | ||||
| -rw-r--r-- | interpolators.cginc | 50 | ||||
| -rw-r--r-- | iq_sdf.cginc | 102 | ||||
| -rw-r--r-- | math.cginc | 115 | ||||
| -rw-r--r-- | mochie_shadow_caster.cginc | 64 | ||||
| -rw-r--r-- | motion.cginc | 90 | ||||
| -rw-r--r-- | oklab.cginc | 126 | ||||
| -rw-r--r-- | pbr.cginc | 164 | ||||
| -rw-r--r-- | pema99.cginc | 36 | ||||
| -rw-r--r-- | poi.cginc | 60 | ||||
| -rw-r--r-- | shadertoy.cginc | 36 | ||||
| -rw-r--r-- | tooner.shader | 276 | ||||
| -rw-r--r-- | tooner_lighting.cginc | 589 | ||||
| -rw-r--r-- | tooner_outline_pass.cginc | 321 | ||||
| -rw-r--r-- | tooner_scroll.cginc | 47 |
18 files changed, 2973 insertions, 0 deletions
diff --git a/Editor/tooner.cs b/Editor/tooner.cs new file mode 100644 index 0000000..44306be --- /dev/null +++ b/Editor/tooner.cs @@ -0,0 +1,745 @@ +using System; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEditor; + +public class ToonerGUI : ShaderGUI { + Material target; + MaterialEditor editor; + MaterialProperty[] properties; + + public override void OnGUI( + MaterialEditor editor, + MaterialProperty[] properties) { + this.target = editor.target as Material; + this.editor = editor; + this.properties = properties; + DoMain(); + } + + static GUIContent staticLabel = new GUIContent(); + + static GUIContent MakeLabel(string prop, string tooltip = null) { + staticLabel.text = prop; + staticLabel.tooltip = tooltip; + return staticLabel; + } + + static GUIContent MakeLabel(MaterialProperty prop, string tooltip = null) { + staticLabel.text = prop.displayName; + staticLabel.tooltip = tooltip; + return staticLabel; + } + + void RecordAction (string label) { + editor.RegisterPropertyChangeUndo(label); + } + + MaterialProperty FindProperty(string label) { + return FindProperty(label, properties); + } + + void SetKeyword(string keyword, bool state) { + if (state) { + target.EnableKeyword(keyword); + } else { + target.DisableKeyword(keyword); + } + } + + void DoBaseColor() { + MaterialProperty bc = FindProperty("_BaseColor"); + MaterialProperty bct = FindProperty("_BaseColorTex"); + editor.TexturePropertySingleLine( + MakeLabel(bct, "Base color (RGBA)"), + bct, + bc); + SetKeyword("_BASECOLOR_MAP", bct.textureValue); + } + + void DoNormal() { + MaterialProperty bct = FindProperty("_NormalTex"); + editor.TexturePropertySingleLine( + MakeLabel(bct, "Normal"), + bct, + FindProperty("_Tex_NormalStr")); + SetKeyword("_NORMAL_MAP", bct.textureValue); + } + + void DoMetallic() { + MaterialProperty bc = FindProperty("_Metallic"); + MaterialProperty bct = FindProperty("_MetallicTex"); + editor.TexturePropertySingleLine( + MakeLabel(bct, "Metallic (RGBA)"), + bct, + bc); + SetKeyword("_METALLIC_MAP", bct.textureValue); + } + + void DoRoughness() { + MaterialProperty bc = FindProperty("_Roughness"); + MaterialProperty bct = FindProperty("_RoughnessTex"); + editor.TexturePropertySingleLine( + MakeLabel(bct, "Roughness (RGBA)"), + bct, + bc); + SetKeyword("_ROUGHNESS_MAP", bct.textureValue); + } + + void DoPBROverlay() { + MaterialProperty bc = FindProperty("_PBR_Overlay_Enable"); + bool enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Enable", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + SetKeyword("_PBR_OVERLAY", enabled); + + if (enabled) { + bc = FindProperty("_PBR_Overlay_BaseColor"); + MaterialProperty bct = FindProperty("_PBR_Overlay_BaseColorTex"); + editor.TexturePropertySingleLine( + MakeLabel(bct, "Base color (RGBA)"), + bct, + bc); + SetKeyword("_PBR_OVERLAY_BASECOLOR_MAP", bct.textureValue); + + bct = FindProperty("_PBR_Overlay_NormalTex"); + editor.TexturePropertySingleLine( + MakeLabel(bct, "Normal"), + bct, + FindProperty("_PBR_Overlay_Tex_NormalStr")); + SetKeyword("_PBR_OVERLAY_NORMAL_MAP", bct.textureValue); + + bc = FindProperty("_PBR_Overlay_Metallic"); + bct = FindProperty("_PBR_Overlay_MetallicTex"); + editor.TexturePropertySingleLine( + MakeLabel(bct, "Metallic (RGBA)"), + bct, + bc); + SetKeyword("_PBR_OVERLAY_METALLIC_MAP", bct.textureValue); + + bc = FindProperty("_PBR_Overlay_Roughness"); + bct = FindProperty("_PBR_Overlay_RoughnessTex"); + editor.TexturePropertySingleLine( + MakeLabel(bct, "Roughness (RGBA)"), + bct, + bc); + SetKeyword("_PBR_OVERLAY_ROUGHNESS_MAP", bct.textureValue); + } + } + + void DoCubemap() { + MaterialProperty bc = FindProperty("_Cubemap"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Cubemap"), + bc); + SetKeyword("_CUBEMAP", bc.textureValue); + } + + void DoBrightness() { + MaterialProperty bc; + + bc = FindProperty("_Min_Brightness"); + editor.RangeProperty( + bc, + "Min brightness"); + + bc = FindProperty("_Max_Brightness"); + editor.RangeProperty( + bc, + "Max brightness"); + } + + void DoEmission() { + MaterialProperty bc = FindProperty("_EmissionTex"); + MaterialProperty bct = FindProperty("_EmissionStrength"); + editor.TexturePropertySingleLine( + MakeLabel(bct, "Emission map"), + bc, + bct); + SetKeyword("_EMISSION", bc.textureValue); + } + + enum MatcapMode { + Add, + Multiply, + Replace, + Subtract, + Min, + Max, + } + + void DoMatcap() { + for (int i = 0; i < 2; i++) { + GUILayout.Label($"Matcap {i}", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + + MaterialProperty bc; + + bc = FindProperty($"_Matcap{i}"); + editor.TexturePropertySingleLine( + MakeLabel(bc, $"Matcap {i}"), + bc); + SetKeyword($"_MATCAP{i}", bc.textureValue); + + if (!bc.textureValue) { + EditorGUI.indentLevel -= 1; + continue; + } + + bc = FindProperty($"_Matcap{i}_Mask"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Mask"), + bc); + SetKeyword($"_MATCAP{i}_MASK", bc.textureValue); + + if (bc.textureValue) { + bc = FindProperty($"_Matcap{i}_Mask_Invert"); + bool enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Invert mask", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + } + + EditorGUI.BeginChangeCheck(); + bc = FindProperty($"_Matcap{i}Mode"); + MatcapMode mode = (MatcapMode) Math.Round(bc.floatValue); + mode = (MatcapMode) EditorGUILayout.EnumPopup( + MakeLabel("Matcap mode"), mode); + if (EditorGUI.EndChangeCheck()) { + RecordAction($"Matcap {i}"); + foreach (Material m in editor.targets) { + m.SetFloat($"_Matcap{i}Mode", (int) mode); + } + } + + bc = FindProperty($"_Matcap{i}Str"); + editor.FloatProperty( + bc, + "Matcap strength"); + EditorGUI.indentLevel -= 1; + } + } + + void DoRimLighting() { + GUILayout.Label($"Rim lighting", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + + MaterialProperty bc; + + bc = FindProperty("_Rim_Lighting_Enabled"); + bool enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Enable", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + SetKeyword($"_RIM_LIGHTING", enabled); + + if (!enabled) { + return; + } + + bc = FindProperty("_Rim_Lighting_Color"); + editor.ColorProperty(bc, "Color (RGB)"); + + bc = FindProperty($"_Rim_Lighting_Mask"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Mask"), + bc); + SetKeyword($"_RIM_LIGHTING_MASK", bc.textureValue); + + if (bc.textureValue) { + bc = FindProperty($"_Rim_Lighting_Mask_Invert"); + enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Invert mask", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + } + + EditorGUI.BeginChangeCheck(); + bc = FindProperty($"_Rim_Lighting_Mode"); + MatcapMode mode = (MatcapMode) Math.Round(bc.floatValue); + mode = (MatcapMode) EditorGUILayout.EnumPopup( + MakeLabel("Rim lighting mode"), mode); + if (EditorGUI.EndChangeCheck()) { + RecordAction("Rim lighting mode"); + foreach (Material m in editor.targets) { + m.SetFloat($"_Rim_Lighting_Mode", (int) mode); + } + } + + bc = FindProperty($"_Rim_Lighting_Center"); + editor.FloatProperty( + bc, + "Center"); + + bc = FindProperty($"_Rim_Lighting_Power"); + editor.FloatProperty( + bc, + "Power"); + + bc = FindProperty($"_Rim_Lighting_Strength"); + editor.FloatProperty( + bc, + "Strength"); + + EditorGUI.indentLevel -= 1; + } + + void DoShadingMode() { + MaterialProperty bc; + + /* + bc = FindProperty("_Shading_Mode"); + editor.RangeProperty( + bc, + "Shading mode (0=realistic,1=flat)"); + SetKeyword("_SHADING_MODE_FLAT", ((int) Math.Round(bc.floatValue, 0)) == 1); + */ + + bc = FindProperty("_Flatten_Mesh_Normals"); + bool enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Flatten normals", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + + bc = FindProperty("_Confabulate_Normals"); + enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Confabulate normals", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + } + + void DoOKLAB() { + MaterialProperty bc; + + bc = FindProperty("_OKLAB_Enabled"); + bool enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Enable", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + + SetKeyword("_OKLAB", enabled); + + if (enabled) { + bc = FindProperty("_OKLAB_Mask"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Mask"), + bc); + + bc = FindProperty("_OKLAB_Lightness_Shift"); + editor.RangeProperty( + bc, + "Lightness shift"); + bc = FindProperty("_OKLAB_Chroma_Shift"); + editor.RangeProperty( + bc, + "Chroma shift"); + bc = FindProperty("_OKLAB_Hue_Shift"); + editor.RangeProperty( + bc, + "Hue shift"); + } + } + + void DoClones() { + MaterialProperty bc; + + bc = FindProperty("_Clones_Enabled"); + bool enabled = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Enable", enabled); + EditorGUI.EndChangeCheck(); + bc.floatValue = enabled ? 1.0f : 0.0f; + + SetKeyword("_CLONES", enabled); + + if (enabled) { + bc = FindProperty("_Clones_Count"); + editor.RangeProperty( + bc, + "Number of clones"); + bc = FindProperty("_Clones_dx"); + editor.RangeProperty( + bc, + "x offset"); + } + } + + void DoOutlines() { + MaterialProperty bc; + + bc = FindProperty("_Outline_Width"); + editor.RangeProperty( + bc, + "Outline width"); + SetKeyword("_OUTLINES", bc.floatValue > 1E-6); + + if (bc.floatValue > 1E-6) { + bc = FindProperty("_Outline_Color"); + editor.ColorProperty( + bc, + "Outline color (RGBA)"); + + bc = FindProperty("_Outline_Emission_Strength"); + editor.RangeProperty( + bc, + "Outline emission strength"); + + bc = FindProperty("_Outline_Mask"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Outline mask"), + bc); + + bc = FindProperty("_Outline_Mask_Invert"); + bool inverted = bc.floatValue > 1E-6; + EditorGUI.BeginChangeCheck(); + inverted = EditorGUILayout.Toggle("Invert mask", inverted); + EditorGUI.EndChangeCheck(); + bc.floatValue = inverted ? 1.0f : 0.0f; + } + } + + void DoGlitter() { + MaterialProperty bc = FindProperty("_Glitter_Enabled"); + bool enabled = bc.floatValue > 1E-6; + + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Enable", enabled); + EditorGUI.EndChangeCheck(); + SetKeyword("_GLITTER", enabled); + bc.floatValue = enabled ? 1.0f : 0.0f; + + if (enabled) { + bc = FindProperty("_Glitter_Mask"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Glitter mask (RGBA)"), + bc); + + bc = FindProperty("_Glitter_Density"); + editor.FloatProperty( + bc, + "Glitter density"); + + bc = FindProperty("_Glitter_Amount"); + editor.FloatProperty( + bc, + "Glitter amount"); + + bc = FindProperty("_Glitter_Speed"); + editor.FloatProperty( + bc, + "Glitter speed"); + + bc = FindProperty("_Glitter_Brightness"); + editor.FloatProperty( + bc, + "Glitter brightness"); + + bc = FindProperty("_Glitter_Angle"); + editor.FloatProperty( + bc, + "Glitter angle"); + } + } + + void DoExplosion() { + MaterialProperty bc = FindProperty("_Explode_Toggle"); + bool enabled = bc.floatValue > 1E-6; + + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Enable", enabled); + EditorGUI.EndChangeCheck(); + SetKeyword("_EXPLODE", enabled); + bc.floatValue = enabled ? 1.0f : 0.0f; + + bc = FindProperty("_Explode_Phase"); + if (enabled) { + editor.RangeProperty( + bc, + "Explosion phase"); + } else { + bc.floatValue = 0.0f; + } + bc = FindProperty("_OutlinesCull"); + bc.floatValue = (float) UnityEngine.Rendering.CullMode.Front; + + /* + if (enabled) { + bc = FindProperty("_Explode_Phase"); + editor.RangeProperty( + bc, + "Explosion phase"); + if (bc.floatValue > 1E-3) { + bc = FindProperty("_Cull"); + bc.floatValue = (float) UnityEngine.Rendering.CullMode.Back; + } else { + bc = FindProperty("_Cull"); + bc.floatValue = (float) UnityEngine.Rendering.CullMode.Front; + } + } else { + bc = FindProperty("_Explode_Phase"); + bc.floatValue = 0.0f; + bc = FindProperty("_Cull"); + bc.floatValue = (float) UnityEngine.Rendering.CullMode.Front; + } + */ + } + + void DoGeoScroll() { + MaterialProperty bc = FindProperty("_Scroll_Toggle"); + bool enabled = bc.floatValue > 1E-6; + + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Enable", enabled); + EditorGUI.EndChangeCheck(); + SetKeyword("_SCROLL", enabled); + bc.floatValue = enabled ? 1.0f : 0.0f; + + if (enabled) { + bc = FindProperty("_Scroll_Top"); + editor.RangeProperty( + bc, + "Scroll top"); + + bc = FindProperty("_Scroll_Bottom"); + editor.RangeProperty( + bc, + "Scroll bottom"); + + bc = FindProperty("_Scroll_Width"); + editor.RangeProperty( + bc, + "Scroll width"); + + bc = FindProperty("_Scroll_Strength"); + editor.RangeProperty( + bc, + "Scroll strength"); + + bc = FindProperty("_Scroll_Speed"); + editor.RangeProperty( + bc, + "Scroll speed"); + } + } + + void DoUVScroll() { + MaterialProperty bc = FindProperty("_UVScroll_Enabled"); + bool enabled = bc.floatValue > 1E-6; + + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Enable", enabled); + EditorGUI.EndChangeCheck(); + SetKeyword("_UVSCROLL", enabled); + bc.floatValue = enabled ? 1.0f : 0.0f; + + if (enabled) { + bc = FindProperty("_UVScroll_Mask"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Mask"), + bc); + + bc = FindProperty("_UVScroll_U_Speed"); + editor.FloatProperty( + bc, + "U speed"); + + bc = FindProperty("_UVScroll_V_Speed"); + editor.FloatProperty( + bc, + "V speed"); + + bc = FindProperty("_UVScroll_Alpha"); + editor.TexturePropertySingleLine( + MakeLabel(bc, "Alpha"), + bc); + } + } + + void DoChainTessellation() { + MaterialProperty bc = FindProperty("_Enable_Chain_Tessellation"); + bool enabled = bc.floatValue > 1E-6; + + EditorGUI.BeginChangeCheck(); + enabled = EditorGUILayout.Toggle("Enable", enabled); + EditorGUI.EndChangeCheck(); + SetKeyword("_CHAIN_TESSELLATION", enabled); + bc.floatValue = enabled ? 1.0f : 0.0f; + + if (enabled) { + bc = FindProperty("_Chain_Tess_Factor"); + editor.RangeProperty( + bc, + "Tessellation factor"); + } + } + + enum RenderingMode { + Opaque, + Cutout, + Fade + } + + void DoRendering() { + RenderingMode mode = RenderingMode.Opaque; + if (target.IsKeywordEnabled("_RENDERING_CUTOUT")) { + mode = RenderingMode.Cutout; + } else if (target.IsKeywordEnabled("_RENDERING_FADE")) { + mode = RenderingMode.Fade; + } + + EditorGUI.BeginChangeCheck(); + mode = (RenderingMode) EditorGUILayout.EnumPopup( + MakeLabel("Rendering Mode"), mode); + BlendMode src_blend = BlendMode.One; + BlendMode dst_blend = BlendMode.Zero; + bool zwrite = false; + + if (EditorGUI.EndChangeCheck()) { + RecordAction("Rendering Mode"); + SetKeyword("_RENDERING_CUTOUT", mode == RenderingMode.Cutout); + SetKeyword("_RENDERING_FADE", mode == RenderingMode.Fade); + + RenderQueue queue = RenderQueue.Geometry; + string render_type = ""; + switch (mode) { + case RenderingMode.Opaque: + queue = RenderQueue.Geometry; + render_type = ""; + src_blend = BlendMode.One; + dst_blend = BlendMode.Zero; + zwrite = true; + break; + case RenderingMode.Cutout: + queue = RenderQueue.AlphaTest; + render_type = "TransparentCutout"; + src_blend = BlendMode.One; + dst_blend = BlendMode.Zero; + zwrite = true; + break; + case RenderingMode.Fade: + queue = RenderQueue.Transparent; + render_type = "Transparent"; + src_blend = BlendMode.SrcAlpha; + dst_blend = BlendMode.OneMinusSrcAlpha; + zwrite = false; + break; + } + foreach (Material m in editor.targets) { + m.renderQueue = (int) queue; + m.SetOverrideTag("RenderType", render_type); + m.SetInt("_SrcBlend", (int) src_blend); + m.SetInt("_DstBlend", (int) dst_blend); + m.SetInt("_ZWrite", zwrite ? 1 : 0); + } + } + + MaterialProperty bc; + if (mode == RenderingMode.Cutout) { + bc = FindProperty("_Alpha_Cutoff"); + editor.ShaderProperty(bc, MakeLabel(bc)); + } + + bc = FindProperty("_Cull"); + UnityEngine.Rendering.CullMode cull_mode = (UnityEngine.Rendering.CullMode) bc.floatValue; + EditorGUI.BeginChangeCheck(); + cull_mode = (UnityEngine.Rendering.CullMode) EditorGUILayout.EnumPopup( + MakeLabel("Culling mode"), cull_mode); + if (EditorGUI.EndChangeCheck()) { + RecordAction("Culling mode"); + bc.floatValue = (float) cull_mode; + } + } + + void DoMain() { + SetKeyword("VERTEXLIGHT_ON", false); + + GUILayout.Label("PBR", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoBaseColor(); + DoNormal(); + DoMetallic(); + DoRoughness(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("PBR overlay", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoPBROverlay(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("Lighting", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoCubemap(); + DoBrightness(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("Emission", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoEmission(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("Shading", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoShadingMode(); + EditorGUI.indentLevel -= 1; + + DoMatcap(); + DoRimLighting(); + + GUILayout.Label("Outlines", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoOutlines(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("Glitter", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoGlitter(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("Explosion", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoExplosion(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("Geometry scroll", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoGeoScroll(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("UV scroll", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoUVScroll(); + EditorGUI.indentLevel -= 1; + + /* + GUILayout.Label("Chain tessellation", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoChainTessellation(); + EditorGUI.indentLevel -= 1; + */ + + GUILayout.Label("Hue shift", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoOKLAB(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("Clones", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoClones(); + EditorGUI.indentLevel -= 1; + + GUILayout.Label("Rendering", EditorStyles.boldLabel); + EditorGUI.indentLevel += 1; + DoRendering(); + EditorGUI.indentLevel -= 1; + } +} + + diff --git a/audiolink.cginc b/audiolink.cginc new file mode 100644 index 0000000..06bbec7 --- /dev/null +++ b/audiolink.cginc @@ -0,0 +1,13 @@ +// Upgrade NOTE: replaced 'defined _AUDIOLINK' with 'defined (_AUDIOLINK)' + +#ifndef __AUDIOLINK +#define __AUDIOLINK + +#if defined (_AUDIOLINK) + +#include "Packages/com.llealloo.audiolink/Runtime/Shaders/AudioLink.cginc" + +#endif // _AUDIOLINK + +#endif // __AUDIOLINK + diff --git a/clones.cginc b/clones.cginc new file mode 100644 index 0000000..6369fee --- /dev/null +++ b/clones.cginc @@ -0,0 +1,34 @@ +#ifndef __CLONES_INC +#define __CLONES_INC + +#if defined(_CLONES) + +#include "interpolators.cginc" +#include "globals.cginc" + +void add_clones(in v2f clone_verts[3], inout TriangleStream<v2f> tri_out) +{ + if (_Clones_dx < 1E-6) { + return; + } + + uint n_clones = (uint) round(_Clones_Count); + for (uint i = 0; i < (uint) n_clones; i++) { + for (uint j = 0; j < 3; j++) { + v2f ii = clone_verts[j]; + float3 objPos = mul(unity_WorldToObject, float4(ii.worldPos, 1)).xyz; + float offset = i; + offset = ((offset % 2) * 2 - 1) * (((offset) / 2) + 1) * _Clones_dx; + objPos.x += offset; + ii.worldPos = mul(unity_ObjectToWorld, float4(objPos, 1)).xyz; + ii.clipPos = UnityObjectToClipPos(objPos); + tri_out.Append(ii); + } + tri_out.RestartStrip(); + } +} + +#endif // _CLONES + +#endif // __CLONES_INC + diff --git a/globals.cginc b/globals.cginc new file mode 100644 index 0000000..748ee04 --- /dev/null +++ b/globals.cginc @@ -0,0 +1,105 @@ +#ifndef __GLOBALS_INC +#define __GLOBALS_INC + +#include "AutoLight.cginc" + +float4 _BaseColor; +float _Metallic; +float _Roughness; + +texture2D _BaseColorTex; +texture2D _NormalTex; +texture2D _MetallicTex; +texture2D _RoughnessTex; + +float4 _PBR_Overlay_BaseColor; +float _PBR_Overlay_Metallic; +float _PBR_Overlay_Roughness; +texture2D _PBR_Overlay_BaseColorTex; +texture2D _PBR_Overlay_NormalTex; +texture2D _PBR_Overlay_MetallicTex; +texture2D _PBR_Overlay_RoughnessTex; +float _PBR_Overlay_Tex_NormalStr; + +texture2D _EmissionTex; +float _EmissionStrength; + +SamplerState linear_repeat_s; + +float _Tex_NormalStr; +float _NormalStr; + +float _Min_Brightness; +float _Max_Brightness; + +float _Alpha_Cutoff; + +float _Flatten_Mesh_Normals; +float _Confabulate_Normals; + +float _Outline_Width; +float4 _Outline_Color; +float _Outline_Emission_Strength; +texture2D _Outline_Mask; +float _Outline_Mask_Invert; + +texture2D _Glitter_Mask; +float _Glitter_Density; +float _Glitter_Amount; +float _Glitter_Speed; +float _Glitter_Seed; +float _Glitter_Brightness; +float _Glitter_Angle; + +float _Explode_Phase; + +float _Scroll_Toggle; +float _Scroll_Top; +float _Scroll_Bottom; +float _Scroll_Width; +float _Scroll_Strength; +float _Scroll_Speed; + +float _Chain_Tess_Factor; + +float _Enable_Matcap0; +texture2D _Matcap0; +texture2D _Matcap0_Mask; +float _Matcap0_Mask_Invert; +float _Matcap0Str; +float _Matcap0Mode; + +float _Enable_Matcap1; +texture2D _Matcap1; +texture2D _Matcap1_Mask; +float _Matcap1_Mask_Invert; +float _Matcap1Str; +float _Matcap1Mode; + +float _Rim_Lighting_Enabled; +float _Rim_Lighting_Mode; +float3 _Rim_Lighting_Color; +texture2D _Rim_Lighting_Mask; +float _Rim_Lighting_Mask_Invert; +float _Rim_Lighting_Center; +float _Rim_Lighting_Power; +float _Rim_Lighting_Strength; + +float _OKLAB_Enabled; +texture2D _OKLAB_Mask; +float _OKLAB_Lightness_Shift; +float _OKLAB_Chroma_Shift; +float _OKLAB_Hue_Shift; + +float _Clones_Enabled; +float _Clones_Count; +float _Clones_dx; + +float _UVScroll_Enabled; +texture2D _UVScroll_Mask; +float _UVScroll_U_Speed; +float _UVScroll_V_Speed; +texture2D _UVScroll_Alpha; + +#endif + diff --git a/interpolators.cginc b/interpolators.cginc new file mode 100644 index 0000000..9b9bcb2 --- /dev/null +++ b/interpolators.cginc @@ -0,0 +1,50 @@ +#ifndef __INTERPOLATORS_INC +#define __INTERPOLATORS_INC + +#include "AutoLight.cginc" + +#if defined(_OUTLINE_INTERPOLATORS) + +struct appdata +{ + float4 vertex : POSITION; + float3 normal : NORMAL; + float2 uv : TEXCOORD0; +}; + +struct v2f +{ + float4 clipPos : POSITION; + float2 uv : TEXCOORD0; + float3 worldPos : TEXCOORD1; + float3 normal : TEXCOORD2; +}; + +#else + +struct appdata +{ + float4 position : POSITION; + float2 uv : TEXCOORD0; + float3 normal : NORMAL; + float4 tangent : TANGENT; +}; + +struct v2f +{ + float4 clipPos : SV_POSITION; + float2 uv : TEXCOORD0; + float3 normal : TEXCOORD1; + float4 tangent : TEXCOORD2; + float3 worldPos : TEXCOORD3; + + SHADOW_COORDS(4) + + #if defined(VERTEXLIGHT_ON) + float3 vertexLightColor : TEXCOORD5; + #endif +}; +#endif + +#endif // __INTERPOLATORS_INC + diff --git a/iq_sdf.cginc b/iq_sdf.cginc new file mode 100644 index 0000000..472256c --- /dev/null +++ b/iq_sdf.cginc @@ -0,0 +1,102 @@ +#include "pema99.cginc" + +// The MIT License +// Copyright © 2019-2021 Inigo Quilez +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +float distance_from_octahedron(in float3 p) +{ + float s = 1.0; + float3 pp = abs(p); + float m = pp.x+pp.y+pp.z-s; + float3 q; + if( 3.0*pp.x < m ) q = pp.xyz; + else if( 3.0*pp.y < m ) q = pp.yzx; + else if( 3.0*pp.z < m ) q = pp.zxy; + else return m*0.57735027; + + float k = clamp(0.5*(q.z-q.y+s),0.0,s); + return length(float3(q.x,q.y-s+k,q.z-k)); +} + +float distance_from_sphere(float3 p, float r) +{ + return length(p) - r; +} + +float distance_from_cut_sphere( in float3 p, in float r, in float h ) +{ + float w = sqrt(r*r-h*h); // constant for a given shape + + float2 q = float2( length(p.xz), p.y ); + + float s = max( (h-r)*q.x*q.x+w*w*(h+r-2.0*q.y), h*q.x-w*q.y ); + + return (s<0.0) ? length(q)-r : + (q.x<w) ? h - q.y : + length(q-float2(w,h)); +} + +float distance_from_cut_hollow_sphere( float3 p, float r, float h, float t ) +{ + float2 q = float2( length(p.xz), p.y ); + + float w = sqrt(r*r-h*h); + + return ((h*q.x<w*q.y) ? length(q-float2(w,h)) : + abs(length(q)-r) ) - t; +} + +float distance_from_box(float3 p, float3 b) +{ + float3 q = abs(p) - b; + return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0); +} + +float distance_from_box_frame(float3 p, float3 b, float e) +{ + p = abs(p)-b; + float3 q = abs(p+e)-e; + + return min(min( + length(max(float3(p.x,q.y,q.z),0.0))+min(max(p.x,max(q.y,q.z)),0.0), + length(max(float3(q.x,p.y,q.z),0.0))+min(max(q.x,max(p.y,q.z)),0.0)), + length(max(float3(q.x,q.y,p.z),0.0))+min(max(q.x,max(q.y,p.z)),0.0)); +} + +float distance_from_pyramid(float3 p, float h, bool invert) +{ + float m2 = h*h + 0.25; + + // symmetry + p.xz = abs(p.xz); // do p=abs(p) instead for double pyramid + p.xz = (p.z>p.x) ? p.zx : p.xz; + p.xz -= 0.5; + + // project into face plane (2D) + float3 q = float3( p.z, h*p.y-0.5*p.x, h*p.x+0.5*p.y); + + float s = max(-q.x,0.0); + float t = clamp( (q.y-0.5*q.x)/(m2+0.25), 0.0, 1.0 ); + + float a = m2*(q.x+s)*(q.x+s) + q.y*q.y; + float b = m2*(q.x+0.5*t)*(q.x+0.5*t) + (q.y-m2*t)*(q.y-m2*t); + + float d2 = max(-q.y,q.x*m2+q.y*0.5) < 0.0 ? 0.0 : min(a,b); + + // recover 3D and scale, and add sign + return sqrt( (d2+q.z*q.z)/m2 ) * sign(max(q.z,-p.y));; +} + +float distance_from_plane(float3 p, float3 n, float h) +{ + // n must be normalized + return dot(p,n) + h; +} + +float3 op_rep(in float3 p, in float3 c) +{ + return glsl_mod(p+0.5*c,c)-0.5*c; +} + +// End licensed section diff --git a/math.cginc b/math.cginc new file mode 100644 index 0000000..747c5c2 --- /dev/null +++ b/math.cginc @@ -0,0 +1,115 @@ +#ifndef __MATH_INC +#define __MATH_INC + +#include "pema99.cginc" + +float4 qmul(float4 q1, float4 q2) +{ + return float4( + q2.xyz * q1.w + q1.xyz * q2.w + cross(q1.xyz, q2.xyz), + q1.w * q2.w - dot(q1.xyz, q2.xyz) + ); +} + +// Vector rotation with a quaternion +// http://mathworld.wolfram.com/Quaternion.html +float3 rotate_vector(float3 v, float4 r) +{ + float4 r_c = r * float4(-1, -1, -1, 1); + return qmul(r, qmul(float4(v, 0), r_c)).xyz; +} + +float4 get_quaternion(float3 axis_normal, float theta) { + return float4( + axis_normal * sin(theta / 2), cos(theta / 2)); +} + +// Differentiable approximation of the standard `max` function. +float dmax(float a, float b, float k) +{ + return log2(exp2(k * a) + exp2(k * b)) / k; +} + +// Differentiable approximation of the standard `min` function. +float dmin(float a, float b, float k) +{ + return -1.0 * dmax(-1.0 * a, -1.0 * b, k); +} + +float dabs(float a, float k) +{ + return log2(exp2(k * a) + exp2(-1.0 * k * a)); +} + +float rand(uint seed) { + seed = seed * 747796405 + 2891336453; + uint result = ((seed >> ((seed >> 28) + 4)) ^ seed) * 277803737; + result = (result >> 22) ^ result; + return result / 4294967295.0; +} + +// Generate a random number on [0, 1]. +float rand2(float2 p) +{ + return glsl_mod(sin(dot(p, float2(561.0, 885.0))) * 776.2, 1.0); +} + +// Generate a random number on [0, 1]. +float rand3(float3 p) +{ + return glsl_mod(sin(dot(p, float3(897.0, 367.0, 197.0))) * 1073.6, 1.0); +} + +float length2(float2 p) +{ + return p.x * p.x + p.y * p.y; +} + +// 3 dimensional value noise. `p` is assumed to be a point inside a unit cube. +// Theory: https://en.wikipedia.org/wiki/Value_noise +float vnoise3d(float3 p) +{ + float3 pu = floor(p); + float3 pv = glsl_mod(frac(p), 1.0); + + // Assign random numbers to the corner of a cube. + float n000 = rand3(pu + float3(0,0,0)); + float n001 = rand3(pu + float3(0,0,1)); + float n010 = rand3(pu + float3(0,1,0)); + float n011 = rand3(pu + float3(0,1,1)); + float n100 = rand3(pu + float3(1,0,0)); + float n101 = rand3(pu + float3(1,0,1)); + float n110 = rand3(pu + float3(1,1,0)); + float n111 = rand3(pu + float3(1,1,1)); + + float n00 = lerp(n000, n001, pv.z); + float n01 = lerp(n010, n011, pv.z); + float n10 = lerp(n100, n101, pv.z); + float n11 = lerp(n110, n111, pv.z); + + float n0 = lerp(n00, n01, pv.y); + float n1 = lerp(n10, n11, pv.y); + + float n = lerp(n0, n1, pv.x); + + return n; +} + +float fbm(float3 p, const int n_octaves, float w) +{ + float g = exp2(-w); + float a = 1.0; + float p_scale = 1.0; + + float res = 0.0; + for (int i = 0; i < n_octaves; i++) { + res += a * vnoise3d(p * p_scale); + + p_scale /= w; + a *= g; + } + return res; +} + +#endif // __MATH_INC + diff --git a/mochie_shadow_caster.cginc b/mochie_shadow_caster.cginc new file mode 100644 index 0000000..2240f5e --- /dev/null +++ b/mochie_shadow_caster.cginc @@ -0,0 +1,64 @@ +#ifndef __MOCHIE_SHADOW_CASTER_INC +#define __MOCHIE_SHADOW_CASTER_INC + +// Source: https://github.com/cnlohr/shadertrixx?tab=readme-ov-file#shadowcasting +// MIT License +// +// NOTE: Much content here is originally from others. Content in third party +// folder may not be fully MIT-licensable. +// +// Copyright (c) 2021 cnlohr, et. al. +// +// All other content in this repository falls under the following terms: +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma vertex vert +#pragma fragment frag +#pragma multi_compile_instancing +#pragma multi_compile_shadowcaster +#include "UnityCG.cginc" + +struct appdata { + float4 vertex : POSITION; + float3 normal : NORMAL; + UNITY_VERTEX_INPUT_INSTANCE_ID +}; + +struct v2f { + float4 pos : SV_POSITION; + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO +}; + +v2f vert (appdata v){ + v2f o = (v2f)0; + UNITY_SETUP_INSTANCE_ID(v); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) + return o; +} + +float4 frag (v2f i) : SV_Target { + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); + return 0; +} + +#endif // __MOCHIE_SHADOW_CASTER_INC + diff --git a/motion.cginc b/motion.cginc new file mode 100644 index 0000000..d6458e9 --- /dev/null +++ b/motion.cginc @@ -0,0 +1,90 @@ +#ifndef MOTION_ +#define MOTION_ + +// xyz represent quaternion vector, w represents theta. +typedef float4 Quaternion; + +// Math from here: +// https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation +float3 qrot(in float3 v, in Quaternion q) +{ + float a = q.w; + float b = q.x; + float c = q.y; + float d = q.z; + + float a2 = a*a; + float b2 = b*b; + float c2 = c*c; + float d2 = d*d; + + float3x3 rot = float3x3( + (a2 + b2 - c2) - d2, 2*b*c - 2*a*d, 2*b*d + 2*a*c, + 2*b*c + 2*a*d, (a2 - b2) + (c2 - d2), 2*c*d - 2*a*b, + 2*b*d - 2*a*c, 2*c*d + 2*a*b, ((a2 - b2) - c2) + d2 + ); + + return mul(rot, v); +} + +Quaternion qinv(in Quaternion q) +{ + return Quaternion(q.xyz, -q.w); +} + +// Multiply two quaternions. +// Math from here: https://www.haroldserrano.com/blog/quaternions-in-computer-graphics +Quaternion qmul(in Quaternion a, in Quaternion b) +{ + return Quaternion(a.w * b.xyz + b.w * a.xyz + cross(a.xyz, b.xyz), a.w * b.w - dot(a.xyz, b.xyz)); +} + +float4 affine3(in float3 m) +{ + return float4(m, 1.0); +} + +float4x4 affine3x3(in float3x3 m) +{ + return float4x4( + m[0][0], m[0][1], m[0][2], 0, + m[1][0], m[1][1], m[1][2], 0, + m[2][0], m[2][1], m[2][2], 0, + 0, 0, 0, 1 + ); +} + +float4x4 eye() +{ + return float4x4( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ); +} + +// Return affine translation matrix. +float4x4 translate(in float dx, in float dy, in float dz) +{ + return float4x4( + 1, 0, 0, dx, + 0, 1, 0, dy, + 0, 0, 1, dz, + 0, 0, 0, 1 + ); +} + +// Return affine scaling matrix. +float4x4 scale(in float sx, in float sy, in float sz) +{ + return float4x4( + sx, 0, 0, 0, + 0, sy, 0, 0, + 0, 0, sz, 0, + 0, 0, 0, 1 + ); +} + +#endif // MOTION_ + diff --git a/oklab.cginc b/oklab.cginc new file mode 100644 index 0000000..4c33428 --- /dev/null +++ b/oklab.cginc @@ -0,0 +1,126 @@ +/* + * MIT License + * + * Copyright (c) 2023 yum_food + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE + * SOFTWARE. + */ + +#ifndef __OKLAB_INC +#define __OKLAB_INC + +#if defined(_OKLAB) + +// Utilities relating to the OKLAB color space, as defined here: +// https://bottosson.github.io/posts/oklab/ +// Code is derived from the samples there, which are in the public domain. + +// Weights: https://en.wikipedia.org/wiki/SRGB +float3 LRGBtoXYZ(float3 c) { + float3x3 rgb_to_xyz = float3x3( + 0.4124, 0.3576, 0.1805, + 0.2126, 0.7152, 0.0722, + 0.0193, 0.1192, 0.9505 + ); + return mul(rgb_to_xyz, c); +} + +// Weights: https://en.wikipedia.org/wiki/SRGB +float3 XYZtoLRGB(float3 c) { + float3x3 xyz_to_rgb = float3x3( + 3.24062548, -1.53720797, -0.4986286, + -0.96893071, 1.87575606, 0.04151752, + 0.05571012, -0.20402105, 1.05699594 + ); + return mul(xyz_to_rgb, c); +} + +// Source: https://bottosson.github.io/posts/oklab/ +float3 XYZtoOKLAB(float3 c) { + float3x3 m1 = float3x3( + 0.8189, 0.3618, -0.1288, + 0.0329, 0.9293, 0.0361, + 0.0482, 0.2643, 0.6338 + ); + float3x3 m2 = float3x3( + 0.2104, 0.7936, -0.0040, + 1.9779, -2.4285, 0.4505, + 0.0259, 0.7827, -0.8086 + ); + c = mul(m1, c); + c = pow(c, 0.33333333333); + return mul(m2, c); +} + +// Source: https://bottosson.github.io/posts/oklab/ +float3 OKLABtoXYZ(float3 c) { + float3x3 m1i = float3x3( + 1.22700842, -0.5576564 , 0.28111404, + -0.04047048, 1.11219073, -0.07157255, + -0.07643651, -0.42138367, 1.58625265 + ); + float3x3 m2i = float3x3( + 1.00003964, 0.39638005, 0.21589049, + 0.99998945, -0.10553958, -0.06374665, + 0.99999105, -0.08946276, -1.291495 + ); + c = mul(m2i, c); + c = pow(c, 3); + return mul(m1i, c); +} + +// Source: https://bottosson.github.io/posts/oklab/ +float3 OKLABtoOKLCH(float3 c) { + float c_ = length(c.yz); + float h_ = atan2(c.z, c.y); + return float3(c.x, c_, h_); +} + +// Source: https://bottosson.github.io/posts/oklab/ +// Note: hue must be in units of radians. +float3 OKLCHtoOKLAB(float3 c) { + float a = c.y * cos(c.z); + float b = c.y * sin(c.z); + return float3(c.x, a, b); +} + +float3 LRGBtoOKLAB(float3 c) { + return XYZtoOKLAB(LRGBtoXYZ(c)); +} + +float3 OKLABtoLRGB(float3 c) { + return XYZtoLRGB(OKLABtoXYZ(c)); +} + +float3 LRGBtoOKLCH(float3 c) { + return OKLABtoOKLCH(XYZtoOKLAB(LRGBtoXYZ(c))); +} + +float3 OKLCHtoLRGB(float3 c) { + return XYZtoLRGB(OKLABtoXYZ(OKLCHtoOKLAB(c))); +} + +#endif // _OKLAB + +#endif // __OKLAB_INC + diff --git a/pbr.cginc b/pbr.cginc new file mode 100644 index 0000000..182c1ff --- /dev/null +++ b/pbr.cginc @@ -0,0 +1,164 @@ +#ifndef __PBR_INC +#define __PBR_INC + +#include "AutoLight.cginc" +#include "UnityPBSLighting.cginc" + +#include "globals.cginc" +#include "interpolators.cginc" +#include "poi.cginc" + +UNITY_DECLARE_TEXCUBE(_Cubemap); + +UnityLight CreateDirectLight(float3 normal, v2f i) +{ + UNITY_LIGHT_ATTENUATION(attenuation, i, i.worldPos); + UnityLight light; + light.color = _LightColor0.rgb * attenuation; +#if defined(POINT) || defined(POINT_COOKIE) || defined(SPOT) + light.dir = normalize((_WorldSpaceLightPos0 - i.worldPos).xyz); +#else + light.dir = _WorldSpaceLightPos0; +#endif + if (round(_Confabulate_Normals)) { + light.dir = normal; + } + light.ndotl = DotClamped(normal, light.dir); + + return light; +} + +float GetRoughness(float smoothness) { + float r = 1 - smoothness; + r *= 1.7 - 0.7 * r; + return r; +} + +float3 BoxProjection ( + float3 direction, float3 position, + float4 cubemapPosition, float3 boxMin, float3 boxMax +) { + #if UNITY_SPECCUBE_BOX_PROJECTION + UNITY_BRANCH + if (cubemapPosition.w > 0) { + float3 factors = + ((direction > 0 ? boxMax : boxMin) - position) / direction; + float scalar = min(min(factors.x, factors.y), factors.z); + direction = direction * scalar + (position - cubemapPosition); + } + #endif + return direction; +} + +UnityIndirect CreateIndirectLight(float4 vertexLightColor, float3 view_dir, float3 normal, + float smoothness, float3 worldPos, float2 uv) { + UnityIndirect indirect; + indirect.diffuse = vertexLightColor; + indirect.specular = 0; + +#if defined(FORWARD_BASE_PASS) + indirect.diffuse += max(0, ShadeSH9(float4(normal, 1))); + float3 reflect_dir = reflect(-view_dir, normal); + Unity_GlossyEnvironmentData env_data; + env_data.roughness = GetRoughness(smoothness); + env_data.reflUVW = BoxProjection( + reflect_dir, worldPos, + unity_SpecCube0_ProbePosition, + unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax + ); + float3 probe0 = Unity_GlossyEnvironment( + UNITY_PASS_TEXCUBE(unity_SpecCube0), unity_SpecCube0_HDR, env_data + ); + env_data.reflUVW = BoxProjection( + reflect_dir, worldPos, + unity_SpecCube1_ProbePosition, + unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax + ); +#if UNITY_SPECCUBE_BLENDING + float interpolator = unity_SpecCube0_BoxMin.w; + UNITY_BRANCH + if (interpolator < 0.99999) { + float3 probe1 = Unity_GlossyEnvironment( + UNITY_PASS_TEXCUBE_SAMPLER(unity_SpecCube1, unity_SpecCube0), + unity_SpecCube0_HDR, env_data + ); + indirect.specular = lerp(probe1, probe0, interpolator); + } + else { + indirect.specular = probe0; + } +#else + indirect.specular = probe0; +#endif // UNITY_SPECCUBE_BLENDING + +#if defined(_CUBEMAP) + float roughness = GetRoughness(smoothness); + probe0 = + UNITY_SAMPLE_TEXCUBE_LOD( + _Cubemap, + reflect_dir, + roughness * UNITY_SPECCUBE_LOD_STEPS); +#endif // _CUBEMAP + + indirect.specular = probe0; +#endif // FORWARD_BASE_PASS + + return indirect; +} + +float4 getLitColor( + float4 vertexLightColor, + float4 albedo, + float3 worldPos, + float3 normal, + float metallic, float smoothness, float2 uv, v2f i) +{ + float3 specular_tint; + float one_minus_reflectivity; + albedo.rgb = DiffuseAndSpecularFromMetallic( + albedo, metallic, specular_tint, one_minus_reflectivity); + + float3 view_dir = normalize(_WorldSpaceCameraPos - worldPos); + + bool flat = round(_Flatten_Mesh_Normals) == 1.0; + UnityIndirect indirect_light = CreateIndirectLight(vertexLightColor, + view_dir, flat ? view_dir : normal, smoothness, worldPos, uv); + + UnityLight direct_light = CreateDirectLight(normal, i); + if (flat) { + float e = 0.8; + indirect_light.diffuse += direct_light.color * e; + direct_light.color *= (1 - e); + } + + indirect_light.diffuse = clamp(indirect_light.diffuse, _Min_Brightness, _Max_Brightness); + indirect_light.specular = clamp(indirect_light.specular, _Min_Brightness, _Max_Brightness); + + float3 pbr; + if (round(_Confabulate_Normals)) { + pbr = UNITY_BRDF_PBS( + albedo, + specular_tint, + one_minus_reflectivity, + smoothness, + view_dir, + flat ? view_dir : normal, + direct_light, + indirect_light).xyz; + } else { + pbr = UNITY_BRDF_PBS( + albedo, + specular_tint, + one_minus_reflectivity, + smoothness, + flat ? view_dir : normal, + view_dir, + direct_light, + indirect_light).xyz; + } + + return float4(pbr, albedo.a); +} + +#endif // __PBR_INC + diff --git a/pema99.cginc b/pema99.cginc new file mode 100644 index 0000000..1c4b746 --- /dev/null +++ b/pema99.cginc @@ -0,0 +1,36 @@ +/* +MIT License + +Copyright (c) 2022 Pema Malling + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef __PEMA_99_INC +#define __PEMA_99_INC + +#define glsl_mod(x,y) (((x)-(y)*floor((x)/(y)))) + +bool isInMirror() +{ + return unity_CameraProjection[2][0] != 0.f || unity_CameraProjection[2][1] + != 0.f; +} + +#endif // __PEMA_99_INC diff --git a/poi.cginc b/poi.cginc new file mode 100644 index 0000000..5e31a42 --- /dev/null +++ b/poi.cginc @@ -0,0 +1,60 @@ +#ifndef __POI_INC +#define __POI_INC + +/* +MIT License + +Copyright (c) 2018 King Arthur + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +static const float Epsilon = 1e-10; +float3 RGBtoHCV(in float3 RGB) +{ + // Based on work by Sam Hocevar and Emil Persson + float4 P = (RGB.g < RGB.b) ? float4(RGB.bg, -1.0, 2.0 / 3.0) : float4(RGB.gb, 0.0, -1.0 / 3.0); + float4 Q = (RGB.r < P.x) ? float4(P.xyw, RGB.r) : float4(RGB.r, P.yzx); + float C = Q.x - min(Q.w, Q.y); + float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); + return float3(H, C, Q.x); +} + +float3 RGBtoHSV(in float3 RGB) +{ + float3 HCV = RGBtoHCV(RGB); + float S = HCV.y / (HCV.z + Epsilon); + return float3(HCV.x, S, HCV.z); +} + +float3 HUEtoRGB(in float H) +{ + float R = abs(H * 6 - 3) - 1; + float G = 2 - abs(H * 6 - 2); + float B = 2 - abs(H * 6 - 4); + return saturate(float3(R, G, B)); +} + +float3 HSVtoRGB(in float3 HSV) +{ + float3 RGB = HUEtoRGB(HSV.x); + return ((RGB - 1) * HSV.y + 1) * HSV.z; +} + +#endif // __POI_INC diff --git a/shadertoy.cginc b/shadertoy.cginc new file mode 100644 index 0000000..b19193d --- /dev/null +++ b/shadertoy.cginc @@ -0,0 +1,36 @@ +#ifndef __SHADERTOY_INC +#define __SHADERTOY_INC + +#include "AutoLight.cginc" +#include "pema99.cginc" +#include "poi.cginc" + +// https://www.shadertoy.com/view/3ttSzr +void effect_crumpled_wave( out float4 fragColor, in float2 uv ){ + for(float i = 1.0; i < 8.0; i++) { + uv.y += i * 0.1 / i * + sin(uv.x * i * i + _Time[3] * 0.5) * + sin(uv.y * i * i + _Time[3] * 0.5); + } + + float3 col; + col.r = uv.y - 0.1; + col.g = uv.y + 0.3; + col.b = uv.y + 0.95; + + col = RGBtoHSV(col); + + float x_diff = 0.50 - col.x; + col.x = 0.80 + x_diff * 0.5; + col.x += uv.x / 16.0 + .05; + + col.y *= 0.8; + col.z *= 0.7; // Darken + + col.x = glsl_mod(col.x, 1.0); + col = HSVtoRGB(col); + + fragColor = float4(col,1.0); +} + +#endif // __SHADERTOY_INC diff --git a/tooner.shader b/tooner.shader new file mode 100644 index 0000000..586e58b --- /dev/null +++ b/tooner.shader @@ -0,0 +1,276 @@ +Shader "yum_food/tooner" +{ + Properties + { + _BaseColor("Base color", Color) = (0.8, 0.8, 0.8, 1) + _Metallic("Metallic", Range(0, 1)) = 0 + _Roughness("Roughness", Range(0, 1)) = 1 + + [NoScaleOffset] _BaseColorTex("Base color", 2D) = "white" {} + [NoScaleOffset] _NormalTex("Normal", 2D) = "bump" {} + [NoScaleOffset] _MetallicTex("Metallic", 2D) = "white" {} + [NoScaleOffset] _RoughnessTex("Roughness", 2D) = "black" {} + + _PBR_Overlay_Enable("Enable PBR overlay", Float) = 0.0 + _PBR_Overlay_BaseColor("Base color", Color) = (0.8, 0.8, 0.8, 1) + _PBR_Overlay_Metallic("Metallic", Range(0, 1)) = 0 + _PBR_Overlay_Roughness("Roughness", Range(0, 1)) = 1 + [NoScaleOffset] _PBR_Overlay_BaseColorTex("Base color", 2D) = "white" {} + [NoScaleOffset] _PBR_Overlay_NormalTex("Normal", 2D) = "bump" {} + [NoScaleOffset] _PBR_Overlay_MetallicTex("Metallic", 2D) = "white" {} + [NoScaleOffset] _PBR_Overlay_RoughnessTex("Roughness", 2D) = "black" {} + [NoScaleOffset] _PBR_Overlay_Tex_NormalStr("Normal texture strength", Range(0, 10)) = 1 + + [NoScaleOffset] _EmissionTex("Emission map", 2D) = "black" {} + _EmissionStrength("Emission strength", Range(0, 2)) = 0 + + [NoScaleOffset] _Tex_NormalStr("Normal texture strength", Range(0, 10)) = 1 + + _Cubemap("Cubemap", Cube) = "" {} + _Min_Brightness("Min brightness", Range(0, 1)) = 0 + _Max_Brightness("Max brightness", Range(0, 1.5)) = 1 + _Mesh_Normal_Strength("Mesh normal strength", Range(0, 10)) = 1 + _NormalStr("Normal strength", Range(0, 10)) = 1 + + _Shading_Mode("Shading mode", Range(0, 1)) = 0 + [MaterialToggle] _Flatten_Mesh_Normals("Flatten mesh normals", Float) = 0.0 + [MaterialToggle] _Confabulate_Normals("Confabulate mesh normals", Float) = 0.0 + + _Alpha_Cutoff("Alpha cutoff", Range(0, 1)) = 0.5 + + _Outline_Width("Outline width", Range(0, 0.1)) = 0.01 + _Outline_Color("Outline color", Color) = (0, 0, 0, 1) + _Outline_Emission_Strength("Outline emission strength", Range(0, 2)) = 0.2 + _Outline_Mask("Outline mask", 2D) = "white" {} + _Outline_Mask_Invert("Invert outline mask", Float) = 0.0 + + _Glitter_Enabled("Glitter enabled", Float) = 0 + _Glitter_Mask("Glitter mask", 2D) = "white" {} + _Glitter_Density("Glitter density", float) = 400 + _Glitter_Amount("Glitter amount", Range(1, 100)) = 35 + _Glitter_Speed("Glitter speed", float) = 1 + _Glitter_Seed("Glitter seed", float) = 1 + _Glitter_Brightness("Glitter brightness", float) = 1 + _Glitter_Angle("Glitter angle", Range(0, 90)) = 90 + + [MaterialToggle] _Explode_Toggle("Explode toggle", Float) = 0 + _Explode_Phase("Explode phase", Range(0, 1)) = 0 + [Enum(UnityEngine.Rendering.CullMode)] _OutlinesCull ("Outlines pass culling mode", Float) = 1 + [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Culling mode", Float) = 2 + + [MaterialToggle] _Scroll_Toggle("Scroll toggle", Float) = 0 + _Scroll_Top("Scroll top (m)", Range(-5, 5)) = 1 + _Scroll_Bottom("Scroll bottom (m)", Range(-5, 5)) = 0 + _Scroll_Width("Scroll width", Range(0, 1)) = 0 + _Scroll_Strength("Scroll strength", Range(0, 1)) = 0 + _Scroll_Speed("Scroll speed", Range(0, 1)) = 1 + + [HideInInspector] _SrcBlend ("_SrcBlend", Float) = 1 + [HideInInspector] _DstBlend ("_SrcBlend", Float) = 0 + [HideInInspector] _ZWrite ("_ZWrite", Float) = 1 + + _Matcap0("Matcap", 2D) = "black" {} + _Matcap0_Mask("Matcap mask", 2D) = "white" {} + _Matcap0_Mask_Invert("Invert mask", Float) = 0.0 + _Matcap0Mode("Matcap mode", Float) = 0 + _Matcap0Str("Matcap strength", Float) = 1 + + _Matcap1("Matcap", 2D) = "black" {} + _Matcap1_Mask("Matcap mask", 2D) = "white" {} + _Matcap1_Mask_Invert("Invert mask", Float) = 0.0 + _Matcap1Mode("Matcap mode", Float) = 0 + _Matcap1Str("Matcap strength", Float) = 1 + + _Rim_Lighting_Enabled("Enable rim lighting", Float) = 0 + _Rim_Lighting_Mode("Rim lighting mode", Float) = 0 + _Rim_Lighting_Mask("Rim lighting mask", 2D) = "white" {} + _Rim_Lighting_Mask_Invert("Invert rim lighting mask", Float) = 0.0 + _Rim_Lighting_Color("Rim lighting color", Color) = (1, 1, 1, 1) + _Rim_Lighting_Center("Rim lighting center", Float) = 0.5 + _Rim_Lighting_Power("Rim lighting power", Float) = 2.0 + _Rim_Lighting_Strength("Rim lighting power", Float) = 1.0 + + _OKLAB_Enabled("Enable OKLAB", Float) = 0.0 + _OKLAB_Mask("Mask", 2D) = "white" {} + _OKLAB_Lightness_Shift("OKLAB lightness shift", Range(-1.0, 1.0)) = 0.0 + _OKLAB_Chroma_Shift("OKLAB chroma shift", Range(-0.37, 0.37)) = 0.0 + _OKLAB_Hue_Shift("OKLAB hue shift", Range(0, 6.283185307)) = 0.0 + + _Clones_Enabled("Enable clones", Float) = 0.0 + _Clones_Count("Clones count", Range(0,4)) = 0.0 + _Clones_dx("Clones dx", Range(0, 1)) = 1.0 + + _UVScroll_Enabled("Enable UV scrolling", Float) = 0.0 + _UVScroll_Mask("UV scroll mask", 2D) = "white" + _UVScroll_U_Speed("UV scroll U speed", Float) = 0.0 + _UVScroll_V_Speed("UV scroll V speed", Float) = 1.0 + _UVScroll_Alpha("UV scroll alpha", 2D) = "white" + } + Fallback "Transparent" + SubShader + { + Pass { + Tags { + "RenderType"="Opaque" + "Queue"="Geometry" + "LightMode" = "ForwardBase" + } + Blend [_SrcBlend] [_DstBlend] + ZWrite [_ZWrite] + ZTest LEqual + Cull [_Cull] + + Stencil { + Ref 1 + Comp Always + Pass Replace + } + + CGPROGRAM + #pragma target 5.0 + + #pragma multi_compile _ VERTEXLIGHT_ON + #pragma shader_feature_local _ _BASECOLOR_MAP + #pragma shader_feature_local _ _NORMAL_MAP + #pragma shader_feature_local _ _METALLIC_MAP + #pragma shader_feature_local _ _ROUGHNESS_MAP + #pragma shader_feature_local _ _CUBEMAP + #pragma shader_feature_local _ _EMISSION + //#pragma shader_feature_local _ _SHADING_MODE_FLAT + #pragma shader_feature_local _ _RENDERING_CUTOUT + #pragma shader_feature_local _ _RENDERING_FADE + #pragma shader_feature_local _ _OUTLINES + #pragma shader_feature_local _ _GLITTER + #pragma shader_feature_local _ _EXPLODE + #pragma shader_feature_local _ _SCROLL + #pragma shader_feature_local _ _UVSCROLL + #pragma shader_feature_local _ _MATCAP0 + #pragma shader_feature_local _ _MATCAP0_MASK + #pragma shader_feature_local _ _MATCAP1 + #pragma shader_feature_local _ _MATCAP1_MASK + #pragma shader_feature_local _ _RIM_LIGHTING + #pragma shader_feature_local _ _RIM_LIGHTING_MASK + #pragma shader_feature_local _ _OKLAB + #pragma shader_feature_local _ _CLONES + #pragma shader_feature_local _ _PBR_OVERLAY + #pragma shader_feature_local _ _PBR_OVERLAY_BASECOLOR_MAP + #pragma shader_feature_local _ _PBR_OVERLAY_NORMAL_MAP + #pragma shader_feature_local _ _PBR_OVERLAY_ROUGHNESS_MAP + #pragma shader_feature_local _ _PBR_OVERLAY_METALLIC_MAP + + #pragma vertex vert + //#pragma vertex hull_vertex + //#pragma hull hull + //#pragma domain domain + + #pragma geometry geom + #pragma fragment frag + + #define FORWARD_BASE_PASS + + #include "tooner_lighting.cginc" + ENDCG + } + Pass { + Tags { + "RenderType" = "Opaque" + "Queue"="Geometry" + "LightMode" = "ForwardAdd" + } + Blend [_SrcBlend] One + ZWrite Off + Cull [_Cull] + + CGPROGRAM + #pragma target 5.0 + + #pragma multi_compile_fwdadd + #pragma multi_compile DIRECTIONAL DIRECTIONAL_COOKIE POINT SPOT + #pragma shader_feature_local _BASECOLOR_MAP + #pragma shader_feature_local _NORMAL_MAP + #pragma shader_feature_local _METALLIC_MAP + #pragma shader_feature_local _ROUGHNESS_MAP + #pragma shader_feature_local _CUBEMAP + #pragma shader_feature_local _ _EMISSION + //#pragma shader_feature_local _SHADING_MODE_FLAT + #pragma shader_feature_local _RENDERING_CUTOUT + #pragma shader_feature_local _RENDERING_FADE + #pragma shader_feature_local _OUTLINES + #pragma shader_feature_local _GLITTER + #pragma shader_feature_local _EXPLODE + #pragma shader_feature_local _SCROLL + #pragma shader_feature_local _UVSCROLL + #pragma shader_feature_local _MATCAP0 + #pragma shader_feature_local _ _MATCAP0_MASK + #pragma shader_feature_local _MATCAP1 + #pragma shader_feature_local _ _MATCAP1_MASK + #pragma shader_feature_local _ _RIM_LIGHTING + #pragma shader_feature_local _ _RIM_LIGHTING_MASK + #pragma shader_feature_local _ _OKLAB + #pragma shader_feature_local _ _CLONES + #pragma shader_feature_local _ _PBR_OVERLAY + #pragma shader_feature_local _ _PBR_OVERLAY_BASECOLOR_MAP + #pragma shader_feature_local _ _PBR_OVERLAY_NORMAL_MAP + #pragma shader_feature_local _ _PBR_OVERLAY_ROUGHNESS_MAP + #pragma shader_feature_local _ _PBR_OVERLAY_METALLIC_MAP + + #pragma vertex vert + //#pragma vertex hull_vertex + //#pragma hull hull + //#pragma domain domain + + #pragma geometry geom + #pragma fragment frag + + #include "tooner_lighting.cginc" + ENDCG + } + Pass { + Cull [_OutlinesCull] + + ZWrite [_ZWrite] + ZTest LEqual + + CGPROGRAM + #pragma target 5.0 + #pragma shader_feature_local _BASECOLOR_MAP + #pragma shader_feature_local _RENDERING_CUTOUT + #pragma shader_feature_local _OUTLINES + #pragma shader_feature_local _EXPLODE + #pragma shader_feature_local _ _SCROLL + #pragma shader_feature_local _ _UVSCROLL + #pragma shader_feature_local _MATCAP0 + #pragma shader_feature_local _ _MATCAP0_MASK + #pragma shader_feature_local _MATCAP1 + #pragma shader_feature_local _ _MATCAP1_MASK + #pragma shader_feature_local _ _RIM_LIGHTING + #pragma shader_feature_local _ _RIM_LIGHTING_MASK + #pragma shader_feature_local _ _OKLAB + #pragma shader_feature_local _ _CLONES + #pragma shader_feature_local _ _PBR_OVERLAY + #pragma shader_feature_local _ _PBR_OVERLAY_BASECOLOR_MAP + #pragma shader_feature_local _ _PBR_OVERLAY_NORMAL_MAP + #pragma shader_feature_local _ _PBR_OVERLAY_ROUGHNESS_MAP + #pragma shader_feature_local _ _PBR_OVERLAY_METALLIC_MAP + + #pragma vertex vert + //#pragma vertex hull_vertex + //#pragma hull hull + //#pragma domain domain + + #pragma geometry geom + #pragma fragment frag + + #include "tooner_outline_pass.cginc" + ENDCG + } + Pass { + Tags {"LightMode" = "ShadowCaster"} + CGPROGRAM + #include "mochie_shadow_caster.cginc" + ENDCG + } + } + CustomEditor "ToonerGUI" +} + diff --git a/tooner_lighting.cginc b/tooner_lighting.cginc new file mode 100644 index 0000000..4627554 --- /dev/null +++ b/tooner_lighting.cginc @@ -0,0 +1,589 @@ +#ifndef TOONER_LIGHTING +#define TOONER_LIGHTING + +#include "audiolink.cginc" +#include "clones.cginc" +#include "globals.cginc" +#include "interpolators.cginc" +#include "iq_sdf.cginc" +#include "math.cginc" +#include "motion.cginc" +#include "pbr.cginc" +#include "poi.cginc" +#include "shadertoy.cginc" +#include "tooner_scroll.cginc" +#include "oklab.cginc" + +struct tess_data +{ + float4 position : INTERNALTESSPOS; + float2 uv : TEXCOORD0; + float3 normal : TEXCOORD1; + float4 tangent : TEXCOORD2; + + #if defined(VERTEXLIGHT_ON) + float3 vertexLightColor : TEXCOORD4; + #endif +}; + +struct tess_factors { + float edge[4] : SV_TessFactor; + float inside[2] : SV_InsideTessFactor; +}; + +void getVertexLightColor(inout v2f i) +{ + #if defined(VERTEXLIGHT_ON) + float3 view_dir = normalize(_WorldSpaceCameraPos - worldPos); + bool flat = round(_Flatten_Mesh_Normals) == 1.0; + i.vertexLightColor = Shade4PointLights( + unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0, + unity_LightColor[0].rgb, + unity_LightColor[1].rgb, + unity_LightColor[2].rgb, + unity_LightColor[3].rgb, + unity_4LightAtten0, i.worldPos, flat ? view_dir : i.normal + ); + #endif +} + +v2f vert(appdata v) +{ + v2f o; + + o.clipPos = UnityObjectToClipPos(v.position); + o.worldPos = mul(unity_ObjectToWorld, v.position); + + o.normal = UnityObjectToWorldNormal(v.normal); + o.tangent = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); + o.uv = v.uv; + + getVertexLightColor(o); + + return o; +} + +void getVertexLightColorTess(inout tess_data i) +{ + #if defined(VERTEXLIGHT_ON) + i.vertexLightColor = Shade4PointLights( + unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0, + unity_LightColor[0].rgb, + unity_LightColor[1].rgb, + unity_LightColor[2].rgb, + unity_LightColor[3].rgb, + unity_4LightAtten0, worldPos, i.normal + ); + #endif +} + +tess_data hull_vertex(appdata v) +{ + tess_data o; + + o.position = v.position; + + o.normal = UnityObjectToWorldNormal(v.normal); + o.tangent = float4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w); + o.uv = v.uv; + + getVertexLightColorTess(o); + + return o; +} + +tess_factors patch_constant(InputPatch<tess_data, 4> patch) +{ + tess_factors f; + float factor = _Chain_Tess_Factor; + factor = 1; + f.edge[0] = factor; + f.edge[1] = factor; + f.edge[2] = factor; + f.edge[3] = factor; + f.inside[0] = factor; + f.inside[1] = factor; + return f; +} + +[UNITY_domain("quad")] +[UNITY_outputcontrolpoints(4)] +[UNITY_outputtopology("triangle_cw")] +[UNITY_partitioning("fractional_odd")] +[UNITY_patchconstantfunc("patch_constant")] +tess_data hull( + InputPatch<tess_data, 4> patch, + uint id : SV_OutputControlPointID) +{ + return patch[id]; +} + +[UNITY_domain("quad")] +v2f domain( + tess_factors factors, + OutputPatch<tess_data, 4> patch, + float2 uv : SV_DomainLocation) +{ + v2f data; +#define DOMAIN_INTERP(fieldName) data.fieldName = \ + lerp(\ + lerp(patch[0].fieldName, patch[1].fieldName, uv.x), \ + lerp(patch[2].fieldName, patch[3].fieldName, uv.x), \ + uv.y) + DOMAIN_INTERP(uv); + DOMAIN_INTERP(normal); + DOMAIN_INTERP(tangent); + + #if defined(VERTEXLIGHT_ON) + DOMAIN_INTERP(vertexLightColor); + #endif + + float4 pos = lerp( + lerp(patch[0].position, patch[1].position, uv.x), + lerp(patch[2].position, patch[3].position, uv.x), + uv.y); + data.clipPos = UnityObjectToClipPos(pos); + data.worldPos = mul(unity_ObjectToWorld, pos); + + return data; +} + +// maxvertexcount == the number of vertices we create +#if defined(_CLONES) +[maxvertexcount(15)] +#else +[maxvertexcount(3)] +#endif +void geom(triangle v2f tri_in[3], + uint pid: SV_PrimitiveID, + inout TriangleStream<v2f> tri_out) +{ + v2f v0 = tri_in[0]; + v2f v1 = tri_in[1]; + v2f v2 = tri_in[2]; + + float3 v0_objPos; + float3 v1_objPos; + float3 v2_objPos; + +#if defined(_EXPLODE) + float3 n = normalize(cross(v1.worldPos - v0.worldPos, v2.worldPos - v0.worldPos)); + float3 avg_pos; + + float3 n0 = v0.normal; + float3 n1 = v1.normal; + float3 n2 = v2.normal; + + float phase = _Explode_Phase; + phase = smoothstep(0, 1, phase); + phase *= phase; + phase *= 4; + const float pid_rand = rand((int) pid); + + if (phase > 1E-6) { + float3 axis = normalize(float3( + rand((int) ((v0.uv.x + v0.uv.y) * 1E9)) * 2 - 1, + rand((int) ((v1.uv.x + v1.uv.y) * 1E9)) * 2 - 1, + rand((int) ((v2.uv.x + v2.uv.y) * 1E9)) * 2 - 1)); + float3 np = BlendNormals(n, axis * phase); + + v0.worldPos += np * phase * pid_rand; + v1.worldPos += np * phase * pid_rand; + v2.worldPos += np * phase * pid_rand; + + v0_objPos = mul(unity_WorldToObject, float4(v0.worldPos, 1)); + v1_objPos = mul(unity_WorldToObject, float4(v1.worldPos, 1)); + v2_objPos = mul(unity_WorldToObject, float4(v2.worldPos, 1)); + + float chrono = 0; +#if defined(_AUDIOLINK) + if (AudioLinkIsAvailable()) { + chrono = (AudioLinkDecodeDataAsUInt( ALPASS_CHRONOTENSITY + uint2( 2, 1 ) ) % 1000000) / 1000000.0; + } +#endif + v0.worldPos += n * phase * sin(_Time[2] + length(v0_objPos)*6 + chrono) * .01 + chrono * n * phase * .2; + v1.worldPos += n * phase * sin(_Time[2] + length(v1_objPos)*6 + chrono) * .01 + chrono * n * phase * .2; + v2.worldPos += n * phase * sin(_Time[2] + length(v2_objPos)*6 + chrono) * .01 + chrono * n * phase * .2; + + avg_pos = (v0.worldPos + v1.worldPos + v2.worldPos) / 3; + v0.worldPos -= avg_pos; + v1.worldPos -= avg_pos; + v2.worldPos -= avg_pos; + + float theta = phase * 3.14159 * 4 + phase * (sin(_Time[1] * (1 + pid_rand) / 2.0 + pid_rand) + cos(_Time[1] * (1 + pid_rand) / 6.1 + pid_rand) * 2) * pid_rand * 2; + float4 quat = get_quaternion(axis, theta); + v0.worldPos = rotate_vector(v0.worldPos, quat); + v1.worldPos = rotate_vector(v1.worldPos, quat); + v2.worldPos = rotate_vector(v2.worldPos, quat); + + v0.worldPos += avg_pos; + v1.worldPos += avg_pos; + v2.worldPos += avg_pos; + + n = normalize(cross(v1.worldPos - v0.worldPos, v2.worldPos - v0.worldPos)); + v0.normal = n; + v1.normal = n; + v2.normal = n; + + n = normalize(cross(v1.worldPos - v0.worldPos, v2.worldPos - v0.worldPos)); + avg_pos = (v0.worldPos + v1.worldPos + v2.worldPos) / 3; + v0.worldPos = applyScroll(v0.worldPos, n, avg_pos); + v1.worldPos = applyScroll(v1.worldPos, n, avg_pos); + v2.worldPos = applyScroll(v2.worldPos, n, avg_pos); + + // Omit geometry that's too close when exploded. + /* + if (_Explode_Phase > .05 && length(v0.worldPos - _WorldSpaceCameraPos) < .2) { + return; + } + */ + + v0_objPos = mul(unity_WorldToObject, float4(v0.worldPos, 1)); + v1_objPos = mul(unity_WorldToObject, float4(v1.worldPos, 1)); + v2_objPos = mul(unity_WorldToObject, float4(v2.worldPos, 1)); + + // Apply transformed worldPos to other coordinate systems. + if (_Explode_Phase > 1E-6) { + v0.clipPos = UnityObjectToClipPos(v0_objPos); + v1.clipPos = UnityObjectToClipPos(v1_objPos); + v2.clipPos = UnityObjectToClipPos(v2_objPos); + } + } +#endif // __EXPLODE +#if defined(_CLONES) + v2f clone_verts[3] = {v0, v1, v2}; + add_clones(clone_verts, tri_out); +#endif // _CLONES + + // Output transformed geometry. + tri_out.Append(v0); + tri_out.Append(v1); + tri_out.Append(v2); + tri_out.RestartStrip(); +} + +#if defined(_GLITTER) +float get_glitter(float2 uv, float iddx, float iddy, float3 worldPos, float3 normal) +{ + float pixellate = _Glitter_Density; + float glitter = rand2(round(uv * pixellate) / pixellate + _Glitter_Seed); + + float thresh = 1 - _Glitter_Amount / 100; + glitter = lerp(0, glitter, glitter > thresh); + glitter = (glitter - thresh) / (1 - thresh); + + float b = sin(_Time[2] * _Glitter_Speed / 2 + glitter*100); + glitter = max(glitter, 0)*max(b, 0); + + float mask = _Glitter_Mask.SampleGrad(linear_repeat_s, uv, iddx, iddy); + glitter *= mask; + + glitter = clamp(glitter, 0, 1); + glitter *= _Glitter_Brightness; + + if (_Glitter_Angle < 90) { + float ndotl = abs(dot(normal, normalize(_WorldSpaceCameraPos.xyz - worldPos))); + float cutoff = cos((_Glitter_Angle / 180) * 3.14159); + + glitter *= saturate(pow(ndotl / cutoff, 30)); + + //glitter = ndotl > cutoff ? glitter : 0; + } + + return glitter; +} +#endif // _GLITTER + +float3 CreateBinormal (float3 normal, float3 tangent, float binormalSign) { + return cross(normal, tangent.xyz) * + (binormalSign * unity_WorldTransformParams.w); +} + +float4 effect(inout v2f i) +{ + float iddx = ddx(i.uv.x) / 4; + float iddy = ddx(i.uv.y) / 4; + +#if defined(_UVSCROLL) + float2 orig_uv = i.uv; + float uv_scroll_mask = round(_UVScroll_Mask.SampleGrad(linear_repeat_s, i.uv, iddx, iddy)); + i.uv += _Time[0] * float2(_UVScroll_U_Speed, _UVScroll_V_Speed) * uv_scroll_mask; +#endif + +#if defined(_BASECOLOR_MAP) + float4 albedo = _BaseColorTex.SampleGrad(linear_repeat_s, i.uv, iddx, iddy); + albedo *= _BaseColor; +#else + float4 albedo = _BaseColor; +#endif // _BASECOLOR_MAP + +#if defined(_UVSCROLL) + if (uv_scroll_mask) { + float uv_scroll_alpha = _UVScroll_Alpha.SampleGrad(linear_repeat_s, orig_uv, iddx, iddy); + albedo.a *= uv_scroll_alpha; + } +#endif + +#if defined(_RENDERING_CUTOUT) +#if 0 + if (albedo.a < _Alpha_Cutoff) { + discard; + } +#else + clip(albedo.a - _Alpha_Cutoff); +#endif + albedo.a = 1; +#endif + +#if defined(_NORMAL_MAP) + // Use UVs to smoothly blend between fully detailed normals when close up and + // flat normals when far away. If we don't do this, then we see moire effects + // on e.g. striped normal maps. + float fw = clamp(fwidth(i.uv), .001, 1) * 1200; + float3 raw_normal = UnpackScaleNormal(_NormalTex.SampleGrad(linear_repeat_s, i.uv, iddx/2, iddy/2), _Tex_NormalStr); + + raw_normal = BlendNormals( + (1/fw) * raw_normal, + fw * float3(0, 0, 1)); + +#if defined(_PBR_OVERLAY_NORMAL_MAP) + { + // Use UVs to smoothly blend between fully detailed normals when close up and + // flat normals when far away. If we don't do this, then we see moire effects + // on e.g. striped normal maps. + //float3 raw_normal = UnpackScaleNormal(_PBR_Overlay_NormalTex.SampleGrad(linear_repeat_s, i.uv, iddx/2, iddy/2), _PBR_Overlay_Tex_NormalStr); + float3 raw_normal_2 = UnpackScaleNormal(_PBR_Overlay_NormalTex.SampleGrad(linear_repeat_s, i.uv, iddx/2, iddy/2), _PBR_Overlay_Tex_NormalStr); + + raw_normal = BlendNormals( + raw_normal, + raw_normal_2); + } +#endif // _PBR_OVERLAY_NORMAL_MAP + + + float3 binormal = CreateBinormal(i.normal, i.tangent.xyz, i.tangent.w); + float3 normal = normalize( + raw_normal.x * i.tangent + + raw_normal.y * binormal + + raw_normal.z * i.normal + ); +#else // !_NORMAL_MAP + float3 normal = i.normal; +#endif // _NORMAL_MAP + +#if defined(_METALLIC_MAP) + float metallic = _MetallicTex.SampleGrad(linear_repeat_s, i.uv, iddx, iddy); +#else + float metallic = _Metallic; +#endif +#if defined(_ROUGHNESS_MAP) + float roughness = _RoughnessTex.SampleGrad(linear_repeat_s, i.uv, iddx, iddy); +#else + float roughness = _Roughness; +#endif +#if defined(VERTEXLIGHT_ON) + float4 vertex_light_color = float4(i.vertexLightColor, 1); +#else + float4 vertex_light_color = 0; +#endif + +#if defined(_PBR_OVERLAY) +#if defined(_PBR_OVERLAY_BASECOLOR_MAP) + float4 ov_albedo = _PBR_Overlay_BaseColorTex.SampleGrad(linear_repeat_s, i.uv, iddx, iddy); + ov_albedo *= _PBR_Overlay_BaseColor; +#else + float4 ov_albedo = _BaseColor; +#endif // _PBR_OVERLAY_BASECOLOR_MAP + albedo.rgb = lerp(albedo.rgb, ov_albedo.rgb, ov_albedo.a); + +#endif // _PBR_OVERLAY + + { +#if defined(_MATCAP0) + // theorem: (a, b, c) and (c, c, -(a +b)) are perpendicular to each other + // proof: + // dot((a,b,c), (c,c,-(a+b))) = + // ca + cb - (ca + cb) = + // 0 + // recall that dot(x,y) = ||x|| ||y|| cos(theta), so for two non-vanishing + // vectors, dot(x,y) = 0 iff cos(theta) = 0. + float3 view_dir = normalize(_WorldSpaceCameraPos - i.worldPos); + float3 up = float3(0, 1, 0); + float3 ortho_1 = normalize(float3(view_dir.z, view_dir.z, -(view_dir.y + view_dir.x))); + float3 ortho_2 = cross(view_dir, ortho_1); + float2 matcap_uv = (float2(dot(normal, ortho_1), dot(normal, ortho_2)) + 1) * .50; + float iddx = ddx(i.uv.x); + float iddy = ddy(i.uv.y); + float3 matcap = _Matcap0.SampleGrad(linear_repeat_s, matcap_uv, iddx, iddy) * _Matcap0Str; + +#if defined(_MATCAP0_MASK) + float4 matcap_mask_raw = _Matcap0_Mask.SampleGrad(linear_repeat_s, i.uv.xy, iddx, iddy); + matcap_mask_raw.rgb = (bool) round(_Matcap0_Mask_Invert) ? 1 - matcap_mask_raw.rgb : matcap_mask_raw.rgb; + float matcap_mask = matcap_mask_raw.r * matcap_mask_raw.a; +#else + float matcap_mask = 1; +#endif + + int mode = round(_Matcap0Mode); + switch (mode) { + case 0: + albedo.rgb += lerp(0, matcap, matcap_mask); + break; + case 1: + albedo.rgb *= lerp(1, matcap, matcap_mask); + break; + case 2: + albedo.rgb = lerp(albedo.rgb, matcap, matcap_mask);; + break; + case 3: + albedo.rgb -= lerp(0, matcap, matcap_mask); + break; + case 4: + albedo.rgb = lerp(albedo.rgb, min(albedo.rgb, matcap), matcap_mask); + break; + case 5: + albedo.rgb = lerp(albedo.rgb, max(albedo.rgb, matcap), matcap_mask); + break; + default: + break; + } +#endif + } + { +#if defined(_MATCAP1) + float3 view_dir = normalize(_WorldSpaceCameraPos - i.worldPos); + float3 ortho_1 = normalize(float3(view_dir.z, view_dir.z, -(view_dir.y + view_dir.x))); + float3 ortho_2 = cross(view_dir, ortho_1); + float2 matcap_uv = (float2(dot(normal, ortho_1), dot(normal, ortho_2)) + 1) * .50; + float iddx = ddx(i.uv.x); + float iddy = ddy(i.uv.y); + float3 matcap = _Matcap1.SampleGrad(linear_repeat_s, matcap_uv, iddx, iddy) * _Matcap1Str; + +#if defined(_MATCAP1_MASK) + float4 matcap_mask_raw = _Matcap1_Mask.SampleGrad(linear_repeat_s, i.uv.xy, iddx, iddy); + matcap_mask_raw.rgb = (bool) round(_Matcap1_Mask_Invert) ? 1 - matcap_mask_raw.rgb : matcap_mask_raw.rgb; + float matcap_mask = matcap_mask_raw.r * matcap_mask_raw.a; +#else + float matcap_mask = 1; +#endif + + int mode = round(_Matcap1Mode); + switch (mode) { + case 0: + albedo.rgb += lerp(0, matcap, matcap_mask); + break; + case 1: + albedo.rgb *= lerp(1, matcap, matcap_mask); + break; + case 2: + albedo.rgb = lerp(albedo.rgb, matcap, matcap_mask);; + break; + case 3: + albedo.rgb -= lerp(0, matcap, matcap_mask); + break; + case 4: + albedo.rgb = lerp(albedo.rgb, min(albedo.rgb, matcap), matcap_mask); + break; + case 5: + albedo.rgb = lerp(albedo.rgb, max(albedo.rgb, matcap), matcap_mask); + break; + default: + break; + } +#endif + } + { +#if defined(_RIM_LIGHTING) + // identity: (a, b, c) and (c, c, -(a +b)) are perpendicular to each other + float3 view_dir = normalize(_WorldSpaceCameraPos - i.worldPos); + float theta = atan2(length(cross(view_dir, normal)), dot(view_dir, normal)); +#define PI 3.14159265 + float rl = abs(theta) / PI; // on [0, 1] + rl = pow(2, -_Rim_Lighting_Power * abs(rl - _Rim_Lighting_Center)); + + float3 matcap = rl * _Rim_Lighting_Color * _Rim_Lighting_Strength; + +#if defined(_RIM_LIGHTING_MASK) + float4 matcap_mask_raw = _Rim_Lighting_Mask.SampleGrad(linear_repeat_s, i.uv.xy, iddx, iddy); + matcap_mask_raw.rgb = (bool) round(_Rim_Lighting_Mask_Invert) ? 1 - matcap_mask_raw.rgb : matcap_mask_raw.rgb; + float matcap_mask = matcap_mask_raw.r * matcap_mask_raw.a; +#else + float matcap_mask = 1; +#endif + + int mode = round(_Rim_Lighting_Mode); + switch (mode) { + case 0: + albedo.rgb += lerp(0, matcap, matcap_mask); + break; + case 1: + albedo.rgb *= lerp(1, matcap, matcap_mask); + break; + case 2: + albedo.rgb = lerp(albedo.rgb, matcap, matcap_mask);; + break; + case 3: + albedo.rgb -= lerp(0, matcap, matcap_mask); + break; + case 4: + albedo.rgb = lerp(albedo.rgb, min(albedo.rgb, matcap), matcap_mask); + break; + case 5: + albedo.rgb = lerp(albedo.rgb, max(albedo.rgb, matcap), matcap_mask); + break; + default: + break; + } +#endif + } + +#if defined(_OKLAB) + // Do hue shift in perceptually uniform color space so it doesn't look like + // shit. + float oklab_mask = _OKLAB_Mask.SampleGrad(linear_repeat_s, i.uv, iddx, iddy); + if (oklab_mask > 0.01 && + (_OKLAB_Hue_Shift > 1E-6 || + abs(_OKLAB_Chroma_Shift) > 1E-6 || + abs(_OKLAB_Lightness_Shift) > 1E-6)) { + float3 c = albedo.rgb; + c = LRGBtoOKLCH(c); + c.x += _OKLAB_Lightness_Shift; + c.y += _OKLAB_Chroma_Shift; + c.z += _OKLAB_Hue_Shift; + c = OKLCHtoLRGB(c); + albedo.rgb = c; + } +#endif + + float4 lit = getLitColor(vertex_light_color, albedo, i.worldPos, normal, + metallic, 1.0 - roughness, i.uv, i); + + float4 result = lit; +#if defined(_GLITTER) + float glitter = get_glitter(i.uv, iddx, iddy, i.worldPos, normal); + result.xyz += glitter; +#endif +#if defined(_EMISSION) + float emission = _EmissionTex.SampleGrad(linear_repeat_s, i.uv, iddx, iddy); + result.xyz += albedo.xyz * emission * _EmissionStrength; +#endif +#if defined(_EXPLODE) && defined(_AUDIOLINK) + if (AudioLinkIsAvailable() && _Explode_Phase > 1E-6) { + float4 al_color = + AudioLinkData( + ALPASS_CCLIGHTS + + uint2(uint(i.uv.x * 8) + uint(i.uv.y * 16) * 8, 0 )).rgba; + result = lerp(result, al_color, _Explode_Phase * _Explode_Phase); + } +#endif + + return result; +} + +fixed4 frag(v2f i) : SV_Target +{ + return effect(i); +} + +#endif // TOONER_LIGHTING + diff --git a/tooner_outline_pass.cginc b/tooner_outline_pass.cginc new file mode 100644 index 0000000..eba7470 --- /dev/null +++ b/tooner_outline_pass.cginc @@ -0,0 +1,321 @@ +#ifndef __TOONER_OUTLINE_PASS +#define __TOONER_OUTLINE_PASS + +#define _OUTLINE_INTERPOLATORS + +#include "audiolink.cginc" +#include "clones.cginc" +#include "globals.cginc" +#include "math.cginc" +#include "pbr.cginc" +#include "tooner_scroll.cginc" +#include "UnityCG.cginc" + +struct tess_data +{ + float4 vertex : INTERNALTESSPOS; + float2 uv : TEXCOORD0; + float3 normal : TEXCOORD2; +}; + +struct tess_factors { + float edge[4] : SV_TessFactor; + float inside[2] : SV_InsideTessFactor; +}; + +v2f vert(appdata v) +{ + float outline_mask = _Outline_Mask.SampleLevel(linear_repeat_s, v.uv, /*lod=*/1); + outline_mask = _Outline_Mask_Invert > 1E-6 ? 1 - outline_mask : outline_mask; + + float4 position = v.vertex; +#if !defined(_WORLD_SPACE_SCALING) +#if defined(_EXPLODE) + if (_Explode_Phase <= 1E-6) { + position.xyz += v.normal * _Outline_Width * .1 * outline_mask; + } +#else + position.xyz += v.normal * _Outline_Width * .1 * outline_mask; +#endif +#endif + + position = mul(unity_ObjectToWorld, position); + const float3 normal = UnityObjectToWorldNormal(v.normal); + +#if defined(_WORLD_SPACE_SCALING) + // Perform scaling operation in world space so that object scale doesn't + // affect outline width. This is handy on avatars with a bunch of different + // gameobjects that have different scale. +#if defined(_EXPLODE) + if (_Explode_Phase <= 1E-6) { + position.xyz += normal * _Outline_Width * .1 * outline_mask; + } +#else + position.xyz += normal * _Outline_Width * .1 * outline_mask; +#endif +#endif + + // Transform back to object, then clip. + position = mul(unity_WorldToObject, position); + v.vertex.xyz = position.xyz; + + v2f o; + o.worldPos = mul(unity_ObjectToWorld, v.vertex); + o.clipPos = UnityObjectToClipPos(v.vertex); + o.normal = normal; + o.uv = v.uv; + + return o; +} + +tess_data hull_vertex(appdata v) +{ + float outline_mask = _Outline_Mask.SampleLevel(linear_repeat_s, v.uv, /*lod=*/3); + outline_mask = _Outline_Mask_Invert > 1E-6 ? 1 - outline_mask : outline_mask; + + float4 position = v.vertex; + position = mul(unity_ObjectToWorld, position); + const float3 normal = UnityObjectToWorldNormal(v.normal); + + // Perform scaling operation in world space so that object scale doesn't + // affect outline width. This is handy on avatars with a bunch of different + // gameobjects that have different scale. +#if defined(_EXPLODE) + if (_Explode_Phase <= 1E-6) { + position.xyz += normal * _Outline_Width * .1 * outline_mask; + } +#else + position.xyz += normal * _Outline_Width * .1 * outline_mask; +#endif + + // Transform back to object, then clip. + position = mul(unity_WorldToObject, position); + v.vertex.xyz = position.xyz; + + tess_data o; + o.vertex = v.vertex; + o.normal = normal; + o.uv = v.uv; + + return o; +} + +tess_factors patch_constant(InputPatch<tess_data, 4> patch) +{ + tess_factors f; + float factor = _Chain_Tess_Factor; + f.edge[0] = factor; + f.edge[1] = factor; + f.edge[2] = factor; + f.edge[3] = factor; + f.inside[0] = factor; + f.inside[1] = factor; + return f; +} + +[UNITY_domain("quad")] +[UNITY_outputcontrolpoints(3)] +[UNITY_outputtopology("triangle_cw")] +[UNITY_partitioning("fractional_odd")] +[UNITY_patchconstantfunc("patch_constant")] +tess_data hull( + InputPatch<tess_data, 4> patch, + uint id : SV_OutputControlPointID) +{ + return patch[id]; +} + +[UNITY_domain("quad")] +v2f domain( + tess_factors factors, + OutputPatch<tess_data, 4> patch, + float2 uv : SV_DomainLocation) +{ + v2f data; +#define DOMAIN_INTERP(fieldName) data.fieldName = \ + lerp(\ + lerp(patch[0].fieldName, patch[1].fieldName, uv.x), \ + lerp(patch[2].fieldName, patch[3].fieldName, uv.x), \ + uv.y) + DOMAIN_INTERP(uv); + DOMAIN_INTERP(normal); + //DOMAIN_INTERP(tangent); + + #if defined(VERTEXLIGHT_ON) + DOMAIN_INTERP(vertexLightColor); + #endif + + float4 pos = lerp( + lerp(patch[0].vertex, patch[1].vertex, uv.x), + lerp(patch[2].vertex, patch[3].vertex, uv.x), + uv.y); + data.clipPos = UnityObjectToClipPos(pos); + data.worldPos = mul(unity_ObjectToWorld, pos); + + return data; +} + +// maxvertexcount == the number of vertices we create +#if defined(_CLONES) +[maxvertexcount(15)] +#else +[maxvertexcount(3)] +#endif +void geom(triangle v2f tri_in[3], + uint pid: SV_PrimitiveID, + inout TriangleStream<v2f> tri_out) +{ + v2f v0 = tri_in[0]; + v2f v1 = tri_in[1]; + v2f v2 = tri_in[2]; + + float3 v0_objPos; + float3 v1_objPos; + float3 v2_objPos; + + float3 n = normalize(cross(v1.worldPos - v0.worldPos, v2.worldPos - v0.worldPos)); + float3 avg_pos; +#if defined(_EXPLODE) + float3 n0 = v0.normal; + float3 n1 = v1.normal; + float3 n2 = v2.normal; + + float phase = _Explode_Phase; + phase = smoothstep(0, 1, phase); + phase *= phase; + phase *= 4; + + if (phase > 1E-6) { + const float pid_rand = rand((int) pid); + + float3 axis = normalize(float3( + rand((int) ((v0.uv.x + v0.uv.y) * 1E9)) * 2 - 1, + rand((int) ((v1.uv.x + v1.uv.y) * 1E9)) * 2 - 1, + rand((int) ((v2.uv.x + v2.uv.y) * 1E9)) * 2 - 1)); + + float3 np = BlendNormals(n, axis * phase); + + v0.worldPos += np * phase * pid_rand; + v1.worldPos += np * phase * pid_rand; + v2.worldPos += np * phase * pid_rand; + + v0_objPos = mul(unity_WorldToObject, float4(v0.worldPos, 1)); + v1_objPos = mul(unity_WorldToObject, float4(v1.worldPos, 1)); + v2_objPos = mul(unity_WorldToObject, float4(v2.worldPos, 1)); + + float chrono = 0; +#if defined(_AUDIOLINK) + if (AudioLinkIsAvailable()) { + chrono = (AudioLinkDecodeDataAsUInt( ALPASS_CHRONOTENSITY + uint2( 2, 1 ) ) % 1000000) / 1000000.0; + } +#endif + v0.worldPos += n * phase * sin(_Time[2] + length(v0_objPos)*6 + chrono) * .01 + chrono * n * phase * .2; + v1.worldPos += n * phase * sin(_Time[2] + length(v1_objPos)*6 + chrono) * .01 + chrono * n * phase * .2; + v2.worldPos += n * phase * sin(_Time[2] + length(v2_objPos)*6 + chrono) * .01 + chrono * n * phase * .2; + + avg_pos = (v0.worldPos + v1.worldPos + v2.worldPos) / 3; + v0.worldPos -= avg_pos; + v1.worldPos -= avg_pos; + v2.worldPos -= avg_pos; + + float r = rand((int) pid); + float theta = phase * 3.14159 * 4 + phase * (sin(_Time[1] * (1 + pid_rand) / 2.0 + r) + cos(_Time[1] * (1 + pid_rand) / 6.1 + r) * 2) * pid_rand * 2; + float4 quat = get_quaternion(axis, theta); + v0.worldPos = rotate_vector(v0.worldPos, quat); + v1.worldPos = rotate_vector(v1.worldPos, quat); + v2.worldPos = rotate_vector(v2.worldPos, quat); + + //v0.worldPos *= 1.1; + //v1.worldPos *= 1.1; + //v2.worldPos *= 1.1; + + v0.worldPos += avg_pos; + v1.worldPos += avg_pos; + v2.worldPos += avg_pos; + + float3 nn = normalize(cross(v1.worldPos - v0.worldPos, v2.worldPos - v0.worldPos)); + v0.worldPos -= nn * .0005; + v1.worldPos -= nn * .0005; + v2.worldPos -= nn * .0005; + + v0.normal = nn; + v1.normal = nn; + v2.normal = nn; + + n = normalize(cross(v1.worldPos - v0.worldPos, v2.worldPos - v0.worldPos)); + avg_pos = (v0.worldPos + v1.worldPos + v2.worldPos) / 3; + v0.worldPos = applyScroll(v0.worldPos, n, avg_pos); + v1.worldPos = applyScroll(v1.worldPos, n, avg_pos); + v2.worldPos = applyScroll(v2.worldPos, n, avg_pos); + + // Omit geometry that's too close when exploded. + /* + if (_Explode_Phase > .05 && length(v0.worldPos - _WorldSpaceCameraPos) < .2) { + return; + } + */ + + // Apply transformed worldPos to other coordinate systems. + v0_objPos = mul(unity_WorldToObject, float4(v0.worldPos, 1)); + v1_objPos = mul(unity_WorldToObject, float4(v1.worldPos, 1)); + v2_objPos = mul(unity_WorldToObject, float4(v2.worldPos, 1)); + + v0.clipPos = UnityObjectToClipPos(v0_objPos); + v1.clipPos = UnityObjectToClipPos(v1_objPos); + v2.clipPos = UnityObjectToClipPos(v2_objPos); + } +#endif +#if defined(_CLONES) + v2f clone_verts[3] = {v0, v1, v2}; + add_clones(clone_verts, tri_out); +#endif // _CLONES + + // Output transformed geometry. + tri_out.Append(v0); + tri_out.Append(v1); + tri_out.Append(v2); + tri_out.RestartStrip(); +} + +fixed4 frag (v2f i) : SV_Target +{ + float iddx = ddx(i.uv.x) / 4; + float iddy = ddx(i.uv.y) / 4; +#if defined(_BASECOLOR_MAP) + float4 albedo = _BaseColorTex.SampleGrad(linear_repeat_s, i.uv, iddx, iddy); + albedo *= _BaseColor; +#else + float4 albedo = _BaseColor; +#endif // _BASECOLOR_MAP + +#if defined(_RENDERING_CUTOUT) + clip(albedo.a - _Alpha_Cutoff); +#endif + + // TODO FIXME the normals are fucked in pbr pass, causing flickering + //return _Outline_Color; + + //float3 flat_normal = normalize(UnpackNormal(float4(128, 128, 255, 255)/255)); + float3 flat_normal = normalize(_WorldSpaceCameraPos - i.worldPos); + float4 vertex_light_color = 0; + float4 result = getLitColor( + vertex_light_color, + _Outline_Color, i.worldPos, flat_normal, 0, 0, i.uv, i); + + result += _Outline_Color * _Outline_Emission_Strength; + +#if defined(_EXPLODE) && defined(_AUDIOLINK) + if (AudioLinkIsAvailable() && _Explode_Phase > 1E-6) { + float4 al_color = + AudioLinkData( + ALPASS_CCLIGHTS + + uint2(uint(i.uv.x * 8) + uint(i.uv.y * 16) * 8, 0 )).rgba; + result = lerp(result, al_color, _Explode_Phase * _Explode_Phase); + } +#endif + + return result; +} + +#endif // __TOONER_OUTLINE_PASS + diff --git a/tooner_scroll.cginc b/tooner_scroll.cginc new file mode 100644 index 0000000..1fd29cb --- /dev/null +++ b/tooner_scroll.cginc @@ -0,0 +1,47 @@ +#ifndef __TOONER_SCROLL +#define __TOONER_SCROLL + +#include "globals.cginc" +#include "math.cginc" +#include "pema99.cginc" + +#if 0 +float _Scroll_Toggle; +float _Scroll_Top; +float _Scroll_Bottom; +float _Scroll_Width; +float _Scroll_Strength; +float _Scroll_Speed; +#endif + +float3 applyScroll(float3 p, float3 n, float3 avg_pos) { +#if defined(_SCROLL) + float phase = glsl_mod(_Time[1] * _Scroll_Speed, 1.0); + + float z1 = _Scroll_Top; + float z0 = _Scroll_Bottom; + float zc = (z1 - z0) * phase + z0; + + float3 op = mul(unity_WorldToObject, float4(p, 1)).xyz; + + float offset = + 1 / (1 + pow(.5 * (zc - op.y) / _Scroll_Width, 6)); + + p -= avg_pos; + float3 axis = normalize(float3( + rand((int) p.x * 1.0E6), + rand((int) p.y * 1.0E6), + rand((int) p.z * 1.0E6))); + float theta = offset * .5; + float4 quat = get_quaternion(axis, theta); + p = rotate_vector(p, quat); + p += avg_pos; + + return p + n * offset * _Scroll_Strength; +#else + return p; +#endif // _SCROLL +} + +#endif // __TOONER_SCROLL + |
