ADD : 퍼 쉐이더 추가
This commit is contained in:
parent
52d9e9f548
commit
5a559d888e
@ -0,0 +1,298 @@
|
|||||||
|
// NiloToon Character Fur Shader - Custom ShaderGUI
|
||||||
|
// Clean, organized material inspector with foldable sections
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NiloToonURP.ShaderGUI
|
||||||
|
{
|
||||||
|
public class NiloToonCharacterFurShaderGUI : UnityEditor.ShaderGUI
|
||||||
|
{
|
||||||
|
// Foldout states
|
||||||
|
private static bool showBaseColor = true;
|
||||||
|
private static bool showNormalMap = false;
|
||||||
|
private static bool showFurShape = true;
|
||||||
|
private static bool showFurRim = false;
|
||||||
|
private static bool showCelShading = true;
|
||||||
|
private static bool showShadowColor = false;
|
||||||
|
private static bool showMatCap = false;
|
||||||
|
private static bool showRimLight = false;
|
||||||
|
private static bool showEmission = false;
|
||||||
|
private static bool showOcclusion = false;
|
||||||
|
private static bool showOutline = false;
|
||||||
|
private static bool showRendering = false;
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
private static GUIStyle headerStyle;
|
||||||
|
private static GUIStyle foldoutStyle;
|
||||||
|
private static bool stylesInitialized = false;
|
||||||
|
|
||||||
|
private static void InitStyles()
|
||||||
|
{
|
||||||
|
if (stylesInitialized) return;
|
||||||
|
|
||||||
|
headerStyle = new GUIStyle(EditorStyles.boldLabel)
|
||||||
|
{
|
||||||
|
fontSize = 12,
|
||||||
|
margin = new RectOffset(0, 0, 10, 5)
|
||||||
|
};
|
||||||
|
|
||||||
|
foldoutStyle = new GUIStyle(EditorStyles.foldout)
|
||||||
|
{
|
||||||
|
fontStyle = FontStyle.Bold,
|
||||||
|
fontSize = 11
|
||||||
|
};
|
||||||
|
|
||||||
|
stylesInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
|
||||||
|
{
|
||||||
|
InitStyles();
|
||||||
|
|
||||||
|
Material material = materialEditor.target as Material;
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
EditorGUILayout.LabelField("NiloToon Character Fur Shader", EditorStyles.boldLabel);
|
||||||
|
EditorGUILayout.HelpBox(
|
||||||
|
"Single-material fur shader with Base + Fur Shell rendering.\n\n" +
|
||||||
|
"Setup:\n" +
|
||||||
|
"1. Add 'NiloToonFurRendererFeature' to your URP Renderer Asset\n" +
|
||||||
|
"2. Apply this shader to your mesh material (single material slot)\n\n" +
|
||||||
|
"The shader will render base mesh first, then fur shells on top.",
|
||||||
|
MessageType.Info);
|
||||||
|
DrawSeparator();
|
||||||
|
|
||||||
|
// Base Color Section
|
||||||
|
showBaseColor = DrawSection("Base Color", showBaseColor, () =>
|
||||||
|
{
|
||||||
|
DrawProperty(materialEditor, properties, "_BaseMap", "Base Map");
|
||||||
|
DrawProperty(materialEditor, properties, "_BaseColor", "Base Color");
|
||||||
|
DrawProperty(materialEditor, properties, "_Cutoff", "Alpha Cutoff");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Normal Map Section
|
||||||
|
showNormalMap = DrawSection("Normal Map", showNormalMap, () =>
|
||||||
|
{
|
||||||
|
DrawToggleProperty(materialEditor, properties, "_UseNormalMap", "Enable Normal Map", "_NORMALMAP", material);
|
||||||
|
if (material.IsKeywordEnabled("_NORMALMAP"))
|
||||||
|
{
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
DrawProperty(materialEditor, properties, "_BumpMap", "Normal Map");
|
||||||
|
DrawProperty(materialEditor, properties, "_BumpScale", "Normal Scale");
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fur Shape Section
|
||||||
|
showFurShape = DrawSection("Fur Shape", showFurShape, () =>
|
||||||
|
{
|
||||||
|
DrawProperty(materialEditor, properties, "_FurNoiseMask", "Fur Noise Mask");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurMask", "Fur Mask");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurLengthMask", "Fur Length Mask");
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
DrawProperty(materialEditor, properties, "_FurVector", "Fur Direction (XYZ) + Length (W)");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurVectorTex", "Fur Direction Map");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurVectorScale", "Fur Direction Scale");
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
DrawProperty(materialEditor, properties, "_FurGravity", "Fur Gravity");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurRandomize", "Fur Randomize");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurAO", "Fur Ambient Occlusion");
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
DrawProperty(materialEditor, properties, "_FurLayerNum", "Fur Layer Count");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurRootOffset", "Fur Root Offset");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fur Rim Section
|
||||||
|
showFurRim = DrawSection("Fur Rim Light", showFurRim, () =>
|
||||||
|
{
|
||||||
|
DrawProperty(materialEditor, properties, "_FurRimColor", "Fur Rim Color");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurRimFresnelPower", "Fur Rim Fresnel Power");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurRimAntiLight", "Fur Rim Anti-Light");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cel Shading Section
|
||||||
|
showCelShading = DrawSection("Cel Shading", showCelShading, () =>
|
||||||
|
{
|
||||||
|
DrawProperty(materialEditor, properties, "_CelShadeMidPoint", "Cel Shade Mid Point");
|
||||||
|
DrawProperty(materialEditor, properties, "_CelShadeSoftness", "Cel Shade Softness");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Shadow Color Section
|
||||||
|
showShadowColor = DrawSection("Shadow Color", showShadowColor, () =>
|
||||||
|
{
|
||||||
|
DrawToggleProperty(materialEditor, properties, "_EnableShadowColor", "Enable Shadow Color", "_SHADOW_COLOR", material);
|
||||||
|
if (material.IsKeywordEnabled("_SHADOW_COLOR"))
|
||||||
|
{
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
DrawProperty(materialEditor, properties, "_ShadowColor", "Shadow Tint Color");
|
||||||
|
DrawProperty(materialEditor, properties, "_ShadowBrightness", "Shadow Brightness");
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
EditorGUILayout.LabelField("HSV Adjustment", EditorStyles.miniLabel);
|
||||||
|
DrawProperty(materialEditor, properties, "_ShadowHueShift", "Hue Shift");
|
||||||
|
DrawProperty(materialEditor, properties, "_ShadowSaturationBoost", "Saturation Boost");
|
||||||
|
DrawProperty(materialEditor, properties, "_ShadowValueMultiplier", "Value Multiplier");
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// MatCap Section
|
||||||
|
showMatCap = DrawSection("MatCap", showMatCap, () =>
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField("MatCap Additive", EditorStyles.miniLabel);
|
||||||
|
DrawToggleProperty(materialEditor, properties, "_UseMatCapAdd", "Enable MatCap (Add)", "_MATCAP_ADD", material);
|
||||||
|
if (material.IsKeywordEnabled("_MATCAP_ADD"))
|
||||||
|
{
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
DrawProperty(materialEditor, properties, "_MatCapAddMap", "MatCap Add Map");
|
||||||
|
DrawProperty(materialEditor, properties, "_MatCapAddColor", "MatCap Add Color");
|
||||||
|
DrawProperty(materialEditor, properties, "_MatCapAddIntensity", "MatCap Add Intensity");
|
||||||
|
DrawProperty(materialEditor, properties, "_MatCapAddMask", "MatCap Add Mask");
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
EditorGUILayout.LabelField("MatCap Multiply", EditorStyles.miniLabel);
|
||||||
|
DrawToggleProperty(materialEditor, properties, "_UseMatCapMul", "Enable MatCap (Multiply)", "_MATCAP_MUL", material);
|
||||||
|
if (material.IsKeywordEnabled("_MATCAP_MUL"))
|
||||||
|
{
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
DrawProperty(materialEditor, properties, "_MatCapMulMap", "MatCap Multiply Map");
|
||||||
|
DrawProperty(materialEditor, properties, "_MatCapMulIntensity", "MatCap Multiply Intensity");
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rim Light Section
|
||||||
|
showRimLight = DrawSection("Rim Light (General)", showRimLight, () =>
|
||||||
|
{
|
||||||
|
DrawToggleProperty(materialEditor, properties, "_UseRimLight", "Enable Rim Light", "_RIMLIGHT", material);
|
||||||
|
if (material.IsKeywordEnabled("_RIMLIGHT"))
|
||||||
|
{
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
DrawProperty(materialEditor, properties, "_RimLightColor", "Rim Light Color");
|
||||||
|
DrawProperty(materialEditor, properties, "_RimLightPower", "Rim Light Power");
|
||||||
|
DrawProperty(materialEditor, properties, "_RimLightIntensity", "Rim Light Intensity");
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Emission Section
|
||||||
|
showEmission = DrawSection("Emission", showEmission, () =>
|
||||||
|
{
|
||||||
|
DrawToggleProperty(materialEditor, properties, "_UseEmission", "Enable Emission", "_EMISSION", material);
|
||||||
|
if (material.IsKeywordEnabled("_EMISSION"))
|
||||||
|
{
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
DrawProperty(materialEditor, properties, "_EmissionMap", "Emission Map");
|
||||||
|
DrawProperty(materialEditor, properties, "_EmissionColor", "Emission Color");
|
||||||
|
DrawProperty(materialEditor, properties, "_EmissionIntensity", "Emission Intensity");
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Occlusion Section
|
||||||
|
showOcclusion = DrawSection("Occlusion", showOcclusion, () =>
|
||||||
|
{
|
||||||
|
DrawToggleProperty(materialEditor, properties, "_UseOcclusion", "Enable Occlusion Map", "_OCCLUSIONMAP", material);
|
||||||
|
if (material.IsKeywordEnabled("_OCCLUSIONMAP"))
|
||||||
|
{
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
DrawProperty(materialEditor, properties, "_OcclusionMap", "Occlusion Map");
|
||||||
|
DrawProperty(materialEditor, properties, "_OcclusionStrength", "Occlusion Strength");
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Outline Section
|
||||||
|
showOutline = DrawSection("Outline", showOutline, () =>
|
||||||
|
{
|
||||||
|
DrawProperty(materialEditor, properties, "_OutlineWidth", "Outline Width");
|
||||||
|
DrawProperty(materialEditor, properties, "_OutlineColor", "Outline Color");
|
||||||
|
DrawProperty(materialEditor, properties, "_OutlineWidthMask", "Outline Width Mask");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rendering Options Section
|
||||||
|
showRendering = DrawSection("Rendering Options", showRendering, () =>
|
||||||
|
{
|
||||||
|
DrawProperty(materialEditor, properties, "_Cull", "Cull Mode");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurCull", "Fur Cull Mode");
|
||||||
|
DrawProperty(materialEditor, properties, "_ZWrite", "ZWrite");
|
||||||
|
DrawProperty(materialEditor, properties, "_FurZWrite", "Fur ZWrite");
|
||||||
|
DrawProperty(materialEditor, properties, "_ZTest", "ZTest");
|
||||||
|
});
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
|
||||||
|
// Render Queue
|
||||||
|
materialEditor.RenderQueueField();
|
||||||
|
materialEditor.EnableInstancingField();
|
||||||
|
materialEditor.DoubleSidedGIField();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DrawSection(string title, bool foldout, Action drawContent)
|
||||||
|
{
|
||||||
|
EditorGUILayout.Space(2);
|
||||||
|
|
||||||
|
// Section header with foldout
|
||||||
|
Rect headerRect = EditorGUILayout.GetControlRect(false, 20);
|
||||||
|
headerRect.x -= 2;
|
||||||
|
headerRect.width += 4;
|
||||||
|
|
||||||
|
// Background
|
||||||
|
EditorGUI.DrawRect(headerRect, new Color(0.22f, 0.22f, 0.22f, 1f));
|
||||||
|
|
||||||
|
// Foldout
|
||||||
|
headerRect.x += 4;
|
||||||
|
foldout = EditorGUI.Foldout(headerRect, foldout, title, true, foldoutStyle);
|
||||||
|
|
||||||
|
if (foldout)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||||
|
EditorGUI.indentLevel++;
|
||||||
|
drawContent?.Invoke();
|
||||||
|
EditorGUI.indentLevel--;
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
}
|
||||||
|
|
||||||
|
return foldout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawProperty(MaterialEditor editor, MaterialProperty[] properties, string propertyName, string label)
|
||||||
|
{
|
||||||
|
MaterialProperty prop = FindProperty(propertyName, properties, false);
|
||||||
|
if (prop != null)
|
||||||
|
{
|
||||||
|
editor.ShaderProperty(prop, label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawToggleProperty(MaterialEditor editor, MaterialProperty[] properties, string propertyName, string label, string keyword, Material material)
|
||||||
|
{
|
||||||
|
MaterialProperty prop = FindProperty(propertyName, properties, false);
|
||||||
|
if (prop != null)
|
||||||
|
{
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
editor.ShaderProperty(prop, label);
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
if (prop.floatValue > 0.5f)
|
||||||
|
material.EnableKeyword(keyword);
|
||||||
|
else
|
||||||
|
material.DisableKeyword(keyword);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawSeparator()
|
||||||
|
{
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
Rect rect = EditorGUILayout.GetControlRect(false, 1);
|
||||||
|
EditorGUI.DrawRect(rect, new Color(0.5f, 0.5f, 0.5f, 0.5f));
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3ad6027c1c29b71488586df1e8150fa7
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
// NiloToon Fur Renderer Feature
|
||||||
|
// Add this to your URP Renderer to enable fur shell rendering
|
||||||
|
// This allows single-material fur shaders to work properly
|
||||||
|
//
|
||||||
|
// Note: Fur mask rendering is now integrated into NiloToonPrepassBufferRTPass
|
||||||
|
// The fur mask is automatically rendered to G and B channels of _NiloToonPrepassBufferTex
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Rendering.Universal;
|
||||||
|
|
||||||
|
namespace NiloToon.NiloToonURP
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class NiloToonFurRendererFeatureSettings
|
||||||
|
{
|
||||||
|
[Header("Fur Shell Settings")]
|
||||||
|
public NiloToonFurShellPass.Settings furShellSettings = new NiloToonFurShellPass.Settings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NiloToonFurRendererFeature : ScriptableRendererFeature
|
||||||
|
{
|
||||||
|
public NiloToonFurRendererFeatureSettings settings = new NiloToonFurRendererFeatureSettings();
|
||||||
|
|
||||||
|
NiloToonFurShellPass FurShellPass;
|
||||||
|
|
||||||
|
public override void Create()
|
||||||
|
{
|
||||||
|
ReInitPassesIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReInitPassesIfNeeded()
|
||||||
|
{
|
||||||
|
if (FurShellPass == null)
|
||||||
|
FurShellPass = new NiloToonFurShellPass(settings.furShellSettings);
|
||||||
|
|
||||||
|
// Set render pass events
|
||||||
|
FurShellPass.renderPassEvent = settings.furShellSettings.renderTiming;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
||||||
|
{
|
||||||
|
ReInitPassesIfNeeded();
|
||||||
|
|
||||||
|
// Update render timing in case it changed
|
||||||
|
FurShellPass.renderPassEvent = settings.furShellSettings.renderTiming;
|
||||||
|
|
||||||
|
// Enqueue fur shell pass for actual fur rendering
|
||||||
|
// Note: Fur mask is rendered via NiloToonPrepassBufferRTPass (NiloToonFurShellMask LightMode)
|
||||||
|
renderer.EnqueuePass(FurShellPass);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2022_2_OR_NEWER
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
FurShellPass = null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4076e5ecd1634a74eaabed924c9a971c
|
||||||
@ -0,0 +1,220 @@
|
|||||||
|
// NiloToon Fur Mask Pass
|
||||||
|
// Renders fur shells to a dedicated mask buffer for fur area detection
|
||||||
|
// Separate from main fur rendering for cleaner architecture
|
||||||
|
// Based on NiloToonPrepassBufferRTPass pattern
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Experimental.Rendering;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
using UnityEngine.Rendering.RendererUtils;
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
using UnityEngine.Rendering.RenderGraphModule;
|
||||||
|
#endif
|
||||||
|
using UnityEngine.Rendering.Universal;
|
||||||
|
|
||||||
|
namespace NiloToon.NiloToonURP
|
||||||
|
{
|
||||||
|
public class NiloToonFurMaskPass : ScriptableRenderPass
|
||||||
|
{
|
||||||
|
static readonly ShaderTagId furShellMaskLightModeShaderTagId = new ShaderTagId("NiloToonFurShellMask");
|
||||||
|
static readonly int FurMaskTexId = Shader.PropertyToID("_NiloToonFurMaskTex");
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Settings
|
||||||
|
{
|
||||||
|
[Tooltip("Create a mask buffer for fur area detection.\n" +
|
||||||
|
"This creates _NiloToonFurMaskTex which can be used for post-processing.\n\nDefault: ON")]
|
||||||
|
public bool Enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings settings;
|
||||||
|
RenderQueueRange renderQueueRange;
|
||||||
|
|
||||||
|
#if UNITY_2022_2_OR_NEWER
|
||||||
|
RTHandle furMaskRTHColor;
|
||||||
|
RTHandle furMaskRTHDepth;
|
||||||
|
#else
|
||||||
|
RenderTargetHandle furMaskRTHandle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public NiloToonFurMaskPass(Settings settings)
|
||||||
|
{
|
||||||
|
this.settings = settings;
|
||||||
|
this.renderQueueRange = RenderQueueRange.all;
|
||||||
|
|
||||||
|
#if !UNITY_2022_2_OR_NEWER
|
||||||
|
furMaskRTHandle.Init("_NiloToonFurMaskRT");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
base.profilingSampler = new ProfilingSampler(nameof(NiloToonFurMaskPass));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
[Obsolete]
|
||||||
|
#endif
|
||||||
|
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
|
||||||
|
{
|
||||||
|
if (!settings.Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var cameraData = renderingData.cameraData;
|
||||||
|
|
||||||
|
#if UNITY_2022_2_OR_NEWER
|
||||||
|
// [color RTHandle's Descriptor] - same pattern as NiloToonPrepassBufferRTPass
|
||||||
|
var colorDesc = cameraData.cameraTargetDescriptor;
|
||||||
|
colorDesc.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm;
|
||||||
|
colorDesc.depthBufferBits = 0;
|
||||||
|
colorDesc.msaaSamples = 1;
|
||||||
|
|
||||||
|
// [depth RTHandle's Descriptor] - create own depth buffer like PrepassBufferRTPass
|
||||||
|
var depthDesc = cameraData.cameraTargetDescriptor;
|
||||||
|
depthDesc.graphicsFormat = GraphicsFormat.None; // Depth only rendering
|
||||||
|
depthDesc.depthStencilFormat = cameraData.cameraTargetDescriptor.depthStencilFormat;
|
||||||
|
depthDesc.msaaSamples = 1;
|
||||||
|
|
||||||
|
RenderingUtils.ReAllocateIfNeeded(ref furMaskRTHColor, colorDesc, name: "_NiloToonFurMaskColor");
|
||||||
|
RenderingUtils.ReAllocateIfNeeded(ref furMaskRTHDepth, depthDesc, name: "_NiloToonFurMaskDepth");
|
||||||
|
|
||||||
|
// Set global RT
|
||||||
|
cmd.SetGlobalTexture(FurMaskTexId, furMaskRTHColor);
|
||||||
|
|
||||||
|
// Configure target with own color and depth buffers
|
||||||
|
ConfigureTarget(furMaskRTHColor, furMaskRTHDepth);
|
||||||
|
ConfigureClear(ClearFlag.All, Color.black);
|
||||||
|
#else
|
||||||
|
var furMaskDesc = cameraData.cameraTargetDescriptor;
|
||||||
|
furMaskDesc.colorFormat = RenderTextureFormat.ARGB32;
|
||||||
|
furMaskDesc.depthStencilFormat = cameraData.cameraTargetDescriptor.depthStencilFormat;
|
||||||
|
furMaskDesc.msaaSamples = 1;
|
||||||
|
|
||||||
|
cmd.GetTemporaryRT(furMaskRTHandle.id, furMaskDesc);
|
||||||
|
cmd.SetGlobalTexture(FurMaskTexId, furMaskRTHandle.Identifier());
|
||||||
|
|
||||||
|
ConfigureTarget(new RenderTargetIdentifier(furMaskRTHandle.Identifier(), 0, CubemapFace.Unknown, -1));
|
||||||
|
ConfigureClear(ClearFlag.All, Color.black);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
[Obsolete]
|
||||||
|
#endif
|
||||||
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||||
|
{
|
||||||
|
if (!settings.Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Never draw in Preview
|
||||||
|
Camera camera = renderingData.cameraData.camera;
|
||||||
|
if (camera.cameraType == CameraType.Preview)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var cmd = CommandBufferPool.Get();
|
||||||
|
using (new ProfilingScope(cmd, base.profilingSampler))
|
||||||
|
{
|
||||||
|
// Execute command buffer before DrawRenderers (frame debugger requirement)
|
||||||
|
context.ExecuteCommandBuffer(cmd);
|
||||||
|
cmd.Clear();
|
||||||
|
|
||||||
|
// Draw all fur shells with NiloToonFurShellMask pass
|
||||||
|
var filterSetting = new FilteringSettings(renderQueueRange);
|
||||||
|
var sortFlags = SortingCriteria.CommonTransparent;
|
||||||
|
var drawSettings = CreateDrawingSettings(furShellMaskLightModeShaderTagId, ref renderingData, sortFlags);
|
||||||
|
drawSettings.perObjectData = PerObjectData.None;
|
||||||
|
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSetting);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.ExecuteCommandBuffer(cmd);
|
||||||
|
cmd.Clear();
|
||||||
|
CommandBufferPool.Release(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnCameraCleanup(CommandBuffer cmd)
|
||||||
|
{
|
||||||
|
// To Release a RTHandle, do it in ScriptableRendererFeature's Dispose(), don't do it in OnCameraCleanup(...)
|
||||||
|
#if !UNITY_2022_2_OR_NEWER
|
||||||
|
if (settings.Enabled)
|
||||||
|
{
|
||||||
|
cmd.ReleaseTemporaryRT(furMaskRTHandle.id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2022_2_OR_NEWER
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
furMaskRTHColor?.Release();
|
||||||
|
furMaskRTHDepth?.Release();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
private class FurMaskPassData
|
||||||
|
{
|
||||||
|
public UniversalCameraData cameraData;
|
||||||
|
public TextureHandle colorTarget;
|
||||||
|
public TextureHandle depthTarget;
|
||||||
|
public RendererListHandle rendererList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
||||||
|
{
|
||||||
|
if (!settings.Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var cameraData = frameData.Get<UniversalCameraData>();
|
||||||
|
var resourceData = frameData.Get<UniversalResourceData>();
|
||||||
|
var renderingData = frameData.Get<UniversalRenderingData>();
|
||||||
|
|
||||||
|
// Skip Preview cameras - same check as Execute
|
||||||
|
if (cameraData.camera.cameraType == CameraType.Preview)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using (var builder = renderGraph.AddRasterRenderPass<FurMaskPassData>("NiloToon Fur Mask Buffer", out var passData, base.profilingSampler))
|
||||||
|
{
|
||||||
|
passData.cameraData = cameraData;
|
||||||
|
|
||||||
|
// Create render textures for RG - EXACT same descriptors as OnCameraSetup
|
||||||
|
var colorDesc = cameraData.cameraTargetDescriptor;
|
||||||
|
colorDesc.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm;
|
||||||
|
colorDesc.depthBufferBits = 0;
|
||||||
|
colorDesc.msaaSamples = 1;
|
||||||
|
|
||||||
|
var depthDesc = cameraData.cameraTargetDescriptor;
|
||||||
|
depthDesc.graphicsFormat = GraphicsFormat.None; // Depth only rendering
|
||||||
|
depthDesc.depthStencilFormat = cameraData.cameraTargetDescriptor.depthStencilFormat;
|
||||||
|
depthDesc.msaaSamples = 1;
|
||||||
|
|
||||||
|
passData.colorTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, colorDesc, "_NiloToonFurMaskColor", false);
|
||||||
|
passData.depthTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDesc, "_NiloToonFurMaskDepth", false);
|
||||||
|
|
||||||
|
// Create renderer list - EXACT same settings as Execute
|
||||||
|
var renderListDesc = new RendererListDesc(furShellMaskLightModeShaderTagId, renderingData.cullResults, cameraData.camera)
|
||||||
|
{
|
||||||
|
sortingCriteria = SortingCriteria.CommonTransparent,
|
||||||
|
renderQueueRange = renderQueueRange,
|
||||||
|
};
|
||||||
|
passData.rendererList = renderGraph.CreateRendererList(renderListDesc);
|
||||||
|
|
||||||
|
// Set up render targets - Match ConfigureTarget behavior
|
||||||
|
builder.SetRenderAttachment(passData.colorTarget, 0, AccessFlags.Write);
|
||||||
|
builder.SetRenderAttachmentDepth(passData.depthTarget, AccessFlags.Write);
|
||||||
|
|
||||||
|
builder.UseRendererList(passData.rendererList);
|
||||||
|
|
||||||
|
// Set global textures - Match cmd.SetGlobalTexture behavior
|
||||||
|
builder.SetGlobalTextureAfterPass(passData.colorTarget, FurMaskTexId);
|
||||||
|
|
||||||
|
builder.SetRenderFunc((FurMaskPassData data, RasterGraphContext context) =>
|
||||||
|
{
|
||||||
|
// Match ConfigureClear(ClearFlag.All, Color.black) behavior
|
||||||
|
context.cmd.ClearRenderTarget(RTClearFlags.All, Color.black, 1.0f, 0);
|
||||||
|
|
||||||
|
// Match context.DrawRenderers behavior
|
||||||
|
context.cmd.DrawRendererList(data.rendererList);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d398264d435e9314bae19d3e5532f775
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
// NiloToon Fur Shell Pass
|
||||||
|
// Renders fur shell pass for materials with "NiloToonFurShell" LightMode tag
|
||||||
|
// Only handles fur rendering - mask buffer is handled by NiloToonFurMaskPass
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Rendering;
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
using UnityEngine.Rendering.RenderGraphModule;
|
||||||
|
#endif
|
||||||
|
using UnityEngine.Rendering.Universal;
|
||||||
|
|
||||||
|
namespace NiloToon.NiloToonURP
|
||||||
|
{
|
||||||
|
public class NiloToonFurShellPass : ScriptableRenderPass
|
||||||
|
{
|
||||||
|
static readonly ShaderTagId furShellLightModeShaderTagId = new ShaderTagId("NiloToonFurShell");
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Settings
|
||||||
|
{
|
||||||
|
[Header("Fur Shell Settings")]
|
||||||
|
|
||||||
|
[Tooltip("Enable to render fur shells.\n\nDefault: ON")]
|
||||||
|
[OverrideDisplayName("Enable?")]
|
||||||
|
[Revertible]
|
||||||
|
public bool ShouldRenderFurShell = true;
|
||||||
|
|
||||||
|
[Tooltip("When to render fur shells in the rendering pipeline.\n\nDefault: AfterRenderingOpaques")]
|
||||||
|
[Revertible]
|
||||||
|
[OverrideDisplayName("Render Timing")]
|
||||||
|
public RenderPassEvent renderTiming = RenderPassEvent.AfterRenderingOpaques;
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings settings;
|
||||||
|
ProfilingSampler m_ProfilingSampler;
|
||||||
|
RenderQueueRange renderQueueRange;
|
||||||
|
|
||||||
|
public NiloToonFurShellPass(Settings settings)
|
||||||
|
{
|
||||||
|
this.settings = settings;
|
||||||
|
m_ProfilingSampler = new ProfilingSampler("NiloToonFurShellPass");
|
||||||
|
this.renderQueueRange = RenderQueueRange.all;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
[Obsolete]
|
||||||
|
#endif
|
||||||
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
||||||
|
{
|
||||||
|
if (!settings.ShouldRenderFurShell)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CommandBuffer cmd = CommandBufferPool.Get();
|
||||||
|
|
||||||
|
using (new ProfilingScope(cmd, m_ProfilingSampler))
|
||||||
|
{
|
||||||
|
context.ExecuteCommandBuffer(cmd);
|
||||||
|
cmd.Clear();
|
||||||
|
|
||||||
|
DrawingSettings drawingSettings = CreateDrawingSettings(
|
||||||
|
furShellLightModeShaderTagId,
|
||||||
|
ref renderingData,
|
||||||
|
SortingCriteria.CommonTransparent
|
||||||
|
);
|
||||||
|
|
||||||
|
FilteringSettings filteringSettings = new FilteringSettings(renderQueueRange);
|
||||||
|
context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filteringSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.ExecuteCommandBuffer(cmd);
|
||||||
|
cmd.Clear();
|
||||||
|
CommandBufferPool.Release(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
private class PassData
|
||||||
|
{
|
||||||
|
public RendererListHandle rendererListHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
||||||
|
{
|
||||||
|
if (!settings.ShouldRenderFurShell)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UniversalRenderingData renderingData = frameData.Get<UniversalRenderingData>();
|
||||||
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
||||||
|
UniversalLightData lightData = frameData.Get<UniversalLightData>();
|
||||||
|
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
|
||||||
|
|
||||||
|
using (var builder = renderGraph.AddRasterRenderPass<PassData>("NiloToonFurShellPass", out var passData, m_ProfilingSampler))
|
||||||
|
{
|
||||||
|
var drawingSettings = RenderingUtils.CreateDrawingSettings(
|
||||||
|
furShellLightModeShaderTagId,
|
||||||
|
renderingData,
|
||||||
|
cameraData,
|
||||||
|
lightData,
|
||||||
|
SortingCriteria.CommonTransparent
|
||||||
|
);
|
||||||
|
|
||||||
|
var filteringSettings = new FilteringSettings(renderQueueRange);
|
||||||
|
var renderListParams = new RendererListParams(renderingData.cullResults, drawingSettings, filteringSettings);
|
||||||
|
passData.rendererListHandle = renderGraph.CreateRendererList(renderListParams);
|
||||||
|
|
||||||
|
builder.UseRendererList(passData.rendererListHandle);
|
||||||
|
|
||||||
|
builder.SetRenderAttachment(resourceData.activeColorTexture, 0);
|
||||||
|
builder.SetRenderAttachmentDepth(resourceData.activeDepthTexture);
|
||||||
|
|
||||||
|
builder.SetRenderFunc((PassData data, RasterGraphContext rgContext) =>
|
||||||
|
{
|
||||||
|
rgContext.cmd.DrawRendererList(data.rendererListHandle);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6edb03bf5b2c68d4dbc8b39fac860935
|
||||||
@ -5,12 +5,14 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
_NiloToonPrepassBufferRT is storing the following data
|
_NiloToonPrepassBufferRT is storing the following data
|
||||||
-r: face
|
-r: face (legacy, kept for compatibility)
|
||||||
-g: character visible area (for NiloToon Bloom / NiloToon Tonemapping)
|
-g: character visible area (for NiloToon Bloom / NiloToon Tonemapping) - includes face, body, and fur
|
||||||
-b: unused
|
-b: unused
|
||||||
-a: unused
|
-a: unused
|
||||||
|
|
||||||
* We may draw IsFace,IsSkin,RimArea into this RT in future versions
|
* We may draw IsFace,IsSkin,RimArea into this RT in future versions
|
||||||
|
* Fur mask is now integrated: renders fur shells to G channel
|
||||||
|
* All character areas (face, body, fur) use G channel for unified character mask
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@ -38,6 +40,10 @@ namespace NiloToon.NiloToonURP
|
|||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
static readonly ShaderTagId shaderTagId = new ShaderTagId("NiloToonPrepassBuffer");
|
static readonly ShaderTagId shaderTagId = new ShaderTagId("NiloToonPrepassBuffer");
|
||||||
|
static readonly ShaderTagId furShellMaskShaderTagId = new ShaderTagId("NiloToonFurShellMask");
|
||||||
|
|
||||||
|
// Fur mask settings
|
||||||
|
bool enableFurMask = true;
|
||||||
|
|
||||||
// Constructor(will not call every frame)
|
// Constructor(will not call every frame)
|
||||||
public NiloToonPrepassBufferRTPass(NiloToonRendererFeatureSettings allSettings)
|
public NiloToonPrepassBufferRTPass(NiloToonRendererFeatureSettings allSettings)
|
||||||
@ -50,6 +56,14 @@ namespace NiloToon.NiloToonURP
|
|||||||
|
|
||||||
base.profilingSampler = new ProfilingSampler(nameof(NiloToonPrepassBufferRTPass));
|
base.profilingSampler = new ProfilingSampler(nameof(NiloToonPrepassBufferRTPass));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable fur mask rendering
|
||||||
|
/// </summary>
|
||||||
|
public void SetFurMaskEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
enableFurMask = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
// This method is called before executing the render pass.
|
// This method is called before executing the render pass.
|
||||||
// It can be used to configure render targets and their clear state. Also to create temporary render target textures.
|
// It can be used to configure render targets and their clear state. Also to create temporary render target textures.
|
||||||
@ -149,16 +163,27 @@ namespace NiloToon.NiloToonURP
|
|||||||
cmd.Clear();
|
cmd.Clear();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// draw all nilotoon character renderer's "NiloToonPrepassBuffer" pass using SRP batching
|
// 1. Draw all nilotoon character renderer's "NiloToonPrepassBuffer" pass using SRP batching
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
var filterSetting = new FilteringSettings(RenderQueueRange.opaque); //TODO: should include transparent also?
|
var filterSetting = new FilteringSettings(RenderQueueRange.opaque); //TODO: should include transparent also?
|
||||||
|
|
||||||
var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
|
var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
|
||||||
var drawSettings = CreateDrawingSettings(shaderTagId, ref renderingData, sortFlags);
|
var drawSettings = CreateDrawingSettings(shaderTagId, ref renderingData, sortFlags);
|
||||||
drawSettings.perObjectData = PerObjectData.None;
|
drawSettings.perObjectData = PerObjectData.None;
|
||||||
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSetting);
|
context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSetting);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 2. Draw fur shell mask (NiloToonFurShellMask pass) - adds fur area to G and B channels
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
if (enableFurMask)
|
||||||
|
{
|
||||||
|
var furFilterSetting = new FilteringSettings(RenderQueueRange.all);
|
||||||
|
var furDrawSettings = CreateDrawingSettings(furShellMaskShaderTagId, ref renderingData, SortingCriteria.CommonTransparent);
|
||||||
|
furDrawSettings.perObjectData = PerObjectData.None;
|
||||||
|
context.DrawRenderers(renderingData.cullResults, ref furDrawSettings, ref furFilterSetting);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// must write these line after using{} finished, to ensure profiler and frame debugger display correctness
|
// must write these line after using{} finished, to ensure profiler and frame debugger display correctness
|
||||||
context.ExecuteCommandBuffer(cmd);
|
context.ExecuteCommandBuffer(cmd);
|
||||||
cmd.Clear();
|
cmd.Clear();
|
||||||
@ -187,13 +212,15 @@ namespace NiloToon.NiloToonURP
|
|||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// RG support
|
// RG support
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
#if UNITY_6000_0_OR_NEWER
|
#if UNITY_6000_0_OR_NEWER
|
||||||
private class PrepassBufferPassData
|
private class PrepassBufferPassData
|
||||||
{
|
{
|
||||||
public UniversalCameraData cameraData;
|
public UniversalCameraData cameraData;
|
||||||
public TextureHandle colorTarget;
|
public TextureHandle colorTarget;
|
||||||
public TextureHandle depthTarget;
|
public TextureHandle depthTarget;
|
||||||
public RendererListHandle rendererList;
|
public RendererListHandle rendererList;
|
||||||
|
public RendererListHandle furRendererList;
|
||||||
|
public bool enableFurMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext)
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameContext)
|
||||||
@ -209,6 +236,7 @@ namespace NiloToon.NiloToonURP
|
|||||||
using (var builder = renderGraph.AddRasterRenderPass<PrepassBufferPassData>("NiloToon Prepass Buffer", out var passData, base.profilingSampler))
|
using (var builder = renderGraph.AddRasterRenderPass<PrepassBufferPassData>("NiloToon Prepass Buffer", out var passData, base.profilingSampler))
|
||||||
{
|
{
|
||||||
passData.cameraData = cameraData;
|
passData.cameraData = cameraData;
|
||||||
|
passData.enableFurMask = enableFurMask;
|
||||||
|
|
||||||
// Create render textures for RG - EXACT same descriptors as OnCameraSetup
|
// Create render textures for RG - EXACT same descriptors as OnCameraSetup
|
||||||
var colorDesc = cameraData.cameraTargetDescriptor;
|
var colorDesc = cameraData.cameraTargetDescriptor;
|
||||||
@ -224,19 +252,28 @@ namespace NiloToon.NiloToonURP
|
|||||||
passData.colorTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, colorDesc, "_NiloToonPrepassBufferColor", false);
|
passData.colorTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, colorDesc, "_NiloToonPrepassBufferColor", false);
|
||||||
passData.depthTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDesc, "_NiloToonPrepassBufferDepth", false);
|
passData.depthTarget = UniversalRenderer.CreateRenderGraphTexture(renderGraph, depthDesc, "_NiloToonPrepassBufferDepth", false);
|
||||||
|
|
||||||
// Create renderer list - EXACT same settings as Execute
|
// Create renderer list for character prepass - EXACT same settings as Execute
|
||||||
var renderListDesc = new RendererListDesc(shaderTagId, renderingData.cullResults, cameraData.camera)
|
var renderListDesc = new RendererListDesc(shaderTagId, renderingData.cullResults, cameraData.camera)
|
||||||
{
|
{
|
||||||
sortingCriteria = cameraData.defaultOpaqueSortFlags, // Match: var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
|
sortingCriteria = cameraData.defaultOpaqueSortFlags,
|
||||||
renderQueueRange = RenderQueueRange.opaque, // Match: var filterSetting = new FilteringSettings(RenderQueueRange.opaque);
|
renderQueueRange = RenderQueueRange.opaque,
|
||||||
};
|
};
|
||||||
passData.rendererList = renderGraph.CreateRendererList(renderListDesc);
|
passData.rendererList = renderGraph.CreateRendererList(renderListDesc);
|
||||||
|
|
||||||
|
// Create renderer list for fur shell mask
|
||||||
|
var furRenderListDesc = new RendererListDesc(furShellMaskShaderTagId, renderingData.cullResults, cameraData.camera)
|
||||||
|
{
|
||||||
|
sortingCriteria = SortingCriteria.CommonTransparent,
|
||||||
|
renderQueueRange = RenderQueueRange.all,
|
||||||
|
};
|
||||||
|
passData.furRendererList = renderGraph.CreateRendererList(furRenderListDesc);
|
||||||
|
|
||||||
// Set up render targets - Match ConfigureTarget behavior
|
// Set up render targets - Match ConfigureTarget behavior
|
||||||
builder.SetRenderAttachment(passData.colorTarget, 0, AccessFlags.Write);
|
builder.SetRenderAttachment(passData.colorTarget, 0, AccessFlags.Write);
|
||||||
builder.SetRenderAttachmentDepth(passData.depthTarget, AccessFlags.Write);
|
builder.SetRenderAttachmentDepth(passData.depthTarget, AccessFlags.Write);
|
||||||
|
|
||||||
builder.UseRendererList(passData.rendererList);
|
builder.UseRendererList(passData.rendererList);
|
||||||
|
builder.UseRendererList(passData.furRendererList);
|
||||||
|
|
||||||
// Set global textures - Match cmd.SetGlobalTexture behavior
|
// Set global textures - Match cmd.SetGlobalTexture behavior
|
||||||
builder.SetGlobalTextureAfterPass(passData.colorTarget, Shader.PropertyToID("_NiloToonPrepassBufferTex"));
|
builder.SetGlobalTextureAfterPass(passData.colorTarget, Shader.PropertyToID("_NiloToonPrepassBufferTex"));
|
||||||
@ -246,9 +283,15 @@ namespace NiloToon.NiloToonURP
|
|||||||
{
|
{
|
||||||
// Match ConfigureClear(ClearFlag.All, Color.black) behavior
|
// Match ConfigureClear(ClearFlag.All, Color.black) behavior
|
||||||
context.cmd.ClearRenderTarget(RTClearFlags.All, Color.black, 1.0f, 0);
|
context.cmd.ClearRenderTarget(RTClearFlags.All, Color.black, 1.0f, 0);
|
||||||
|
|
||||||
// Match context.DrawRenderers behavior
|
// 1. Draw character prepass
|
||||||
context.cmd.DrawRendererList(data.rendererList);
|
context.cmd.DrawRendererList(data.rendererList);
|
||||||
|
|
||||||
|
// 2. Draw fur shell mask (adds fur area to G and B channels)
|
||||||
|
if (data.enableFurMask)
|
||||||
|
{
|
||||||
|
context.cmd.DrawRendererList(data.furRendererList);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
566
Assets/NiloToonURP/Shaders/NiloToonCharacterFur.shader
Normal file
566
Assets/NiloToonURP/Shaders/NiloToonCharacterFur.shader
Normal file
@ -0,0 +1,566 @@
|
|||||||
|
// NiloToon Character Fur Shader
|
||||||
|
// Single-material fur shader with Base + Fur Shell rendering
|
||||||
|
// Requires NiloToonFurRendererFeature to be added to URP Renderer
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// 1. Add NiloToonFurRendererFeature to your URP Renderer Asset
|
||||||
|
// 2. Apply this shader to your mesh material (single material slot)
|
||||||
|
|
||||||
|
Shader "Universal Render Pipeline/NiloToon/NiloToon_Character_Fur"
|
||||||
|
{
|
||||||
|
Properties
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Base Color
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(Base Color)]
|
||||||
|
[Space(5)]
|
||||||
|
[MainTexture] _BaseMap("Base Map", 2D) = "white" {}
|
||||||
|
[HDR][MainColor] _BaseColor("Base Color", Color) = (1,1,1,1)
|
||||||
|
_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Normal Map
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(Normal Map)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_NORMALMAP)] _UseNormalMap("Enable Normal Map", Float) = 0
|
||||||
|
[Normal] _BumpMap("Normal Map", 2D) = "bump" {}
|
||||||
|
_BumpScale("Normal Scale", Range(0, 2)) = 1.0
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fur Settings
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(Fur Shape)]
|
||||||
|
[Space(5)]
|
||||||
|
_FurNoiseMask("Fur Noise Mask", 2D) = "white" {}
|
||||||
|
_FurMask("Fur Mask (where fur appears)", 2D) = "white" {}
|
||||||
|
_FurLengthMask("Fur Length Mask", 2D) = "white" {}
|
||||||
|
_FurVector("Fur Direction (XYZ) + Length (W)", Vector) = (0, 0, 1, 0.02)
|
||||||
|
[Normal] _FurVectorTex("Fur Direction Map (Normal)", 2D) = "bump" {}
|
||||||
|
_FurVectorScale("Fur Direction Scale", Range(-10, 10)) = 1.0
|
||||||
|
_FurGravity("Fur Gravity", Range(0, 1)) = 0.25
|
||||||
|
_FurRandomize("Fur Randomize", Range(0, 1)) = 0.1
|
||||||
|
_FurAO("Fur Ambient Occlusion", Range(0, 1)) = 0.5
|
||||||
|
|
||||||
|
[Header(Shell Layers)]
|
||||||
|
[Space(5)]
|
||||||
|
[IntRange] _FurLayerNum("Fur Layer Count", Range(1, 3)) = 2
|
||||||
|
_FurRootOffset("Fur Root Offset", Range(-1, 0)) = 0
|
||||||
|
|
||||||
|
[Header(Fur Rim Light)]
|
||||||
|
[Space(5)]
|
||||||
|
[HDR] _FurRimColor("Fur Rim Color", Color) = (1, 1, 1, 1)
|
||||||
|
_FurRimFresnelPower("Fur Rim Fresnel Power", Range(0.01, 50)) = 3.0
|
||||||
|
_FurRimAntiLight("Fur Rim Anti-Light", Range(0, 1)) = 0.5
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Toon Shading (NiloToon Style)
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(Cel Shading)]
|
||||||
|
[Space(5)]
|
||||||
|
_CelShadeMidPoint("Cel Shade Mid Point", Range(-1, 1)) = 0
|
||||||
|
_CelShadeSoftness("Cel Shade Softness", Range(0, 1)) = 0.1
|
||||||
|
|
||||||
|
[Header(Shadow Color)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_SHADOW_COLOR)] _EnableShadowColor("Enable Shadow Color", Float) = 0
|
||||||
|
[HDR] _ShadowColor("Shadow Tint Color", Color) = (1, 1, 1, 1)
|
||||||
|
_ShadowBrightness("Shadow Brightness", Range(0, 2)) = 1.0
|
||||||
|
|
||||||
|
[Header(HSV Adjustment in Shadow)]
|
||||||
|
[Space(5)]
|
||||||
|
_ShadowHueShift("Shadow Hue Shift", Range(-0.5, 0.5)) = 0
|
||||||
|
_ShadowSaturationBoost("Shadow Saturation Boost", Range(0, 2)) = 1.0
|
||||||
|
_ShadowValueMultiplier("Shadow Value Multiplier", Range(0, 2)) = 1.0
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MatCap
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(MatCap Additive)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_MATCAP_ADD)] _UseMatCapAdd("Enable MatCap (Add)", Float) = 0
|
||||||
|
_MatCapAddMap("MatCap Add Map", 2D) = "black" {}
|
||||||
|
[HDR] _MatCapAddColor("MatCap Add Color", Color) = (1, 1, 1, 1)
|
||||||
|
_MatCapAddIntensity("MatCap Add Intensity", Range(0, 5)) = 1.0
|
||||||
|
_MatCapAddMask("MatCap Add Mask", 2D) = "white" {}
|
||||||
|
|
||||||
|
[Header(MatCap Multiply)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_MATCAP_MUL)] _UseMatCapMul("Enable MatCap (Multiply)", Float) = 0
|
||||||
|
_MatCapMulMap("MatCap Multiply Map", 2D) = "white" {}
|
||||||
|
_MatCapMulIntensity("MatCap Multiply Intensity", Range(0, 2)) = 1.0
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Rim Light (General)
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(Rim Light)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_RIMLIGHT)] _UseRimLight("Enable Rim Light", Float) = 0
|
||||||
|
[HDR] _RimLightColor("Rim Light Color", Color) = (1, 1, 1, 1)
|
||||||
|
_RimLightPower("Rim Light Power", Range(0.01, 20)) = 5.0
|
||||||
|
_RimLightIntensity("Rim Light Intensity", Range(0, 5)) = 1.0
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Emission
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(Emission)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_EMISSION)] _UseEmission("Enable Emission", Float) = 0
|
||||||
|
_EmissionMap("Emission Map", 2D) = "white" {}
|
||||||
|
[HDR] _EmissionColor("Emission Color", Color) = (0, 0, 0, 1)
|
||||||
|
_EmissionIntensity("Emission Intensity", Range(0, 10)) = 1.0
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Occlusion
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(Occlusion)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_OCCLUSIONMAP)] _UseOcclusion("Enable Occlusion Map", Float) = 0
|
||||||
|
_OcclusionMap("Occlusion Map", 2D) = "white" {}
|
||||||
|
_OcclusionStrength("Occlusion Strength", Range(0, 1)) = 1.0
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Outline
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(Outline)]
|
||||||
|
[Space(5)]
|
||||||
|
_OutlineWidth("Outline Width", Range(0, 10)) = 1.0
|
||||||
|
[HDR] _OutlineColor("Outline Color", Color) = (0, 0, 0, 1)
|
||||||
|
_OutlineWidthMask("Outline Width Mask", 2D) = "white" {}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Rendering Options
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
[Header(Rendering Options)]
|
||||||
|
[Space(5)]
|
||||||
|
[Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull Mode", Float) = 2
|
||||||
|
[Enum(UnityEngine.Rendering.CullMode)] _FurCull("Fur Cull Mode", Float) = 0
|
||||||
|
[Enum(Off, 0, On, 1)] _ZWrite("ZWrite", Float) = 1
|
||||||
|
_FurZWrite("Fur ZWrite", Float) = 0
|
||||||
|
[Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", Float) = 4
|
||||||
|
|
||||||
|
// Hidden
|
||||||
|
[HideInInspector] _Surface("__surface", Float) = 0.0
|
||||||
|
[HideInInspector] _Blend("__blend", Float) = 0.0
|
||||||
|
[HideInInspector] _QueueOffset("Queue offset", Float) = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
SubShader
|
||||||
|
{
|
||||||
|
Tags
|
||||||
|
{
|
||||||
|
"RenderType" = "Opaque"
|
||||||
|
"RenderPipeline" = "UniversalPipeline"
|
||||||
|
"UniversalMaterialType" = "Lit"
|
||||||
|
"IgnoreProjector" = "True"
|
||||||
|
"Queue" = "Geometry"
|
||||||
|
}
|
||||||
|
LOD 300
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pass 0: ForwardLit - Base Surface (Full NiloToon Style)
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "ForwardLit"
|
||||||
|
Tags { "LightMode" = "UniversalForward" }
|
||||||
|
|
||||||
|
Cull [_Cull]
|
||||||
|
ZWrite On
|
||||||
|
ZTest LEqual
|
||||||
|
Blend One Zero
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
|
||||||
|
// Shader Features
|
||||||
|
#pragma shader_feature_local _NORMALMAP
|
||||||
|
#pragma shader_feature_local _SHADOW_COLOR
|
||||||
|
#pragma shader_feature_local _MATCAP_ADD
|
||||||
|
#pragma shader_feature_local _MATCAP_MUL
|
||||||
|
#pragma shader_feature_local _RIMLIGHT
|
||||||
|
#pragma shader_feature_local _EMISSION
|
||||||
|
#pragma shader_feature_local _OCCLUSIONMAP
|
||||||
|
|
||||||
|
// URP Keywords
|
||||||
|
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
|
||||||
|
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
|
||||||
|
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
|
||||||
|
#pragma multi_compile_fragment _ _SHADOWS_SOFT
|
||||||
|
#pragma multi_compile_fog
|
||||||
|
|
||||||
|
// GPU Instancing
|
||||||
|
#pragma multi_compile_instancing
|
||||||
|
#pragma instancing_options renderinglayer
|
||||||
|
|
||||||
|
#pragma vertex vert
|
||||||
|
#pragma fragment frag
|
||||||
|
|
||||||
|
#define NILOTOON_FUR_BASE_PASS
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Shared.hlsl"
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Fragment.hlsl"
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pass 1: Fur Shell Pass (Geometry Shader) - Standard single target
|
||||||
|
// Rendered by NiloToonFurRendererFeature via "NiloToonFurShell" LightMode
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "FurShell"
|
||||||
|
Tags { "LightMode" = "NiloToonFurShell" }
|
||||||
|
|
||||||
|
Cull [_FurCull]
|
||||||
|
ZWrite [_FurZWrite]
|
||||||
|
ZTest LEqual
|
||||||
|
Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
#pragma require geometry
|
||||||
|
|
||||||
|
// Shader Features
|
||||||
|
#pragma shader_feature_local _NORMALMAP
|
||||||
|
#pragma shader_feature_local _SHADOW_COLOR
|
||||||
|
#pragma shader_feature_local _MATCAP_ADD
|
||||||
|
#pragma shader_feature_local _MATCAP_MUL
|
||||||
|
#pragma shader_feature_local _RIMLIGHT
|
||||||
|
#pragma shader_feature_local _EMISSION
|
||||||
|
#pragma shader_feature_local _OCCLUSIONMAP
|
||||||
|
|
||||||
|
// URP Keywords
|
||||||
|
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
|
||||||
|
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
|
||||||
|
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
|
||||||
|
#pragma multi_compile_fragment _ _SHADOWS_SOFT
|
||||||
|
#pragma multi_compile_fog
|
||||||
|
|
||||||
|
// GPU Instancing
|
||||||
|
#pragma multi_compile_instancing
|
||||||
|
#pragma instancing_options renderinglayer
|
||||||
|
|
||||||
|
#pragma vertex vert_fur
|
||||||
|
#pragma geometry geom_fur
|
||||||
|
#pragma fragment frag_fur
|
||||||
|
|
||||||
|
#define NILOTOON_FUR_SHELL_PASS
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Shared.hlsl"
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Geometry.hlsl"
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Fragment.hlsl"
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pass 1.5: Fur Shell Mask Pass (Geometry Shader)
|
||||||
|
// Renders fur shells to mask buffer only (white where fur is rendered)
|
||||||
|
// Used for fur area detection in post-processing
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "FurShellMask"
|
||||||
|
Tags { "LightMode" = "NiloToonFurShellMask" }
|
||||||
|
|
||||||
|
Cull [_FurCull]
|
||||||
|
ZWrite Off
|
||||||
|
ZTest Always // Always pass - we want to mark ALL fur pixels regardless of depth
|
||||||
|
Blend One Zero // Just overwrite
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
#pragma require geometry
|
||||||
|
|
||||||
|
// GPU Instancing
|
||||||
|
#pragma multi_compile_instancing
|
||||||
|
#pragma instancing_options renderinglayer
|
||||||
|
|
||||||
|
#pragma vertex vert_fur
|
||||||
|
#pragma geometry geom_fur
|
||||||
|
#pragma fragment frag_fur_mask
|
||||||
|
|
||||||
|
#define NILOTOON_FUR_SHELL_PASS
|
||||||
|
#define NILOTOON_FUR_MASK_PASS
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Shared.hlsl"
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Geometry.hlsl"
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Fragment.hlsl"
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pass 2: Outline (NiloToon Style)
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "Outline"
|
||||||
|
Tags { "LightMode" = "NiloToonOutline" }
|
||||||
|
|
||||||
|
Cull Front
|
||||||
|
ZWrite [_ZWrite]
|
||||||
|
ZTest [_ZTest]
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
|
||||||
|
#pragma multi_compile_instancing
|
||||||
|
#pragma instancing_options renderinglayer
|
||||||
|
#pragma multi_compile_fog
|
||||||
|
|
||||||
|
#pragma vertex vert_outline
|
||||||
|
#pragma fragment frag_outline
|
||||||
|
|
||||||
|
#define NILOTOON_FUR_OUTLINE_PASS
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Shared.hlsl"
|
||||||
|
|
||||||
|
Varyings vert_outline(Attributes input)
|
||||||
|
{
|
||||||
|
Varyings output = (Varyings)0;
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
||||||
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
||||||
|
|
||||||
|
float outlineWidth = _OutlineWidth * 0.001;
|
||||||
|
float outlineMask = SAMPLE_TEXTURE2D_LOD(_OutlineWidthMask, sampler_OutlineWidthMask, input.uv, 0).r;
|
||||||
|
outlineWidth *= outlineMask;
|
||||||
|
|
||||||
|
// FOV-aware outline width
|
||||||
|
float fovFactor = unity_OrthoParams.w > 0.5 ? 1.0 : (2.0 * abs(UNITY_MATRIX_P[1][1]));
|
||||||
|
outlineWidth *= fovFactor;
|
||||||
|
|
||||||
|
float3 posOS = input.positionOS.xyz + input.normalOS * outlineWidth;
|
||||||
|
output.positionCS = TransformObjectToHClip(posOS);
|
||||||
|
output.uv = input.uv;
|
||||||
|
output.fogFactor = ComputeFogFactor(output.positionCS.z);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
half4 frag_outline(Varyings input) : SV_Target
|
||||||
|
{
|
||||||
|
half4 color = _OutlineColor;
|
||||||
|
color.rgb = MixFog(color.rgb, input.fogFactor);
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pass 3: ShadowCaster
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "ShadowCaster"
|
||||||
|
Tags { "LightMode" = "ShadowCaster" }
|
||||||
|
|
||||||
|
ZWrite On
|
||||||
|
ZTest LEqual
|
||||||
|
ColorMask 0
|
||||||
|
Cull [_Cull]
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
|
||||||
|
#pragma multi_compile_instancing
|
||||||
|
#pragma instancing_options renderinglayer
|
||||||
|
|
||||||
|
#pragma vertex ShadowPassVertex
|
||||||
|
#pragma fragment ShadowPassFragment
|
||||||
|
|
||||||
|
#define NILOTOON_FUR_SHADOW_PASS
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Shared.hlsl"
|
||||||
|
|
||||||
|
float3 _LightDirection;
|
||||||
|
float3 _LightPosition;
|
||||||
|
|
||||||
|
float4 GetShadowPositionHClip(Attributes input)
|
||||||
|
{
|
||||||
|
float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
|
||||||
|
float3 normalWS = TransformObjectToWorldNormal(input.normalOS);
|
||||||
|
|
||||||
|
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
|
||||||
|
float3 lightDirectionWS = normalize(_LightPosition - positionWS);
|
||||||
|
#else
|
||||||
|
float3 lightDirectionWS = _LightDirection;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS));
|
||||||
|
|
||||||
|
#if UNITY_REVERSED_Z
|
||||||
|
positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE);
|
||||||
|
#else
|
||||||
|
positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return positionCS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Varyings ShadowPassVertex(Attributes input)
|
||||||
|
{
|
||||||
|
Varyings output = (Varyings)0;
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
||||||
|
|
||||||
|
output.uv = input.uv;
|
||||||
|
output.positionCS = GetShadowPositionHClip(input);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
half4 ShadowPassFragment(Varyings input) : SV_TARGET
|
||||||
|
{
|
||||||
|
half alpha = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv).a * _BaseColor.a;
|
||||||
|
clip(alpha - _Cutoff);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pass 4: DepthOnly
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "DepthOnly"
|
||||||
|
Tags { "LightMode" = "DepthOnly" }
|
||||||
|
|
||||||
|
ZWrite On
|
||||||
|
ColorMask R
|
||||||
|
Cull [_Cull]
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
|
||||||
|
#pragma multi_compile_instancing
|
||||||
|
#pragma instancing_options renderinglayer
|
||||||
|
|
||||||
|
#pragma vertex DepthOnlyVertex
|
||||||
|
#pragma fragment DepthOnlyFragment
|
||||||
|
|
||||||
|
#define NILOTOON_FUR_DEPTH_PASS
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Shared.hlsl"
|
||||||
|
|
||||||
|
Varyings DepthOnlyVertex(Attributes input)
|
||||||
|
{
|
||||||
|
Varyings output = (Varyings)0;
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
||||||
|
|
||||||
|
output.uv = input.uv;
|
||||||
|
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
half DepthOnlyFragment(Varyings input) : SV_TARGET
|
||||||
|
{
|
||||||
|
half alpha = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv).a * _BaseColor.a;
|
||||||
|
clip(alpha - _Cutoff);
|
||||||
|
return input.positionCS.z;
|
||||||
|
}
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pass 5: DepthNormals
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "DepthNormals"
|
||||||
|
Tags { "LightMode" = "DepthNormals" }
|
||||||
|
|
||||||
|
ZWrite On
|
||||||
|
Cull [_Cull]
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
|
||||||
|
#pragma multi_compile_instancing
|
||||||
|
#pragma instancing_options renderinglayer
|
||||||
|
|
||||||
|
#pragma vertex DepthNormalsVertex
|
||||||
|
#pragma fragment DepthNormalsFragment
|
||||||
|
|
||||||
|
#define NILOTOON_FUR_DEPTHNORMALS_PASS
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Shared.hlsl"
|
||||||
|
|
||||||
|
Varyings DepthNormalsVertex(Attributes input)
|
||||||
|
{
|
||||||
|
Varyings output = (Varyings)0;
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
||||||
|
|
||||||
|
output.uv = input.uv;
|
||||||
|
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
|
||||||
|
output.normalWS = TransformObjectToWorldNormal(input.normalOS);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 DepthNormalsFragment(Varyings input) : SV_TARGET
|
||||||
|
{
|
||||||
|
half alpha = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv).a * _BaseColor.a;
|
||||||
|
clip(alpha - _Cutoff);
|
||||||
|
return float4(normalize(input.normalWS) * 0.5 + 0.5, 0);
|
||||||
|
}
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Pass 6: NiloToonPrepassBuffer (Base mesh only)
|
||||||
|
// For NiloToon Bloom / Tonemapping character area detection - base mesh
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "NiloToonPrepassBuffer"
|
||||||
|
Tags { "LightMode" = "NiloToonPrepassBuffer" }
|
||||||
|
|
||||||
|
ZWrite On
|
||||||
|
ZTest LEqual
|
||||||
|
Cull [_Cull]
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
|
||||||
|
#pragma multi_compile_instancing
|
||||||
|
#pragma instancing_options renderinglayer
|
||||||
|
|
||||||
|
#pragma vertex PrepassBufferVertexBase
|
||||||
|
#pragma fragment PrepassBufferFragmentBase
|
||||||
|
|
||||||
|
#define NILOTOON_FUR_PREPASSBUFFER_PASS
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Shared.hlsl"
|
||||||
|
|
||||||
|
Varyings PrepassBufferVertexBase(Attributes input)
|
||||||
|
{
|
||||||
|
Varyings output = (Varyings)0;
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
||||||
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
||||||
|
|
||||||
|
output.uv = input.uv;
|
||||||
|
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
|
||||||
|
output.furLayer = -1; // Base mesh marker
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 PrepassBufferFragmentBase(Varyings input) : SV_TARGET
|
||||||
|
{
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
||||||
|
|
||||||
|
// Base mesh alpha clip
|
||||||
|
half alpha = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv).a * _BaseColor.a;
|
||||||
|
clip(alpha - _Cutoff);
|
||||||
|
|
||||||
|
// Output: character visible area = 1
|
||||||
|
return float4(0, 1, 0, 1);
|
||||||
|
}
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: Fur shell prepass is handled via MRT in the FurShellMRT pass
|
||||||
|
// When WriteToPrepassBuffer is enabled, FurShellMRT outputs to both:
|
||||||
|
// - SV_Target0: Main color buffer
|
||||||
|
// - SV_Target1: PrepassBuffer (character mask with jagged fur silhouette)
|
||||||
|
}
|
||||||
|
|
||||||
|
FallBack "Universal Render Pipeline/Lit"
|
||||||
|
CustomEditor "NiloToonURP.ShaderGUI.NiloToonCharacterFurShaderGUI"
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d65d4a470e01cd947a07483a9bf34206
|
||||||
|
ShaderImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
defaultTextures: []
|
||||||
|
nonModifiableTextures: []
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 721b8d7aa96ce3243ad6e988775df5ee
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,333 @@
|
|||||||
|
// NiloToon Character Fur - Fragment Shader
|
||||||
|
// Full-featured NiloToon style cel shading + Fur specific effects
|
||||||
|
|
||||||
|
#ifndef NILOTOON_CHARACTER_FUR_FRAGMENT_INCLUDED
|
||||||
|
#define NILOTOON_CHARACTER_FUR_FRAGMENT_INCLUDED
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Get Normal from Normal Map
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
half3 GetNormalFromMap(float2 uv, float3 normalWS, float4 tangentWS)
|
||||||
|
{
|
||||||
|
#if defined(_NORMALMAP)
|
||||||
|
half4 normalMap = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, uv);
|
||||||
|
half3 normalTS = UnpackNormalWithScale(normalMap, _BumpScale);
|
||||||
|
|
||||||
|
float3 bitangent = cross(normalWS, tangentWS.xyz) * tangentWS.w;
|
||||||
|
float3x3 TBN = float3x3(tangentWS.xyz, bitangent, normalWS);
|
||||||
|
|
||||||
|
return normalize(mul(normalTS, TBN));
|
||||||
|
#else
|
||||||
|
return normalize(normalWS);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Apply All Effects (MatCap, Rim, Emission)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
half3 ApplyEffects(
|
||||||
|
half3 color,
|
||||||
|
float2 uv,
|
||||||
|
float3 normalWS,
|
||||||
|
float3 viewDirWS,
|
||||||
|
half3 lightColor,
|
||||||
|
half furLayer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// MatCap UV
|
||||||
|
float2 matCapUV = GetMatCapUV(normalWS, viewDirWS);
|
||||||
|
|
||||||
|
// MatCap Additive
|
||||||
|
#if defined(_MATCAP_ADD)
|
||||||
|
half matCapAddMask = SAMPLE_TEXTURE2D(_MatCapAddMask, sampler_MatCapAddMask, uv).r;
|
||||||
|
half3 matCapAdd = SAMPLE_TEXTURE2D(_MatCapAddMap, sampler_MatCapAddMap, matCapUV).rgb;
|
||||||
|
matCapAdd *= _MatCapAddColor.rgb * _MatCapAddIntensity * matCapAddMask;
|
||||||
|
color += matCapAdd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// MatCap Multiply
|
||||||
|
#if defined(_MATCAP_MUL)
|
||||||
|
half3 matCapMul = SAMPLE_TEXTURE2D(_MatCapMulMap, sampler_MatCapMulMap, matCapUV).rgb;
|
||||||
|
color *= lerp(half3(1, 1, 1), matCapMul, _MatCapMulIntensity);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Rim Light (General) - not applied to fur shells to avoid double rim
|
||||||
|
#if defined(_RIMLIGHT)
|
||||||
|
if (furLayer < 0) // Only for base pass
|
||||||
|
{
|
||||||
|
half NdotV = saturate(dot(normalWS, viewDirWS));
|
||||||
|
half rim = pow(1.0 - NdotV, _RimLightPower);
|
||||||
|
color += rim * _RimLightColor.rgb * _RimLightIntensity * lightColor;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Emission
|
||||||
|
#if defined(_EMISSION)
|
||||||
|
half3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, uv).rgb;
|
||||||
|
emission *= _EmissionColor.rgb * _EmissionIntensity;
|
||||||
|
color += emission;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Base Pass Fragment Shader
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
#if defined(NILOTOON_FUR_BASE_PASS)
|
||||||
|
half4 frag(Varyings input) : SV_Target
|
||||||
|
{
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
||||||
|
|
||||||
|
// Sample base texture
|
||||||
|
half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
|
||||||
|
half4 color = baseMap * _BaseColor;
|
||||||
|
|
||||||
|
// Alpha cutoff
|
||||||
|
clip(color.a - _Cutoff);
|
||||||
|
|
||||||
|
// Get normal (with normal map if enabled)
|
||||||
|
float3 normalWS = GetNormalFromMap(input.uv, input.normalWS, input.tangentWS);
|
||||||
|
|
||||||
|
// Get view direction
|
||||||
|
float3 viewDirWS = GetWorldSpaceViewDirSafe(input.positionWS);
|
||||||
|
|
||||||
|
// Get main light with NiloToon override support
|
||||||
|
Light mainLight = GetMainLightWithNiloToonOverride();
|
||||||
|
|
||||||
|
// Try to get shadow attenuation if shadow coord is valid
|
||||||
|
half shadowAttenuation = 1.0;
|
||||||
|
#if defined(_MAIN_LIGHT_SHADOWS) || defined(_MAIN_LIGHT_SHADOWS_CASCADE) || defined(_MAIN_LIGHT_SHADOWS_SCREEN)
|
||||||
|
shadowAttenuation = MainLightRealtimeShadow(input.shadowCoord);
|
||||||
|
#endif
|
||||||
|
mainLight.shadowAttenuation = shadowAttenuation;
|
||||||
|
|
||||||
|
// Occlusion
|
||||||
|
half occlusion = 1.0;
|
||||||
|
#if defined(_OCCLUSIONMAP)
|
||||||
|
occlusion = lerp(1.0, SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, input.uv).r, _OcclusionStrength);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Apply NiloToon cel shading
|
||||||
|
color.rgb = ApplyNiloToonCelShading(
|
||||||
|
color.rgb,
|
||||||
|
mainLight.color,
|
||||||
|
mainLight.direction,
|
||||||
|
normalWS,
|
||||||
|
viewDirWS,
|
||||||
|
shadowAttenuation,
|
||||||
|
occlusion
|
||||||
|
);
|
||||||
|
|
||||||
|
// Apply additional effects
|
||||||
|
color.rgb = ApplyEffects(color.rgb, input.uv, normalWS, viewDirWS, mainLight.color, input.furLayer);
|
||||||
|
|
||||||
|
// Apply fog
|
||||||
|
color.rgb = MixFog(color.rgb, input.fogFactor);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Fur Shell Pass Fragment Shader
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
#if defined(NILOTOON_FUR_SHELL_PASS)
|
||||||
|
|
||||||
|
// MRT output structure for simultaneous color + prepass buffer rendering
|
||||||
|
struct FurMRTOutput
|
||||||
|
{
|
||||||
|
half4 color : SV_Target0; // Main color buffer
|
||||||
|
half4 prepass : SV_Target1; // PrepassBuffer (character mask)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal function to compute fur color (shared between standard and MRT versions)
|
||||||
|
half4 ComputeFurColor(Varyings input, out half furAlpha)
|
||||||
|
{
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
||||||
|
|
||||||
|
// Sample base texture
|
||||||
|
half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
|
||||||
|
half4 color = baseMap * _BaseColor;
|
||||||
|
|
||||||
|
// Get main light with NiloToon override support
|
||||||
|
Light mainLight = GetMainLightWithNiloToonOverride();
|
||||||
|
half3 lightColor = mainLight.color;
|
||||||
|
half3 lightDir = mainLight.direction;
|
||||||
|
|
||||||
|
// Sample fur noise mask for alpha (default white = full fur)
|
||||||
|
float2 furNoiseUV = input.uv * _FurNoiseMask_ST.xy + _FurNoiseMask_ST.zw;
|
||||||
|
half furNoise = SAMPLE_TEXTURE2D(_FurNoiseMask, sampler_FurNoiseMask, furNoiseUV).r;
|
||||||
|
|
||||||
|
// Sample fur mask (where fur appears, default white = everywhere)
|
||||||
|
float2 furMaskUV = input.uv * _FurMask_ST.xy + _FurMask_ST.zw;
|
||||||
|
half furMask = SAMPLE_TEXTURE2D(_FurMask, sampler_FurMask, furMaskUV).r;
|
||||||
|
|
||||||
|
// furLayer: 0 = root/base, 1 = tip
|
||||||
|
half furLayer = saturate(input.furLayer);
|
||||||
|
|
||||||
|
// Calculate fur alpha using lilToon-style non-linear curve
|
||||||
|
// This creates natural-looking fur tips instead of obvious hair cards
|
||||||
|
|
||||||
|
// furLayerShift with root offset adjustment (lilToon style)
|
||||||
|
// _FurRootOffset range is -1 to 0: -1 = hide roots completely, 0 = show all
|
||||||
|
half furLayerShift = furLayer - furLayer * _FurRootOffset + _FurRootOffset;
|
||||||
|
half furLayerAbs = abs(furLayerShift);
|
||||||
|
|
||||||
|
// Non-linear alpha curve: creates sharp tip cutoff
|
||||||
|
// Using cubic falloff for natural-looking fur tips
|
||||||
|
furAlpha = saturate(furNoise - furLayerShift * furLayerAbs * furLayerAbs * furLayerAbs + 0.25);
|
||||||
|
|
||||||
|
// Apply fur mask
|
||||||
|
furAlpha *= furMask;
|
||||||
|
|
||||||
|
// Minimum alpha threshold
|
||||||
|
clip(furAlpha - 0.05);
|
||||||
|
|
||||||
|
// Get normal (with normal map if enabled)
|
||||||
|
float3 normalWS = GetNormalFromMap(input.uv, input.normalWS, input.tangentWS);
|
||||||
|
|
||||||
|
// Get view direction
|
||||||
|
float3 viewDirWS = GetWorldSpaceViewDirSafe(input.positionWS);
|
||||||
|
|
||||||
|
// Occlusion
|
||||||
|
half occlusion = 1.0;
|
||||||
|
#if defined(_OCCLUSIONMAP)
|
||||||
|
occlusion = lerp(1.0, SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, input.uv).r, _OcclusionStrength);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Cel shading
|
||||||
|
half NdotL = dot(normalWS, lightDir);
|
||||||
|
half halfLambert = NdotL * 0.5 + 0.5;
|
||||||
|
half celShadeResult = smoothstep(
|
||||||
|
_CelShadeMidPoint + 0.5 - _CelShadeSoftness,
|
||||||
|
_CelShadeMidPoint + 0.5 + _CelShadeSoftness,
|
||||||
|
halfLambert
|
||||||
|
);
|
||||||
|
|
||||||
|
celShadeResult *= occlusion;
|
||||||
|
|
||||||
|
#if defined(_SHADOW_COLOR)
|
||||||
|
// Apply HSV adjustment to shadow
|
||||||
|
half3 shadowAlbedo = ApplyHSVChange(
|
||||||
|
color.rgb,
|
||||||
|
_ShadowHueShift,
|
||||||
|
_ShadowSaturationBoost,
|
||||||
|
_ShadowValueMultiplier
|
||||||
|
);
|
||||||
|
shadowAlbedo *= _ShadowColor.rgb * _ShadowBrightness;
|
||||||
|
color.rgb = lerp(shadowAlbedo, color.rgb, celShadeResult);
|
||||||
|
#else
|
||||||
|
color.rgb = lerp(color.rgb * 0.5, color.rgb, celShadeResult);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Apply light color
|
||||||
|
color.rgb *= lightColor;
|
||||||
|
|
||||||
|
// Apply fur ambient occlusion (lilToon style)
|
||||||
|
// Uses fwidth to reduce aliasing at layer boundaries
|
||||||
|
half furAOFactor = _FurAO * saturate(1.0 - fwidth(input.furLayer));
|
||||||
|
color.rgb *= furLayer * furAOFactor * 2.0 + 1.0 - furAOFactor;
|
||||||
|
|
||||||
|
// Apply fur rim lighting
|
||||||
|
half NdotV = abs(dot(normalWS, viewDirWS));
|
||||||
|
half rimFresnel = pow(saturate(1.0 - NdotV), _FurRimFresnelPower);
|
||||||
|
half antiLightFactor = lerp(1.0, 1.0 - Grayscale(lightColor), _FurRimAntiLight);
|
||||||
|
half3 rimColor = furLayer * rimFresnel * antiLightFactor * _FurRimColor.rgb;
|
||||||
|
color.rgb += rimColor;
|
||||||
|
|
||||||
|
// Apply additional effects (MatCap, Emission)
|
||||||
|
// MatCap UV
|
||||||
|
float2 matCapUV = GetMatCapUV(normalWS, viewDirWS);
|
||||||
|
|
||||||
|
#if defined(_MATCAP_ADD)
|
||||||
|
half matCapAddMask = SAMPLE_TEXTURE2D(_MatCapAddMask, sampler_MatCapAddMask, input.uv).r;
|
||||||
|
half3 matCapAdd = SAMPLE_TEXTURE2D(_MatCapAddMap, sampler_MatCapAddMap, matCapUV).rgb;
|
||||||
|
matCapAdd *= _MatCapAddColor.rgb * _MatCapAddIntensity * matCapAddMask * (1.0 - furLayer * 0.5);
|
||||||
|
color.rgb += matCapAdd;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MATCAP_MUL)
|
||||||
|
half3 matCapMul = SAMPLE_TEXTURE2D(_MatCapMulMap, sampler_MatCapMulMap, matCapUV).rgb;
|
||||||
|
color.rgb *= lerp(half3(1, 1, 1), matCapMul, _MatCapMulIntensity * (1.0 - furLayer * 0.5));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_EMISSION)
|
||||||
|
half3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, input.uv).rgb;
|
||||||
|
emission *= _EmissionColor.rgb * _EmissionIntensity * (1.0 - furLayer * 0.5);
|
||||||
|
color.rgb += emission;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Apply fog
|
||||||
|
color.rgb = MixFog(color.rgb, input.fogFactor);
|
||||||
|
|
||||||
|
// Final alpha
|
||||||
|
color.a = furAlpha;
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard single render target version
|
||||||
|
half4 frag_fur(Varyings input) : SV_Target
|
||||||
|
{
|
||||||
|
half furAlpha;
|
||||||
|
return ComputeFurColor(input, furAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MRT version: outputs to both color buffer and Fur Mask buffer simultaneously
|
||||||
|
// This creates the jagged mask effect where only actual rendered fur pixels are marked
|
||||||
|
FurMRTOutput frag_fur_mrt(Varyings input)
|
||||||
|
{
|
||||||
|
FurMRTOutput output;
|
||||||
|
|
||||||
|
half furAlpha;
|
||||||
|
output.color = ComputeFurColor(input, furAlpha);
|
||||||
|
|
||||||
|
// Write to Fur Mask Buffer (_NiloToonFurMaskTex):
|
||||||
|
// Write white (1,1,1,1) where fur pixels are rendered
|
||||||
|
// This creates a mask that shows exactly where fur is visible
|
||||||
|
output.prepass = half4(1, 1, 1, 1);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask-only version: outputs to PrepassBuffer format
|
||||||
|
// R: face (not used by fur), G: character area (fur adds here), B: fur area only
|
||||||
|
// Used for two-pass approach (more compatible than MRT)
|
||||||
|
half4 frag_fur_mask(Varyings input) : SV_Target
|
||||||
|
{
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
||||||
|
|
||||||
|
// Sample fur noise mask for alpha (default white = full fur)
|
||||||
|
float2 furNoiseUV = input.uv * _FurNoiseMask_ST.xy + _FurNoiseMask_ST.zw;
|
||||||
|
half furNoise = SAMPLE_TEXTURE2D(_FurNoiseMask, sampler_FurNoiseMask, furNoiseUV).r;
|
||||||
|
|
||||||
|
// Sample fur mask (where fur appears, default white = everywhere)
|
||||||
|
float2 furMaskUV = input.uv * _FurMask_ST.xy + _FurMask_ST.zw;
|
||||||
|
half furMask = SAMPLE_TEXTURE2D(_FurMask, sampler_FurMask, furMaskUV).r;
|
||||||
|
|
||||||
|
// furLayer: 0 = root/base, 1 = tip
|
||||||
|
half furLayer = saturate(input.furLayer);
|
||||||
|
|
||||||
|
// Calculate fur alpha using lilToon-style non-linear curve
|
||||||
|
half furLayerShift = furLayer - furLayer * _FurRootOffset + _FurRootOffset;
|
||||||
|
half furLayerAbs = abs(furLayerShift);
|
||||||
|
half furAlpha = saturate(furNoise - furLayerShift * furLayerAbs * furLayerAbs * furLayerAbs + 0.25);
|
||||||
|
|
||||||
|
// Apply fur mask
|
||||||
|
furAlpha *= furMask;
|
||||||
|
|
||||||
|
// Clip pixels that don't pass threshold (same as main fur rendering)
|
||||||
|
clip(furAlpha - 0.05);
|
||||||
|
|
||||||
|
// Output to PrepassBuffer format:
|
||||||
|
// G channel = character visible area (unified mask for face, body, and fur)
|
||||||
|
// All character areas use G channel for consistent masking
|
||||||
|
return half4(0, 1, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NILOTOON_CHARACTER_FUR_FRAGMENT_INCLUDED
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 734309d3fd8d31246bde14f3278d4ee3
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,149 @@
|
|||||||
|
// NiloToon Character Fur - Geometry Shader
|
||||||
|
// Shell-based fur generation (based on lilToon implementation)
|
||||||
|
|
||||||
|
#ifndef NILOTOON_CHARACTER_FUR_GEOMETRY_INCLUDED
|
||||||
|
#define NILOTOON_CHARACTER_FUR_GEOMETRY_INCLUDED
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Barycentric Interpolation Helper
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
float LerpBary(float a, float b, float c, float3 factor) { return a * factor.x + b * factor.y + c * factor.z; }
|
||||||
|
float2 LerpBary(float2 a, float2 b, float2 c, float3 factor) { return a * factor.x + b * factor.y + c * factor.z; }
|
||||||
|
float3 LerpBary(float3 a, float3 b, float3 c, float3 factor) { return a * factor.x + b * factor.y + c * factor.z; }
|
||||||
|
float4 LerpBary(float4 a, float4 b, float4 c, float3 factor) { return a * factor.x + b * factor.y + c * factor.z; }
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Append Single Fur Shell (Base + Tip)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
void AppendFurShell(
|
||||||
|
inout TriangleStream<Varyings> outStream,
|
||||||
|
V2G input[3],
|
||||||
|
float3 furVectors[3],
|
||||||
|
float3 factor,
|
||||||
|
float layerProgress // 0 = base, 1 = outer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Varyings output = (Varyings)0;
|
||||||
|
|
||||||
|
UNITY_TRANSFER_INSTANCE_ID(input[0], output);
|
||||||
|
UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input[0], output);
|
||||||
|
|
||||||
|
// Interpolate base attributes
|
||||||
|
output.uv = LerpBary(input[0].uv, input[1].uv, input[2].uv, factor);
|
||||||
|
output.normalWS = normalize(LerpBary(input[0].normalWS, input[1].normalWS, input[2].normalWS, factor));
|
||||||
|
output.tangentWS = LerpBary(input[0].tangentWS, input[1].tangentWS, input[2].tangentWS, factor);
|
||||||
|
output.tangentWS.xyz = normalize(output.tangentWS.xyz);
|
||||||
|
output.fogFactor = LerpBary(input[0].fogFactor, input[1].fogFactor, input[2].fogFactor, factor);
|
||||||
|
|
||||||
|
// Base position (furLayer = 0)
|
||||||
|
float3 basePositionWS = LerpBary(input[0].positionWS, input[1].positionWS, input[2].positionWS, factor);
|
||||||
|
|
||||||
|
output.positionWS = basePositionWS;
|
||||||
|
output.positionCS = TransformWorldToHClip(basePositionWS);
|
||||||
|
output.furLayer = 0;
|
||||||
|
|
||||||
|
// Clipping canceller for near plane
|
||||||
|
#if defined(UNITY_REVERSED_Z)
|
||||||
|
if(output.positionCS.w < _ProjectionParams.y * 1.01 && output.positionCS.w > 0)
|
||||||
|
{
|
||||||
|
output.positionCS.z = output.positionCS.z * 0.0001 + output.positionCS.w * 0.999;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if(output.positionCS.w < _ProjectionParams.y * 1.01 && output.positionCS.w > 0)
|
||||||
|
{
|
||||||
|
output.positionCS.z = output.positionCS.z * 0.0001 - output.positionCS.w * 0.999;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
outStream.Append(output);
|
||||||
|
|
||||||
|
// Tip position (furLayer = 1)
|
||||||
|
float3 mixedFurVector = LerpBary(furVectors[0], furVectors[1], furVectors[2], factor);
|
||||||
|
float3 tipPositionWS = basePositionWS + mixedFurVector;
|
||||||
|
|
||||||
|
output.positionWS = tipPositionWS;
|
||||||
|
output.positionCS = TransformWorldToHClip(tipPositionWS);
|
||||||
|
output.furLayer = layerProgress;
|
||||||
|
|
||||||
|
// Clipping canceller for near plane
|
||||||
|
#if defined(UNITY_REVERSED_Z)
|
||||||
|
if(output.positionCS.w < _ProjectionParams.y * 1.01 && output.positionCS.w > 0)
|
||||||
|
{
|
||||||
|
output.positionCS.z = output.positionCS.z * 0.0001 + output.positionCS.w * 0.999;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if(output.positionCS.w < _ProjectionParams.y * 1.01 && output.positionCS.w > 0)
|
||||||
|
{
|
||||||
|
output.positionCS.z = output.positionCS.z * 0.0001 - output.positionCS.w * 0.999;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
outStream.Append(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Geometry Shader - Shell Generation
|
||||||
|
// Based on lilToon's fur geometry shader
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
[maxvertexcount(40)]
|
||||||
|
void geom_fur(triangle V2G input[3], inout TriangleStream<Varyings> outStream)
|
||||||
|
{
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input[0]);
|
||||||
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input[0]);
|
||||||
|
|
||||||
|
// Get fur vectors for each vertex
|
||||||
|
float3 furVectors[3];
|
||||||
|
furVectors[0] = input[0].furVector;
|
||||||
|
furVectors[1] = input[1].furVector;
|
||||||
|
furVectors[2] = input[2].furVector;
|
||||||
|
|
||||||
|
// Apply procedural randomization using vertex IDs (from lilToon)
|
||||||
|
uint3 n0 = (input[0].vertexID * 3 + input[1].vertexID * 1 + input[2].vertexID * 1) * uint3(1597334677U, 3812015801U, 2912667907U);
|
||||||
|
uint3 n1 = (input[0].vertexID * 1 + input[1].vertexID * 3 + input[2].vertexID * 1) * uint3(1597334677U, 3812015801U, 2912667907U);
|
||||||
|
uint3 n2 = (input[0].vertexID * 1 + input[1].vertexID * 1 + input[2].vertexID * 3) * uint3(1597334677U, 3812015801U, 2912667907U);
|
||||||
|
|
||||||
|
float3 noise0 = normalize(float3(n0) * (2.0 / float(0xffffffffU)) - 1.0);
|
||||||
|
float3 noise1 = normalize(float3(n1) * (2.0 / float(0xffffffffU)) - 1.0);
|
||||||
|
float3 noise2 = normalize(float3(n2) * (2.0 / float(0xffffffffU)) - 1.0);
|
||||||
|
|
||||||
|
furVectors[0] += noise0 * _FurVector.w * _FurRandomize;
|
||||||
|
furVectors[1] += noise1 * _FurVector.w * _FurRandomize;
|
||||||
|
furVectors[2] += noise2 * _FurVector.w * _FurRandomize;
|
||||||
|
|
||||||
|
// Generate shells based on layer count
|
||||||
|
// Layer pattern from lilToon: spreads shells across triangle vertices
|
||||||
|
|
||||||
|
if (_FurLayerNum >= 1)
|
||||||
|
{
|
||||||
|
// 3 shells at each vertex
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(1.0, 0.0, 0.0), 1.0);
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(0.0, 1.0, 0.0), 1.0);
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(0.0, 0.0, 1.0), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_FurLayerNum >= 2)
|
||||||
|
{
|
||||||
|
// 3 more shells at edge midpoints
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(0.0, 0.5, 0.5), 1.0);
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(0.5, 0.0, 0.5), 1.0);
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(0.5, 0.5, 0.0), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_FurLayerNum >= 3)
|
||||||
|
{
|
||||||
|
// 6 more shells for dense fur
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(1.0/6.0, 4.0/6.0, 1.0/6.0), 1.0);
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(0.0, 0.5, 0.5), 0.8);
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(1.0/6.0, 1.0/6.0, 4.0/6.0), 1.0);
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(0.5, 0.0, 0.5), 0.8);
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(4.0/6.0, 1.0/6.0, 1.0/6.0), 1.0);
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(0.5, 0.5, 0.0), 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final shell at first vertex to close the strip
|
||||||
|
AppendFurShell(outStream, input, furVectors, float3(1.0, 0.0, 0.0), 1.0);
|
||||||
|
|
||||||
|
outStream.RestartStrip();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NILOTOON_CHARACTER_FUR_GEOMETRY_INCLUDED
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 130ac8fd23814be49854157d7be9194e
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,440 @@
|
|||||||
|
// NiloToon Character Fur - Shared Definitions
|
||||||
|
// Full-featured structs, CBUFFER, and common functions
|
||||||
|
|
||||||
|
#ifndef NILOTOON_CHARACTER_FUR_SHARED_INCLUDED
|
||||||
|
#define NILOTOON_CHARACTER_FUR_SHARED_INCLUDED
|
||||||
|
|
||||||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
||||||
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// NiloToon Global Light Override Variables (from NiloToonCharacterMainLightOverrider)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
half4 _GlobalUserOverriddenFinalMainLightDirWSParam; // xyz: direction, w: 1 if enabled
|
||||||
|
half4 _GlobalUserOverriddenFinalMainLightColorParam; // rgb: color, w: 1 if enabled
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Helper function for view direction (compatible with all URP versions)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
float3 GetWorldSpaceViewDirSafe(float3 positionWS)
|
||||||
|
{
|
||||||
|
return normalize(_WorldSpaceCameraPos.xyz - positionWS);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Helper function for shadow coord (compatible with all URP versions)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
float4 GetShadowCoordSafe(VertexPositionInputs vertexInput)
|
||||||
|
{
|
||||||
|
#if defined(_MAIN_LIGHT_SHADOWS_SCREEN) && !defined(_SURFACE_TYPE_TRANSPARENT)
|
||||||
|
return ComputeScreenPos(vertexInput.positionCS);
|
||||||
|
#else
|
||||||
|
return TransformWorldToShadowCoord(vertexInput.positionWS);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Get Main Light with NiloToon Override Support
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
Light GetMainLightWithNiloToonOverride()
|
||||||
|
{
|
||||||
|
Light mainLight = GetMainLight();
|
||||||
|
|
||||||
|
// Apply NiloToon MainLightOverrider if enabled
|
||||||
|
if (_GlobalUserOverriddenFinalMainLightDirWSParam.w > 0.5)
|
||||||
|
{
|
||||||
|
mainLight.direction = _GlobalUserOverriddenFinalMainLightDirWSParam.xyz;
|
||||||
|
}
|
||||||
|
if (_GlobalUserOverriddenFinalMainLightColorParam.w > 0.5)
|
||||||
|
{
|
||||||
|
mainLight.color = _GlobalUserOverriddenFinalMainLightColorParam.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mainLight;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// CBUFFER for SRP Batcher
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
CBUFFER_START(UnityPerMaterial)
|
||||||
|
// Base
|
||||||
|
float4 _BaseMap_ST;
|
||||||
|
half4 _BaseColor;
|
||||||
|
half _Cutoff;
|
||||||
|
|
||||||
|
// Normal Map
|
||||||
|
float4 _BumpMap_ST;
|
||||||
|
half _BumpScale;
|
||||||
|
|
||||||
|
// Fur Shape
|
||||||
|
float4 _FurNoiseMask_ST;
|
||||||
|
float4 _FurMask_ST;
|
||||||
|
float4 _FurLengthMask_ST;
|
||||||
|
float4 _FurVector;
|
||||||
|
float4 _FurVectorTex_ST;
|
||||||
|
half _FurVectorScale;
|
||||||
|
half _FurGravity;
|
||||||
|
half _FurRandomize;
|
||||||
|
half _FurAO;
|
||||||
|
half _FurLayerNum;
|
||||||
|
half _FurRootOffset;
|
||||||
|
|
||||||
|
// Fur Rim
|
||||||
|
half4 _FurRimColor;
|
||||||
|
half _FurRimFresnelPower;
|
||||||
|
half _FurRimAntiLight;
|
||||||
|
|
||||||
|
// Cel Shading
|
||||||
|
half _CelShadeMidPoint;
|
||||||
|
half _CelShadeSoftness;
|
||||||
|
|
||||||
|
// Shadow Color
|
||||||
|
half4 _ShadowColor;
|
||||||
|
half _ShadowBrightness;
|
||||||
|
half _ShadowHueShift;
|
||||||
|
half _ShadowSaturationBoost;
|
||||||
|
half _ShadowValueMultiplier;
|
||||||
|
|
||||||
|
// MatCap Add
|
||||||
|
float4 _MatCapAddMap_ST;
|
||||||
|
half4 _MatCapAddColor;
|
||||||
|
half _MatCapAddIntensity;
|
||||||
|
float4 _MatCapAddMask_ST;
|
||||||
|
|
||||||
|
// MatCap Multiply
|
||||||
|
float4 _MatCapMulMap_ST;
|
||||||
|
half _MatCapMulIntensity;
|
||||||
|
|
||||||
|
// Rim Light
|
||||||
|
half4 _RimLightColor;
|
||||||
|
half _RimLightPower;
|
||||||
|
half _RimLightIntensity;
|
||||||
|
|
||||||
|
// Emission
|
||||||
|
float4 _EmissionMap_ST;
|
||||||
|
half4 _EmissionColor;
|
||||||
|
half _EmissionIntensity;
|
||||||
|
|
||||||
|
// Occlusion
|
||||||
|
float4 _OcclusionMap_ST;
|
||||||
|
half _OcclusionStrength;
|
||||||
|
|
||||||
|
// Outline
|
||||||
|
half _OutlineWidth;
|
||||||
|
half4 _OutlineColor;
|
||||||
|
float4 _OutlineWidthMask_ST;
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
half _Cull;
|
||||||
|
half _FurCull;
|
||||||
|
CBUFFER_END
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Texture Declarations (all textures declared unconditionally to avoid compilation issues)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
|
||||||
|
TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap);
|
||||||
|
|
||||||
|
// Fur textures
|
||||||
|
TEXTURE2D(_FurNoiseMask); SAMPLER(sampler_FurNoiseMask);
|
||||||
|
TEXTURE2D(_FurMask); SAMPLER(sampler_FurMask);
|
||||||
|
TEXTURE2D(_FurLengthMask); SAMPLER(sampler_FurLengthMask);
|
||||||
|
TEXTURE2D(_FurVectorTex); SAMPLER(sampler_FurVectorTex);
|
||||||
|
|
||||||
|
// MatCap
|
||||||
|
TEXTURE2D(_MatCapAddMap); SAMPLER(sampler_MatCapAddMap);
|
||||||
|
TEXTURE2D(_MatCapAddMask); SAMPLER(sampler_MatCapAddMask);
|
||||||
|
TEXTURE2D(_MatCapMulMap); SAMPLER(sampler_MatCapMulMap);
|
||||||
|
|
||||||
|
// Emission
|
||||||
|
TEXTURE2D(_EmissionMap); SAMPLER(sampler_EmissionMap);
|
||||||
|
|
||||||
|
// Occlusion
|
||||||
|
TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap);
|
||||||
|
|
||||||
|
// Outline
|
||||||
|
TEXTURE2D(_OutlineWidthMask); SAMPLER(sampler_OutlineWidthMask);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Vertex Input Structure
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
struct Attributes
|
||||||
|
{
|
||||||
|
float4 positionOS : POSITION;
|
||||||
|
float3 normalOS : NORMAL;
|
||||||
|
float4 tangentOS : TANGENT;
|
||||||
|
float2 uv : TEXCOORD0;
|
||||||
|
float2 uv2 : TEXCOORD1;
|
||||||
|
float4 color : COLOR;
|
||||||
|
uint vertexID : SV_VertexID;
|
||||||
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Vertex to Geometry Structure (for Fur Shell Pass)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
struct V2G
|
||||||
|
{
|
||||||
|
float2 uv : TEXCOORD0;
|
||||||
|
float3 positionWS : TEXCOORD1;
|
||||||
|
float3 normalWS : TEXCOORD2;
|
||||||
|
float4 tangentWS : TEXCOORD3;
|
||||||
|
float3 furVector : TEXCOORD4;
|
||||||
|
float fogFactor : TEXCOORD5;
|
||||||
|
uint vertexID : TEXCOORD6;
|
||||||
|
float4 color : COLOR;
|
||||||
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||||
|
UNITY_VERTEX_OUTPUT_STEREO
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Fragment Input Structure
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
struct Varyings
|
||||||
|
{
|
||||||
|
float4 positionCS : SV_POSITION;
|
||||||
|
float2 uv : TEXCOORD0;
|
||||||
|
float3 positionWS : TEXCOORD1;
|
||||||
|
float3 normalWS : TEXCOORD2;
|
||||||
|
float4 tangentWS : TEXCOORD3;
|
||||||
|
float fogFactor : TEXCOORD4;
|
||||||
|
float furLayer : TEXCOORD5; // 0 = base, 1 = outer shell
|
||||||
|
float4 shadowCoord : TEXCOORD6;
|
||||||
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||||
|
UNITY_VERTEX_OUTPUT_STEREO
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Color Space Conversion (RGB <-> HSV)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
float3 RGBToHSV(float3 rgb)
|
||||||
|
{
|
||||||
|
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
||||||
|
float4 p = lerp(float4(rgb.bg, K.wz), float4(rgb.gb, K.xy), step(rgb.b, rgb.g));
|
||||||
|
float4 q = lerp(float4(p.xyw, rgb.r), float4(rgb.r, p.yzx), step(p.x, rgb.r));
|
||||||
|
float d = q.x - min(q.w, q.y);
|
||||||
|
float e = 1.0e-10;
|
||||||
|
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 HSVToRGB(float3 hsv)
|
||||||
|
{
|
||||||
|
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
||||||
|
float3 p = abs(frac(hsv.xxx + K.xyz) * 6.0 - K.www);
|
||||||
|
return hsv.z * lerp(K.xxx, saturate(p - K.xxx), hsv.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Utility: Grayscale
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
half Grayscale(half3 color)
|
||||||
|
{
|
||||||
|
return dot(color, half3(0.299, 0.587, 0.114));
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Normal Map Unpacking
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
half3 UnpackNormalWithScale(half4 packedNormal, half scale)
|
||||||
|
{
|
||||||
|
#if defined(UNITY_NO_DXT5nm)
|
||||||
|
half3 normal = packedNormal.xyz * 2.0 - 1.0;
|
||||||
|
#else
|
||||||
|
half3 normal;
|
||||||
|
normal.xy = packedNormal.ag * 2.0 - 1.0;
|
||||||
|
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
|
||||||
|
#endif
|
||||||
|
normal.xy *= scale;
|
||||||
|
return normalize(normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// MatCap UV Calculation
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
float2 GetMatCapUV(float3 normalWS, float3 viewDirWS)
|
||||||
|
{
|
||||||
|
float3 viewNormal = mul((float3x3)UNITY_MATRIX_V, normalWS);
|
||||||
|
return viewNormal.xy * 0.5 + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Apply HSV Change to Color
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
half3 ApplyHSVChange(half3 color, half hueOffset, half saturationBoost, half valueMul)
|
||||||
|
{
|
||||||
|
float3 hsv = RGBToHSV(color);
|
||||||
|
hsv.x = frac(hsv.x + hueOffset);
|
||||||
|
hsv.y = saturate(hsv.y * saturationBoost);
|
||||||
|
hsv.z = hsv.z * valueMul;
|
||||||
|
return HSVToRGB(hsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// NiloToon Style Cel Shading (Full Version)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
half3 ApplyNiloToonCelShading(
|
||||||
|
half3 baseColor,
|
||||||
|
half3 lightColor,
|
||||||
|
half3 lightDir,
|
||||||
|
half3 normalWS,
|
||||||
|
half3 viewDir,
|
||||||
|
half shadowAttenuation,
|
||||||
|
half occlusion
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Calculate NdotL
|
||||||
|
half NdotL = dot(normalWS, lightDir);
|
||||||
|
|
||||||
|
// Cel shading with configurable mid point and softness
|
||||||
|
half halfLambert = NdotL * 0.5 + 0.5;
|
||||||
|
half celShadeResult = smoothstep(
|
||||||
|
_CelShadeMidPoint + 0.5 - _CelShadeSoftness,
|
||||||
|
_CelShadeMidPoint + 0.5 + _CelShadeSoftness,
|
||||||
|
halfLambert
|
||||||
|
);
|
||||||
|
|
||||||
|
// Apply shadow map attenuation
|
||||||
|
celShadeResult *= shadowAttenuation;
|
||||||
|
|
||||||
|
// Apply occlusion
|
||||||
|
celShadeResult *= occlusion;
|
||||||
|
|
||||||
|
half3 finalColor = baseColor;
|
||||||
|
|
||||||
|
#if defined(_SHADOW_COLOR)
|
||||||
|
// Apply HSV adjustment to shadow
|
||||||
|
half3 shadowAlbedo = ApplyHSVChange(
|
||||||
|
baseColor,
|
||||||
|
_ShadowHueShift,
|
||||||
|
_ShadowSaturationBoost,
|
||||||
|
_ShadowValueMultiplier
|
||||||
|
);
|
||||||
|
|
||||||
|
// Apply shadow tint and brightness
|
||||||
|
shadowAlbedo *= _ShadowColor.rgb * _ShadowBrightness;
|
||||||
|
|
||||||
|
// Blend between shadow and lit based on cel shade result
|
||||||
|
finalColor = lerp(shadowAlbedo, baseColor, celShadeResult);
|
||||||
|
#else
|
||||||
|
// Simple brightness reduction in shadow
|
||||||
|
finalColor = lerp(baseColor * 0.5, baseColor, celShadeResult);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Apply light color
|
||||||
|
finalColor *= lightColor;
|
||||||
|
|
||||||
|
return finalColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Fur Vector Calculation (from lilToon)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
float3 CalculateFurVector(float3 normalOS, float4 tangentOS, float2 uv, float4 vertexColor, bool useVertexColor)
|
||||||
|
{
|
||||||
|
// Build TBN matrix
|
||||||
|
float3 bitangentOS = normalize(cross(normalOS, tangentOS.xyz)) * (tangentOS.w * length(normalOS));
|
||||||
|
float3x3 tbnOS = float3x3(tangentOS.xyz, bitangentOS, normalOS);
|
||||||
|
|
||||||
|
// Start with base fur vector
|
||||||
|
float3 furVector = _FurVector.xyz + float3(0, 0, 0.001);
|
||||||
|
|
||||||
|
// Optional: blend with vertex color
|
||||||
|
if (useVertexColor)
|
||||||
|
{
|
||||||
|
float3 vertexNormal = vertexColor.xyz * 2.0 - 1.0;
|
||||||
|
furVector = normalize(furVector + vertexNormal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform to tangent space, then apply fur direction texture
|
||||||
|
#if defined(NILOTOON_FUR_SHELL_PASS)
|
||||||
|
float4 furDirTex = SAMPLE_TEXTURE2D_LOD(_FurVectorTex, sampler_FurVectorTex, uv * _FurVectorTex_ST.xy + _FurVectorTex_ST.zw, 0);
|
||||||
|
float3 furDirFromTex = UnpackNormalWithScale(furDirTex, _FurVectorScale);
|
||||||
|
furVector = normalize(furVector + furDirFromTex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Transform to object space direction
|
||||||
|
furVector = mul(normalize(furVector), tbnOS);
|
||||||
|
furVector *= _FurVector.w;
|
||||||
|
|
||||||
|
// Apply gravity
|
||||||
|
float furLength = length(furVector);
|
||||||
|
furVector.y -= _FurGravity * furLength;
|
||||||
|
|
||||||
|
return furVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Base Pass Vertex Shader
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
#if defined(NILOTOON_FUR_BASE_PASS)
|
||||||
|
Varyings vert(Attributes input)
|
||||||
|
{
|
||||||
|
Varyings output = (Varyings)0;
|
||||||
|
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
||||||
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
||||||
|
|
||||||
|
// Transform
|
||||||
|
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
|
||||||
|
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
|
||||||
|
|
||||||
|
output.positionCS = vertexInput.positionCS;
|
||||||
|
output.positionWS = vertexInput.positionWS;
|
||||||
|
output.normalWS = normalInput.normalWS;
|
||||||
|
output.tangentWS = float4(normalInput.tangentWS, input.tangentOS.w);
|
||||||
|
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
|
||||||
|
|
||||||
|
// Shadow coord
|
||||||
|
output.shadowCoord = GetShadowCoordSafe(vertexInput);
|
||||||
|
|
||||||
|
// Fog
|
||||||
|
output.fogFactor = ComputeFogFactor(vertexInput.positionCS.z);
|
||||||
|
|
||||||
|
// Base pass has no fur layer
|
||||||
|
output.furLayer = -1.0;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Fur Pass Vertex Shader (outputs to Geometry Shader)
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
#if defined(NILOTOON_FUR_SHELL_PASS)
|
||||||
|
V2G vert_fur(Attributes input)
|
||||||
|
{
|
||||||
|
V2G output = (V2G)0;
|
||||||
|
|
||||||
|
UNITY_SETUP_INSTANCE_ID(input);
|
||||||
|
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
||||||
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
|
||||||
|
|
||||||
|
// Transform position and normal to world space
|
||||||
|
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
|
||||||
|
|
||||||
|
output.positionWS = TransformObjectToWorld(input.positionOS.xyz);
|
||||||
|
output.normalWS = normalInput.normalWS;
|
||||||
|
output.tangentWS = float4(normalInput.tangentWS, input.tangentOS.w);
|
||||||
|
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
|
||||||
|
output.color = input.color;
|
||||||
|
output.vertexID = input.vertexID;
|
||||||
|
|
||||||
|
// Calculate fur vector in world space
|
||||||
|
float3 furVectorOS = CalculateFurVector(input.normalOS, input.tangentOS, input.uv, input.color, false);
|
||||||
|
output.furVector = TransformObjectToWorldDir(furVectorOS, false);
|
||||||
|
|
||||||
|
// Apply fur length mask
|
||||||
|
float furLengthMask = SAMPLE_TEXTURE2D_LOD(_FurLengthMask, sampler_FurLengthMask, input.uv * _FurLengthMask_ST.xy + _FurLengthMask_ST.zw, 0).r;
|
||||||
|
output.furVector *= furLengthMask;
|
||||||
|
|
||||||
|
// Fog
|
||||||
|
float4 posCS = TransformWorldToHClip(output.positionWS);
|
||||||
|
output.fogFactor = ComputeFogFactor(posCS.z);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NILOTOON_CHARACTER_FUR_SHARED_INCLUDED
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 433eaffdfbbdaff41b9794f5adc9878a
|
||||||
|
ShaderIncludeImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
156
Assets/NiloToonURP/Shaders/NiloToonCharacterFur_ShellOnly.shader
Normal file
156
Assets/NiloToonURP/Shaders/NiloToonCharacterFur_ShellOnly.shader
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
// NiloToon Character Fur Shell Only Shader
|
||||||
|
// Use this shader on a second material slot to render fur shells
|
||||||
|
// The base mesh should use NiloToonCharacter or NiloToonCharacterFur shader
|
||||||
|
|
||||||
|
Shader "Universal Render Pipeline/NiloToon/NiloToon_Character_Fur_ShellOnly"
|
||||||
|
{
|
||||||
|
Properties
|
||||||
|
{
|
||||||
|
[Header(Base Color)]
|
||||||
|
[Space(5)]
|
||||||
|
[MainTexture] _BaseMap("Base Map", 2D) = "white" {}
|
||||||
|
[HDR][MainColor] _BaseColor("Base Color", Color) = (1,1,1,1)
|
||||||
|
_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
|
||||||
|
|
||||||
|
[Header(Normal Map)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_NORMALMAP)] _UseNormalMap("Enable Normal Map", Float) = 0
|
||||||
|
[Normal] _BumpMap("Normal Map", 2D) = "bump" {}
|
||||||
|
_BumpScale("Normal Scale", Range(0, 2)) = 1.0
|
||||||
|
|
||||||
|
[Header(Fur Shape)]
|
||||||
|
[Space(5)]
|
||||||
|
_FurNoiseMask("Fur Noise Mask", 2D) = "white" {}
|
||||||
|
_FurMask("Fur Mask (where fur appears)", 2D) = "white" {}
|
||||||
|
_FurLengthMask("Fur Length Mask", 2D) = "white" {}
|
||||||
|
_FurVector("Fur Direction (XYZ) + Length (W)", Vector) = (0, 0, 1, 0.02)
|
||||||
|
[Normal] _FurVectorTex("Fur Direction Map (Normal)", 2D) = "bump" {}
|
||||||
|
_FurVectorScale("Fur Direction Scale", Range(-10, 10)) = 1.0
|
||||||
|
_FurGravity("Fur Gravity", Range(0, 1)) = 0.25
|
||||||
|
_FurRandomize("Fur Randomize", Range(0, 1)) = 0.1
|
||||||
|
_FurAO("Fur Ambient Occlusion", Range(0, 1)) = 0.5
|
||||||
|
|
||||||
|
[Header(Shell Layers)]
|
||||||
|
[Space(5)]
|
||||||
|
[IntRange] _FurLayerNum("Fur Layer Count", Range(1, 3)) = 2
|
||||||
|
_FurRootOffset("Fur Root Offset", Range(-1, 0)) = 0
|
||||||
|
|
||||||
|
[Header(Fur Rim Light)]
|
||||||
|
[Space(5)]
|
||||||
|
[HDR] _FurRimColor("Fur Rim Color", Color) = (1, 1, 1, 1)
|
||||||
|
_FurRimFresnelPower("Fur Rim Fresnel Power", Range(0.01, 50)) = 3.0
|
||||||
|
_FurRimAntiLight("Fur Rim Anti-Light", Range(0, 1)) = 0.5
|
||||||
|
|
||||||
|
[Header(Cel Shading)]
|
||||||
|
[Space(5)]
|
||||||
|
_CelShadeMidPoint("Cel Shade Mid Point", Range(-1, 1)) = 0
|
||||||
|
_CelShadeSoftness("Cel Shade Softness", Range(0, 1)) = 0.1
|
||||||
|
|
||||||
|
[Header(Shadow Color)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_SHADOW_COLOR)] _EnableShadowColor("Enable Shadow Color", Float) = 0
|
||||||
|
[HDR] _ShadowColor("Shadow Tint Color", Color) = (1, 1, 1, 1)
|
||||||
|
_ShadowBrightness("Shadow Brightness", Range(0, 2)) = 1.0
|
||||||
|
_ShadowHueShift("Shadow Hue Shift", Range(-0.5, 0.5)) = 0
|
||||||
|
_ShadowSaturationBoost("Shadow Saturation Boost", Range(0, 2)) = 1.0
|
||||||
|
_ShadowValueMultiplier("Shadow Value Multiplier", Range(0, 2)) = 1.0
|
||||||
|
|
||||||
|
[Header(MatCap Additive)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_MATCAP_ADD)] _UseMatCapAdd("Enable MatCap (Add)", Float) = 0
|
||||||
|
_MatCapAddMap("MatCap Add Map", 2D) = "black" {}
|
||||||
|
[HDR] _MatCapAddColor("MatCap Add Color", Color) = (1, 1, 1, 1)
|
||||||
|
_MatCapAddIntensity("MatCap Add Intensity", Range(0, 5)) = 1.0
|
||||||
|
_MatCapAddMask("MatCap Add Mask", 2D) = "white" {}
|
||||||
|
|
||||||
|
[Header(MatCap Multiply)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_MATCAP_MUL)] _UseMatCapMul("Enable MatCap (Multiply)", Float) = 0
|
||||||
|
_MatCapMulMap("MatCap Multiply Map", 2D) = "white" {}
|
||||||
|
_MatCapMulIntensity("MatCap Multiply Intensity", Range(0, 2)) = 1.0
|
||||||
|
|
||||||
|
[Header(Emission)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_EMISSION)] _UseEmission("Enable Emission", Float) = 0
|
||||||
|
_EmissionMap("Emission Map", 2D) = "white" {}
|
||||||
|
[HDR] _EmissionColor("Emission Color", Color) = (0, 0, 0, 1)
|
||||||
|
_EmissionIntensity("Emission Intensity", Range(0, 10)) = 1.0
|
||||||
|
|
||||||
|
[Header(Occlusion)]
|
||||||
|
[Space(5)]
|
||||||
|
[Toggle(_OCCLUSIONMAP)] _UseOcclusion("Enable Occlusion Map", Float) = 0
|
||||||
|
_OcclusionMap("Occlusion Map", 2D) = "white" {}
|
||||||
|
_OcclusionStrength("Occlusion Strength", Range(0, 1)) = 1.0
|
||||||
|
|
||||||
|
[Header(Outline)]
|
||||||
|
[Space(5)]
|
||||||
|
_OutlineWidth("Outline Width", Range(0, 10)) = 0
|
||||||
|
[HDR] _OutlineColor("Outline Color", Color) = (0, 0, 0, 1)
|
||||||
|
_OutlineWidthMask("Outline Width Mask", 2D) = "white" {}
|
||||||
|
|
||||||
|
[Header(Rendering Options)]
|
||||||
|
[Space(5)]
|
||||||
|
[Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull Mode", Float) = 2
|
||||||
|
[Enum(UnityEngine.Rendering.CullMode)] _FurCull("Fur Cull Mode", Float) = 0
|
||||||
|
[Enum(Off, 0, On, 1)] _ZWrite("ZWrite", Float) = 0
|
||||||
|
_FurZWrite("Fur ZWrite", Float) = 0
|
||||||
|
[Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", Float) = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
SubShader
|
||||||
|
{
|
||||||
|
Tags
|
||||||
|
{
|
||||||
|
"RenderType" = "Transparent"
|
||||||
|
"RenderPipeline" = "UniversalPipeline"
|
||||||
|
"IgnoreProjector" = "True"
|
||||||
|
"Queue" = "Transparent-50"
|
||||||
|
}
|
||||||
|
LOD 300
|
||||||
|
|
||||||
|
// Fur Shell Pass
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
Name "FurShell"
|
||||||
|
Tags { "LightMode" = "UniversalForward" }
|
||||||
|
|
||||||
|
Cull [_FurCull]
|
||||||
|
ZWrite [_FurZWrite]
|
||||||
|
ZTest LEqual
|
||||||
|
Blend SrcAlpha OneMinusSrcAlpha, One OneMinusSrcAlpha
|
||||||
|
|
||||||
|
HLSLPROGRAM
|
||||||
|
#pragma target 4.5
|
||||||
|
#pragma require geometry
|
||||||
|
|
||||||
|
#pragma shader_feature_local _NORMALMAP
|
||||||
|
#pragma shader_feature_local _SHADOW_COLOR
|
||||||
|
#pragma shader_feature_local _MATCAP_ADD
|
||||||
|
#pragma shader_feature_local _MATCAP_MUL
|
||||||
|
#pragma shader_feature_local _RIMLIGHT
|
||||||
|
#pragma shader_feature_local _EMISSION
|
||||||
|
#pragma shader_feature_local _OCCLUSIONMAP
|
||||||
|
|
||||||
|
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
|
||||||
|
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
|
||||||
|
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
|
||||||
|
#pragma multi_compile_fragment _ _SHADOWS_SOFT
|
||||||
|
#pragma multi_compile_fog
|
||||||
|
|
||||||
|
#pragma multi_compile_instancing
|
||||||
|
#pragma instancing_options renderinglayer
|
||||||
|
|
||||||
|
#pragma vertex vert_fur
|
||||||
|
#pragma geometry geom_fur
|
||||||
|
#pragma fragment frag_fur
|
||||||
|
|
||||||
|
#define NILOTOON_FUR_SHELL_PASS
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Shared.hlsl"
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Geometry.hlsl"
|
||||||
|
#include "NiloToonCharacterFur_HLSL/NiloToonCharacterFur_Fragment.hlsl"
|
||||||
|
ENDHLSL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FallBack Off
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9b3349963a9dea04da1b88df137b8d82
|
||||||
|
ShaderImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
defaultTextures: []
|
||||||
|
nonModifiableTextures: []
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Loading…
x
Reference in New Issue
Block a user