Fix : 닐로툰 버전업데이트

This commit is contained in:
KINDNICK 2025-10-31 03:28:00 +09:00
parent 85df3c9126
commit 28676c86d3
106 changed files with 4529 additions and 358 deletions

BIN
.claude/settings.local.json (Stored with Git LFS)

Binary file not shown.

BIN
Assets/External/NiloToonURP/CHANGELOG.md (Stored with Git LFS) vendored

Binary file not shown.

View File

@ -0,0 +1,510 @@
// For how to use [Revertible], see RevertibleAttribute.cs
using UnityEngine;
using UnityEditor;
using System.Reflection;
using System;
using System.Linq;
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(RevertibleAttribute))]
public class RevertiblePropertyDrawer : PropertyDrawer
{
private const float BUTTON_WIDTH = 20f;
private const float SPACING = 2f;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Get the default value
object defaultValue = GetDefaultValue(property);
// Check if current value differs from default
bool isDifferentFromDefault = !IsEqualToDefault(property, defaultValue);
// Calculate rects
Rect propertyRect = position;
if (isDifferentFromDefault)
{
propertyRect.width -= BUTTON_WIDTH + SPACING;
}
// Draw the property field with other attributes (like Range)
DrawPropertyWithOtherAttributes(propertyRect, property, label);
// Draw revert button if value is different from default
if (isDifferentFromDefault)
{
Rect buttonRect = new Rect(
position.x + position.width - BUTTON_WIDTH,
position.y,
BUTTON_WIDTH,
EditorGUIUtility.singleLineHeight
);
// Create tooltip
GUIContent buttonContent = new GUIContent("↺", "Revert to default value");
// Alternative symbols you can use:
// "⟲" - circle arrow
// "↶" - anticlockwise arrow
// "⎌" - undo symbol
// "✕" - X mark
// "⌫" - delete/backspace
// "◀" - back arrow
// Style the button
GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);
buttonStyle.fontSize = 14;
buttonStyle.fontStyle = FontStyle.Bold;
buttonStyle.padding = new RectOffset(0, 0, 0, 0);
// Use orange tint for visibility
Color oldColor = GUI.color;
GUI.color = new Color(1f, 0.8f, 0.5f, 1f); // Orange tint
if (GUI.Button(buttonRect, buttonContent, buttonStyle))
{
RevertToDefault(property, defaultValue);
}
GUI.color = oldColor;
}
}
private void DrawPropertyWithOtherAttributes(Rect position, SerializedProperty property, GUIContent label)
{
// Get the field info
FieldInfo fieldInfo = GetFieldInfo(property);
if (fieldInfo == null)
{
EditorGUI.PropertyField(position, property, label, true);
return;
}
// Check for Range attribute
RangeAttribute rangeAttribute = fieldInfo.GetCustomAttribute<RangeAttribute>();
if (rangeAttribute != null)
{
if (property.propertyType == SerializedPropertyType.Float)
{
EditorGUI.Slider(position, property, rangeAttribute.min, rangeAttribute.max, label);
}
else if (property.propertyType == SerializedPropertyType.Integer)
{
EditorGUI.IntSlider(position, property, (int)rangeAttribute.min, (int)rangeAttribute.max, label);
}
else
{
EditorGUI.PropertyField(position, property, label, true);
}
return;
}
// Check for Min attribute (Unity 2021.2+)
#if UNITY_2021_2_OR_NEWER
MinAttribute minAttribute = fieldInfo.GetCustomAttribute<MinAttribute>();
if (minAttribute != null)
{
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(position, property, label, true);
if (EditorGUI.EndChangeCheck())
{
if (property.propertyType == SerializedPropertyType.Float)
{
property.floatValue = Mathf.Max(property.floatValue, minAttribute.min);
}
else if (property.propertyType == SerializedPropertyType.Integer)
{
property.intValue = Mathf.Max(property.intValue, (int)minAttribute.min);
}
}
return;
}
#endif
// Check for TextArea attribute
TextAreaAttribute textAreaAttribute = fieldInfo.GetCustomAttribute<TextAreaAttribute>();
if (textAreaAttribute != null && property.propertyType == SerializedPropertyType.String)
{
position.height = EditorGUIUtility.singleLineHeight * (textAreaAttribute.maxLines + 1);
property.stringValue = EditorGUI.TextArea(position, label.text, property.stringValue);
return;
}
// Check for Multiline attribute
MultilineAttribute multilineAttribute = fieldInfo.GetCustomAttribute<MultilineAttribute>();
if (multilineAttribute != null && property.propertyType == SerializedPropertyType.String)
{
position.height = EditorGUIUtility.singleLineHeight * multilineAttribute.lines;
property.stringValue = EditorGUI.TextArea(position, label.text, property.stringValue);
return;
}
// Default property field
EditorGUI.PropertyField(position, property, label, true);
}
private FieldInfo GetFieldInfo(SerializedProperty property)
{
Type targetType = property.serializedObject.targetObject.GetType();
string[] path = property.propertyPath.Split('.');
FieldInfo field = null;
Type currentType = targetType;
for (int i = 0; i < path.Length; i++)
{
// Skip array element paths
if (path[i].Contains("["))
continue;
field = currentType.GetField(path[i],
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null && i < path.Length - 1)
{
currentType = field.FieldType;
// Handle arrays and lists
if (currentType.IsArray)
{
currentType = currentType.GetElementType();
}
else if (currentType.IsGenericType && currentType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.List<>))
{
currentType = currentType.GetGenericArguments()[0];
}
}
}
return field;
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
FieldInfo fieldInfo = GetFieldInfo(property);
if (fieldInfo != null)
{
// Check for TextArea attribute
TextAreaAttribute textAreaAttribute = fieldInfo.GetCustomAttribute<TextAreaAttribute>();
if (textAreaAttribute != null && property.propertyType == SerializedPropertyType.String)
{
return EditorGUIUtility.singleLineHeight * (textAreaAttribute.maxLines + 1);
}
// Check for Multiline attribute
MultilineAttribute multilineAttribute = fieldInfo.GetCustomAttribute<MultilineAttribute>();
if (multilineAttribute != null && property.propertyType == SerializedPropertyType.String)
{
return EditorGUIUtility.singleLineHeight * multilineAttribute.lines;
}
}
return EditorGUI.GetPropertyHeight(property, label, true);
}
private object GetDefaultValue(SerializedProperty property)
{
// Get the target object type
Type targetType = property.serializedObject.targetObject.GetType();
// Check if it's a MonoBehaviour or Component - if so, create temp GameObject
if (typeof(MonoBehaviour).IsAssignableFrom(targetType) ||
typeof(Component).IsAssignableFrom(targetType))
{
GameObject tempGO = new GameObject("TempForDefaults");
tempGO.hideFlags = HideFlags.HideAndDontSave;
try
{
Component tempComponent = SafeAddComponentWithRequirements(tempGO,targetType);
// Navigate through the property path to get the field
string[] path = property.propertyPath.Split('.');
object currentObject = tempComponent;
FieldInfo field = null;
for (int i = 0; i < path.Length; i++)
{
// Handle array elements
if (path[i].Contains("["))
{
return GetDefaultValueForType(property.propertyType);
}
field = currentObject.GetType().GetField(path[i],
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null && i < path.Length - 1)
{
currentObject = field.GetValue(currentObject);
if (currentObject == null)
{
return GetDefaultValueForType(property.propertyType);
}
}
}
if (field != null)
{
return field.GetValue(currentObject);
}
}
finally
{
UnityEngine.Object.DestroyImmediate(tempGO);
}
return GetDefaultValueForType(property.propertyType);
}
// Check if it's a ScriptableObject (including ScriptableRendererFeature)
if (typeof(ScriptableObject).IsAssignableFrom(targetType))
{
ScriptableObject tempInstance = ScriptableObject.CreateInstance(targetType);
try
{
// Navigate through the property path to get the field
string[] path = property.propertyPath.Split('.');
object currentObject = tempInstance;
FieldInfo field = null;
for (int i = 0; i < path.Length; i++)
{
// Handle array elements
if (path[i].Contains("["))
{
return GetDefaultValueForType(property.propertyType);
}
field = currentObject.GetType().GetField(path[i],
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (field != null && i < path.Length - 1)
{
currentObject = field.GetValue(currentObject);
if (currentObject == null)
{
return GetDefaultValueForType(property.propertyType);
}
}
}
if (field != null)
{
return field.GetValue(currentObject);
}
}
finally
{
UnityEngine.Object.DestroyImmediate(tempInstance);
}
return GetDefaultValueForType(property.propertyType);
}
// For other types, use Activator.CreateInstance
object tempInstance2 = Activator.CreateInstance(targetType);
// Navigate through the property path to get the field
string[] path2 = property.propertyPath.Split('.');
object currentObject2 = tempInstance2;
FieldInfo field2 = null;
for (int i = 0; i < path2.Length; i++)
{
// Handle array elements
if (path2[i].Contains("["))
{
return GetDefaultValueForType(property.propertyType);
}
field2 = currentObject2.GetType().GetField(path2[i],
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (field2 != null && i < path2.Length - 1)
{
currentObject2 = field2.GetValue(currentObject2);
if (currentObject2 == null)
{
return GetDefaultValueForType(property.propertyType);
}
}
}
if (field2 != null)
{
return field2.GetValue(currentObject2);
}
return GetDefaultValueForType(property.propertyType);
}
private object GetDefaultValueForType(SerializedPropertyType propertyType)
{
switch (propertyType)
{
case SerializedPropertyType.Integer:
return 0;
case SerializedPropertyType.Float:
return 0f;
case SerializedPropertyType.Boolean:
return false;
case SerializedPropertyType.String:
return "";
case SerializedPropertyType.Vector2:
return Vector2.zero;
case SerializedPropertyType.Vector3:
return Vector3.zero;
case SerializedPropertyType.Vector4:
return Vector4.zero;
case SerializedPropertyType.Color:
return Color.white;
default:
return null;
}
}
private bool IsEqualToDefault(SerializedProperty property, object defaultValue)
{
if (defaultValue == null)
return false;
switch (property.propertyType)
{
case SerializedPropertyType.Integer:
return property.intValue == (int)defaultValue;
case SerializedPropertyType.Float:
return Mathf.Approximately(property.floatValue, (float)defaultValue);
case SerializedPropertyType.Boolean:
return property.boolValue == (bool)defaultValue;
case SerializedPropertyType.String:
return property.stringValue == (string)defaultValue;
case SerializedPropertyType.Vector2:
return property.vector2Value == (Vector2)defaultValue;
case SerializedPropertyType.Vector3:
return property.vector3Value == (Vector3)defaultValue;
case SerializedPropertyType.Vector4:
return property.vector4Value == (Vector4)defaultValue;
case SerializedPropertyType.Color:
return property.colorValue == (Color)defaultValue;
case SerializedPropertyType.ObjectReference:
return property.objectReferenceValue == (UnityEngine.Object)defaultValue;
case SerializedPropertyType.Enum:
// Handle enum properly - convert enum value to name then compare
if (defaultValue is Enum enumValue)
{
string defaultEnumName = enumValue.ToString();
string currentEnumName = property.enumNames.Length > property.enumValueIndex && property.enumValueIndex >= 0
? property.enumNames[property.enumValueIndex]
: "";
return defaultEnumName == currentEnumName;
}
return false;
default:
return false;
}
}
private void RevertToDefault(SerializedProperty property, object defaultValue)
{
if (defaultValue == null)
return;
Undo.RecordObject(property.serializedObject.targetObject, "Revert to Default");
switch (property.propertyType)
{
case SerializedPropertyType.Integer:
property.intValue = (int)defaultValue;
break;
case SerializedPropertyType.Float:
property.floatValue = (float)defaultValue;
break;
case SerializedPropertyType.Boolean:
property.boolValue = (bool)defaultValue;
break;
case SerializedPropertyType.String:
property.stringValue = (string)defaultValue;
break;
case SerializedPropertyType.Vector2:
property.vector2Value = (Vector2)defaultValue;
break;
case SerializedPropertyType.Vector3:
property.vector3Value = (Vector3)defaultValue;
break;
case SerializedPropertyType.Vector4:
property.vector4Value = (Vector4)defaultValue;
break;
case SerializedPropertyType.Color:
property.colorValue = (Color)defaultValue;
break;
case SerializedPropertyType.ObjectReference:
property.objectReferenceValue = (UnityEngine.Object)defaultValue;
break;
case SerializedPropertyType.Enum:
// Handle enum properly - find the index by name
if (defaultValue is Enum enumValue)
{
string enumName = enumValue.ToString();
int index = Array.IndexOf(property.enumNames, enumName);
if (index >= 0)
{
property.enumValueIndex = index;
}
else
{
// If exact name not found, try to use the integer value if it's valid
int intValue = Convert.ToInt32(defaultValue);
if (intValue >= 0 && intValue < property.enumNames.Length)
{
property.enumValueIndex = intValue;
}
else
{
// Fall back to first enum value
property.enumValueIndex = 0;
}
}
}
break;
}
property.serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(property.serializedObject.targetObject);
}
private Component SafeAddComponentWithRequirements(GameObject go, Type targetType)
{
// Add any required dependencies first
var requireAttrs = (RequireComponent[])targetType.GetCustomAttributes(typeof(RequireComponent), true);
foreach (var attr in requireAttrs)
{
if (attr.m_Type0 != null) SafeAddComponentWithRequirements(go, attr.m_Type0);
if (attr.m_Type1 != null) SafeAddComponentWithRequirements(go, attr.m_Type1);
if (attr.m_Type2 != null) SafeAddComponentWithRequirements(go, attr.m_Type2);
}
// Skip if already added
Component existing = go.GetComponent(targetType);
if (existing != null)
return existing;
// Handle abstract or problematic base types (like Renderer)
if (targetType == typeof(Renderer))
{
return go.AddComponent<MeshRenderer>(); // safe default
}
// Skip unsupported abstract classes and interfaces
if (targetType.IsAbstract || targetType.IsInterface)
{
Debug.LogWarning($"[Revertible] Skipped adding abstract/interface component type '{targetType}'.");
return null;
}
// Finally, add the actual component
return go.AddComponent(targetType);
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 68e81218f2ed1b040b19c4c7fc3c39bd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -137,6 +137,14 @@ namespace NiloToon.NiloToonURP
return;
// [only the source fbx which has "NiloToonBakeSmoothNormalTSIntoUV8" asset label will enter this section]
// new NiloToon method
if (IsParallelImportEnabled() || NiloToonProjectSettings.Instance.outlineBakeMethod == OutlineBakeMethod.NiloToon)
{
NiloBakeSmoothNormalTSToMeshUv8.GenGOSmoothedNormalToUV8(go, true);
return;
}
// default old Unity method
ModelImporter model = assetImporter as ModelImporter;
string srcFBXPath = model.assetPath;
string copiedFBXPath = ConvertSrcFBXPathToCopiedFBXPath(srcFBXPath);
@ -308,6 +316,14 @@ namespace NiloToon.NiloToonURP
return list;
}
public static bool IsParallelImportEnabled()
{
// https://discussions.unity.com/t/where-is-the-desired-import-worker-count-stored/920547/2
//bool isParallelImportEnabled = AssetDatabase.ActiveRefreshImportMode == AssetDatabase.RefreshImportMode.OutOfProcessPerQueue; // this always return false
bool isParallelImportEnabled = EditorSettings.refreshImportMode == AssetDatabase.RefreshImportMode.OutOfProcessPerQueue; // this works
return isParallelImportEnabled;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Jobs
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -394,6 +394,9 @@ namespace NiloToon.NiloToonURP
mat.shader == VRMURPMToon10Shader)
continue;
// Ensure not a variant
BreakMaterialVariant(mat);
// support these special shaders from URP's package:
// - PhysicalMaterial3DsMax
// - ArnoldStandardSurface
@ -452,6 +455,9 @@ namespace NiloToon.NiloToonURP
Material originalMatClone = allOriginalMaterialsClone[i];
NiloToonSurfaceTypePreset nilotoonSurfaceTypePresetID = niloToonSurfaceTypePresetIDArray[i];
// Ensure not a variant
BreakMaterialVariant(mat);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if material is URP package's material (e.g. Lit.mat),
// skip editing the material,
@ -1745,6 +1751,20 @@ namespace NiloToon.NiloToonURP
return false;
}
/// <summary>
/// Breaks the variant link of a material
/// </summary>
public static void BreakMaterialVariant(Material mat)
{
if (mat == null)
return;
// break (Material.parent only exists in Unity2022.1 or later)
#if UNITY_2022_3_OR_NEWER
mat.parent = null;
#endif
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// copy from UniversalRenderPipelineMaterialUpgrader.cs

View File

@ -364,10 +364,18 @@ namespace NiloToon.NiloToonURP
// we are going to fill in targetResultSetting by a correct setting of current platform
NiloToonShaderStrippingSettingSO.Settings targetResultSetting;
// get Scriptable Object(SO) from active forward renderer's NiloToonAllInOneRendererFeature's shaderStrippingSettingSO slot
NiloToonShaderStrippingSettingSO perPlatformUserStrippingSetting = NiloToonAllInOneRendererFeature.Instance.settings.shaderStrippingSettingSO; // TODO: when will NiloToonAllInOneRendererFeature.Instance is null?
NiloToonShaderStrippingSettingSO perPlatformUserStrippingSetting;
// (1) first try to get Scriptable Object(SO) from project settings
perPlatformUserStrippingSetting = NiloToonProjectSettings.Instance.shaderStrippingSetting;
// (2) if null, get Scriptable Object(SO) from active forward renderer's NiloToonAllInOneRendererFeature's shaderStrippingSettingSO slot
if (perPlatformUserStrippingSetting == null)
{
perPlatformUserStrippingSetting = NiloToonAllInOneRendererFeature.Instance?.settings?.shaderStrippingSettingSO; // NiloToonAllInOneRendererFeature.Instance is null when build using console command
}
// if we can't get any SO (user didn't assign it in active forward renderer's NiloToonAllInOneRendererFeature's shaderStrippingSettingSO slot)
// (3) if we still can't get any SO (user didn't assign it in project settings and active forward renderer's NiloToonAllInOneRendererFeature's shaderStrippingSettingSO slot)
// spawn a temp SO for this function only, which contains default values
if (perPlatformUserStrippingSetting == null)
{

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b346563ec1e2c0c4a9cd6c75478bd11a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,171 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Linq;
namespace NiloToon.NiloToonURP
{
public enum OutlineBakeMethod
{
Unity,
NiloToon
}
[System.Serializable]
public class NiloToonProjectSettingsData
{
public OutlineBakeMethod outlineBakeMethod = OutlineBakeMethod.Unity;
public string shaderStrippingSettingGUID = "";
}
public class NiloToonProjectSettings : ScriptableObject
{
private const string SettingsFileName = "NiloToonProjectSettings.json";
[SerializeField]
private OutlineBakeMethod _outlineBakeMethod = OutlineBakeMethod.Unity;
[SerializeField]
private string _shaderStrippingSettingGUID = "";
public OutlineBakeMethod outlineBakeMethod
{
get => _outlineBakeMethod;
set
{
if (_outlineBakeMethod != value)
{
_outlineBakeMethod = value;
SaveSettings();
}
}
}
public NiloToonShaderStrippingSettingSO shaderStrippingSetting
{
get
{
if (string.IsNullOrEmpty(_shaderStrippingSettingGUID))
return null;
string path = AssetDatabase.GUIDToAssetPath(_shaderStrippingSettingGUID);
if (string.IsNullOrEmpty(path))
{
Debug.LogWarning($"[NiloToon] Shader stripping setting GUID '{_shaderStrippingSettingGUID}' has no valid asset path!");
return null;
}
var asset = AssetDatabase.LoadAssetAtPath<NiloToonShaderStrippingSettingSO>(path);
if (asset == null)
{
Debug.LogWarning($"[NiloToon] Failed to load shader stripping setting from path: {path}");
}
return asset;
}
set
{
string newGUID = "";
if (value != null)
{
string path = AssetDatabase.GetAssetPath(value);
newGUID = AssetDatabase.AssetPathToGUID(path);
}
if (_shaderStrippingSettingGUID != newGUID)
{
_shaderStrippingSettingGUID = newGUID;
SaveSettings();
}
}
}
private static NiloToonProjectSettings instance;
public static NiloToonProjectSettings Instance
{
get
{
if (instance == null)
{
instance = CreateInstance<NiloToonProjectSettings>();
instance.hideFlags = HideFlags.DontUnloadUnusedAsset;
LoadSettings();
}
return instance;
}
}
public static void SaveSettings()
{
if (instance == null) return;
var data = new NiloToonProjectSettingsData
{
outlineBakeMethod = instance._outlineBakeMethod,
shaderStrippingSettingGUID = instance._shaderStrippingSettingGUID
};
string json = JsonUtility.ToJson(data, true);
string path = GetSettingsPath();
string directory = Path.GetDirectoryName(path);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
try
{
File.WriteAllText(path, json);
// Force refresh to ensure AssetDatabase is aware
AssetDatabase.Refresh();
}
catch (System.Exception e)
{
Debug.LogError($"Failed to save NiloToon settings: {e.Message}");
}
}
private static void LoadSettings()
{
string path = GetSettingsPath();
if (File.Exists(path))
{
try
{
string json = File.ReadAllText(path);
var data = JsonUtility.FromJson<NiloToonProjectSettingsData>(json);
if (data != null)
{
instance._outlineBakeMethod = data.outlineBakeMethod;
instance._shaderStrippingSettingGUID = data.shaderStrippingSettingGUID;
}
}
catch (System.Exception e)
{
Debug.LogError($"Failed to load NiloToon settings: {e.Message}");
SaveSettings();
}
}
else
{
SaveSettings();
}
}
private static string GetSettingsPath()
{
return Path.Combine(Application.dataPath, "..", "ProjectSettings", SettingsFileName);
}
internal static SerializedObject GetSerializedSettings()
{
return new SerializedObject(Instance);
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8b40fb4637586441af3b3940707eb9c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,124 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
namespace NiloToon.NiloToonURP
{
public class NiloToonProjectSettingsProvider : SettingsProvider
{
private SerializedObject settings;
private const string SettingsPath = "Project/NiloToon";
public NiloToonProjectSettingsProvider(string path, SettingsScope scope)
: base(path, scope) {}
[SettingsProvider]
public static SettingsProvider CreateSettingsProvider()
{
var provider = new NiloToonProjectSettingsProvider(SettingsPath, SettingsScope.Project);
provider.keywords = new HashSet<string>(new[] { "NiloToon", "Model", "Outline", "Bake", "Method", "Shader", "Stripping" });
return provider;
}
public override void OnActivate(string searchContext, UnityEngine.UIElements.VisualElement rootElement)
{
settings = NiloToonProjectSettings.GetSerializedSettings();
}
public override void OnGUI(string searchContext)
{
EditorGUILayout.LabelField("Outline Bake method", EditorStyles.boldLabel);
// if we don't add this, settings will be null after "revert scene change" clicked
if (settings == null || settings.targetObject == null)
{
settings = NiloToonProjectSettings.GetSerializedSettings();
}
if (settings == null || settings.targetObject == null)
{
EditorGUILayout.HelpBox("NiloToon settings are not available. Please check the console for errors.", MessageType.Error);
return;
}
settings.Update();
SerializedProperty outlineBakeMethodProp = settings.FindProperty("_outlineBakeMethod");
if (outlineBakeMethodProp == null)
{
EditorGUILayout.HelpBox("NiloToon settings(_outlineBakeMethod) are not available. Please check the console for errors.", MessageType.Error);
return;
}
OutlineBakeMethod currentBakeMethod = (OutlineBakeMethod)outlineBakeMethodProp.enumValueIndex;
// HelpBox
string helpBoxMessage;
bool isParallelImportEnabled = EditorSettings.refreshImportMode == AssetDatabase.RefreshImportMode.OutOfProcessPerQueue;
if (isParallelImportEnabled)
{
helpBoxMessage = "Parallel Import enabled, 'Outline Bake Method' is ignored, 'NiloToon' is used instead.\n" +
"Activated method = 'NiloToon' - faster to reimport, Parallel Import supported. It has a slightly different Classic Outline result than 'Unity'";
}
else
{
if (currentBakeMethod == OutlineBakeMethod.Unity)
{
helpBoxMessage = "Activated method = 'Unity' - slower to reimport, Parallel Import not supported, will fallback to 'NiloToon' if Parallel Import is enabled. It is the default option and produce the most robust Classic Outline result";
}
else
{
helpBoxMessage = "Activated method = 'NiloToon' - faster to reimport, Parallel Import supported. It has a slightly different Classic Outline result than 'Unity'";
}
}
EditorGUILayout.HelpBox(helpBoxMessage, MessageType.Info);
// Outline Bake Method
EditorGUILayout.PropertyField(outlineBakeMethodProp, new GUIContent("Outline Bake Method"));
//--------------------------------------------------------------------------------------------------------------------
EditorGUILayout.Space();
EditorGUILayout.LabelField("Shader stripping at Build Time", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("When assigned, NiloToon shader stripping at build time will use this setting.\n- higher priority than NiloToon renderer feature's Shader Stripping Setting\n- Required for build using command line", MessageType.Info);
EditorGUILayout.HelpBox("If your build doesn't reflect the change in this setting, it is due to shader cache from previous build doesn't invalidate, either:\n- Restart UnityEditor\n- or assign the same setting to the active NiloToon renderer feature's Shader Stripping Setting\nthen build again.", MessageType.Info);
// Shader Stripping Setting - ObjectField
EditorGUI.BeginChangeCheck();
var currentSetting = NiloToonProjectSettings.Instance.shaderStrippingSetting;
var newSetting = (NiloToonShaderStrippingSettingSO)EditorGUILayout.ObjectField(
"Shader Stripping Setting",
currentSetting,
typeof(NiloToonShaderStrippingSettingSO),
false
);
if (EditorGUI.EndChangeCheck())
{
NiloToonProjectSettings.Instance.shaderStrippingSetting = newSetting;
}
if (settings.ApplyModifiedProperties())
{
NiloToonProjectSettings.SaveSettings();
if (currentBakeMethod != NiloToonProjectSettings.Instance.outlineBakeMethod)
{
bool userWantToReimport = EditorUtility.DisplayDialog(
"Reimport Assets",
"Outline Bake Method changed. Reimport affected assets to ensure Outline data(UV8) is updated correctly?",
"Yes",
"No"
);
if (userWantToReimport)
{
NiloToonEditor_ReimportAllAssetFilteredByLabel.ReFixAll();
}
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e04314e618d38948ac96abe10a9a944
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -26,11 +26,22 @@ namespace LWGUI
_loadedPresets.Clear();
_isInitComplete = false;
var GUIDs = AssetDatabase.FindAssets("t:" + typeof(LwguiShaderPropertyPreset));
Debug.Log($"LWGUI PresetHelper: Found {GUIDs.Length} preset GUIDs");
foreach (var GUID in GUIDs)
{
var preset = AssetDatabase.LoadAssetAtPath<LwguiShaderPropertyPreset>(AssetDatabase.GUIDToAssetPath(GUID));
var path = AssetDatabase.GUIDToAssetPath(GUID);
var preset = AssetDatabase.LoadAssetAtPath<LwguiShaderPropertyPreset>(path);
if (preset != null)
{
Debug.Log($"LWGUI PresetHelper: Successfully loaded preset '{preset.name}' from '{path}'");
}
else
{
Debug.LogWarning($"LWGUI PresetHelper: Failed to load preset from '{path}' (GUID: {GUID})");
}
AddPreset(preset);
}
Debug.Log($"LWGUI PresetHelper: Loaded {_loadedPresets.Count} presets total");
_isInitComplete = true;
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 42dccf97e5104fe4382a89f9bf084932
guid: ea7a672e3232aff45a69dac5febb0b3b
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -2493,4 +2493,13 @@ namespace LWGUI
#endregion
}
// Unity's MaterialPropertyDrawer system looks for drawers in the global namespace
// Since LWGUI drawers are in the LWGUI namespace, we need to create global aliases
// so Unity can find them when parsing shader property attributes
public class MinMaxSliderDrawer : LWGUI.MinMaxSliderDrawer
{
public MinMaxSliderDrawer(string minPropName, string maxPropName) : base(minPropName, maxPropName) { }
public MinMaxSliderDrawer(string group, string minPropName, string maxPropName) : base(group, minPropName, maxPropName) { }
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -3,7 +3,7 @@ guid: cfbe5a628e96c0d4bae3645ad922a368
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
@ -67,7 +67,7 @@ TextureImporter:
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@ -80,7 +80,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@ -93,7 +93,7 @@ TextureImporter:
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
- serializedVersion: 4
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
@ -110,6 +110,7 @@ TextureImporter:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID:
@ -119,12 +120,11 @@ TextureImporter:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData: '{"MonoBehaviour":{"m_Enabled":true,"m_EditorHideFlags":0,"m_Name":"LWGUI_RampAtlas","m_EditorClassIdentifier":"","rampAtlasWidth":256,"rampAtlasHeight":8,"rampAtlasSRGB":true,"_ramps":[{"name":"Default
Ramp","gradient":{"_curves":[{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":0.0,"inSlope":0.0,"outSlope":1.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":1.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":0.0,"inSlope":0.0,"outSlope":1.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":1.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4}]},"colorSpace":0,"channelMask":15,"timeRange":1},{"name":"Default
Ramp","gradient":{"_curves":[{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":-0.00004999999873689376,"value":0.0,"inSlope":0.0,"outSlope":0.9999500513076782,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.9999500513076782,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":-0.00004999999873689376,"value":0.9492826461791992,"inSlope":0.0,"outSlope":0.05071482062339783,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.05071482062339783,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":-0.00004999999873689376,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4}]},"colorSpace":0,"channelMask":15,"timeRange":1},{"name":"New
Ramp","gradient":{"_curves":[{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4}]},"colorSpace":0,"channelMask":-1,"timeRange":1},{"name":"Green","gradient":{"_curves":[{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":0.0,"inSlope":0.0,"outSlope":1.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":1.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4},{"serializedVersion":"2","m_Curve":[{"serializedVersion":"3","time":0.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0},{"serializedVersion":"3","time":1.0,"value":1.0,"inSlope":0.0,"outSlope":0.0,"tangentMode":69,"weightedMode":0,"inWeight":0.0,"outWeight":0.0}],"m_PreInfinity":2,"m_PostInfinity":2,"m_RotationOrder":4}]},"colorSpace":1,"channelMask":10,"timeRange":24}],"_saveTextureToggle":false}}'
userData: '{"MonoBehaviour":{"m_Enabled":true,"m_EditorHideFlags":0,"m_Name":"LWGUI_RampAtlas","m_EditorClassIdentifier":"","rampAtlasWidth":256,"rampAtlasHeight":4,"rampAtlasSRGB":true,"_ramps":[],"_saveTextureToggle":false}}'
assetBundleName:
assetBundleVariant:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ddde4f59ff87bc842838b9aae66978c8
guid: 06bd32d357185894dbb2f68a3717575e
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d9611311befa11f4f944025e015b7f24
guid: 5c7c34954264fd1448f7dbd9f635da31
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 6379fbe32817f7847b8e0dcd9556c223
guid: 0f07bc2ea41e36b4fb8608dd8a13edd9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7ea89b75afa25a94ab8d5f6bb6e89a12
guid: eaeba2073c9de8b44b66337d73132096
ShaderImporter:
externalObjects: {}
defaultTextures: []

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3fbb65609fddee04d9c39968df19d171
guid: 66cd8ff5528c81244912a5ca60177097
ShaderImporter:
externalObjects: {}
defaultTextures:

Binary file not shown.

View File

@ -17,10 +17,8 @@ namespace UnityEditor.Rendering.Universal.ShaderGUI
//=======================================================================
private LitSplatGUI.LitProperties litSplatProperties;
private LitScreenSpaceOutlineGUI.LitProperties litScreenSpaceOutlineProperties;
private LitBillboardGUI.LitProperties litBillboardProperties;
private SavedBool m_SplatInputsFolder;
private SavedBool m_ScreenSpaceOutlineInputsFolder;
private SavedBool m_BillboardInputsFolder;
//=======================================================================
// NiloToon added (to support URP 12):
@ -33,7 +31,6 @@ namespace UnityEditor.Rendering.Universal.ShaderGUI
//=======================================================================
materialScopesList.RegisterHeaderScope(LitSplatGUI.Styles.splatInputs, Expandable.Details, _ => LitSplatGUI.DoSplatArea(litSplatProperties, materialEditor));
materialScopesList.RegisterHeaderScope(LitScreenSpaceOutlineGUI.Styles.outlineInputs, Expandable.Details, _ => LitScreenSpaceOutlineGUI.DoScreenSpaceOutlineArea(litScreenSpaceOutlineProperties, materialEditor));
materialScopesList.RegisterHeaderScope(LitBillboardGUI.Styles.billboardInputs, Expandable.Details, _ => LitBillboardGUI.DoBillboardArea(litBillboardProperties, materialEditor));
//=======================================================================
}
//=======================================================================
@ -49,7 +46,6 @@ namespace UnityEditor.Rendering.Universal.ShaderGUI
//=======================================================================
litSplatProperties = new LitSplatGUI.LitProperties(properties);
litScreenSpaceOutlineProperties = new LitScreenSpaceOutlineGUI.LitProperties(properties);
litBillboardProperties = new LitBillboardGUI.LitProperties(properties);
//=======================================================================
}
@ -537,98 +533,6 @@ namespace UnityEditor.Rendering.Universal.ShaderGUI
*/
}
}
internal class LitBillboardGUI
{
public static class Styles
{
public static readonly GUIContent billboardInputs = new GUIContent("Billboard Inputs",
"These settings let you enable billboard effect on the object.");
public static readonly GUIContent billboardEnable = new GUIContent("Enable Billboard",
"Enable or disable the billboard effect that makes the object always face the camera.");
public static readonly GUIContent unlitMode = new GUIContent("Unlit Mode",
"When enabled, the material ignores all lighting and uses only the base color.");
public static readonly GUIContent brightnessMultiplier = new GUIContent("Brightness Multiplier",
"Controls the overall brightness of the material. Values above 1 make it brighter, below 1 make it darker.");
public static readonly GUIContent billboardCullMode = new GUIContent("Billboard Cull Mode",
"Controls which faces to render. Off = Both sides, Back = Front faces only, Front = Back faces only.");
public static readonly string[] cullModeNames = { "Off (Both Sides)", "Front", "Back" };
}
public struct LitProperties
{
public MaterialProperty billboardEnable;
public MaterialProperty unlitMode;
public MaterialProperty brightnessMultiplier;
public MaterialProperty billboardCullMode;
public LitProperties(MaterialProperty[] properties)
{
billboardEnable = BaseShaderGUI.FindProperty("_BillboardEnable", properties, false);
unlitMode = BaseShaderGUI.FindProperty("_UnlitMode", properties, false);
brightnessMultiplier = BaseShaderGUI.FindProperty("_BrightnessMultiplier", properties, false);
billboardCullMode = BaseShaderGUI.FindProperty("_BillboardCullMode", properties, false);
}
}
public static void DoBillboardArea(LitProperties properties, MaterialEditor materialEditor)
{
// Toggle for billboard enable/disable
if (properties.billboardEnable != null)
{
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = properties.billboardEnable.hasMixedValue;
bool enabled = EditorGUILayout.Toggle(Styles.billboardEnable, properties.billboardEnable.floatValue > 0.5f);
if (EditorGUI.EndChangeCheck())
properties.billboardEnable.floatValue = enabled ? 1.0f : 0.0f;
EditorGUI.showMixedValue = false;
}
// Toggle for unlit mode
if (properties.unlitMode != null)
{
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = properties.unlitMode.hasMixedValue;
bool unlitEnabled = EditorGUILayout.Toggle(Styles.unlitMode, properties.unlitMode.floatValue > 0.5f);
if (EditorGUI.EndChangeCheck())
properties.unlitMode.floatValue = unlitEnabled ? 1.0f : 0.0f;
EditorGUI.showMixedValue = false;
}
// Brightness multiplier slider
if (properties.brightnessMultiplier != null)
{
materialEditor.ShaderProperty(properties.brightnessMultiplier, Styles.brightnessMultiplier);
}
// Billboard cull mode dropdown
if (properties.billboardCullMode != null)
{
EditorGUI.BeginChangeCheck();
int cullMode = (int)properties.billboardCullMode.floatValue;
cullMode = EditorGUILayout.Popup(Styles.billboardCullMode, cullMode, Styles.cullModeNames);
if (EditorGUI.EndChangeCheck())
{
properties.billboardCullMode.floatValue = cullMode;
// Update the main Cull property
foreach (Material mat in materialEditor.targets)
{
mat.SetInt("_Cull", cullMode);
}
}
}
}
public static void SetMaterialKeywords(Material material)
{
// Currently no keywords needed for billboard functionality
}
}
//=====================================================================================================================================
// direct copy from URP10.5.1's LitDetailGUI.cs (no edit)

View File

@ -42,6 +42,13 @@ namespace NiloToon.NiloToonURP
EditorUtility.SetDirty(target); // Mark the object as dirty when changes are made
}
// error check
if (volumeProfilePicker == null || volumeProfilePicker.volumeProfiles == null || volumeProfilePicker.volumeProfiles.Count == 0)
{
Debug.LogError("Did you manually added a NiloToonVolumePresetPicker script? Don't do that, instead, add via + > Create Other > NiloToon > VolumePresetPicker");
return;
}
// Display the name of the child at the current index
EditorGUILayout.LabelField(volumeProfilePicker.volumeProfiles[currentIndex.intValue].name);

Binary file not shown.

View File

@ -0,0 +1,40 @@
// Add [Revertible] to a field in any MonoBehaviour / ScriptableRendererFeature / ScriptableRenderPass script,
// then a revert button will show if the current value is not the default value
// * Only works for basic field type like float & bool, will not work for:
// - reference type field
// - enum field
// * You must place the [Revertible] ABOVE:
// - unity attributes like [Range(0,1)]
// - Nilo attributes like [RangeOverrideDisplayName("name",0,1)], [ColorUsageOverrideDisplayName("color", false, true)]
//--------------------------------------------------------
// This is correct place for [Revertible]
//[Revertible]
//[RangeOverrideDisplayName(" A", 0, 1)]
//public float settingA = 1;
//[Revertible]
//[Range(0, 1)]
//public float settingA = 1;
//--------------------------------------------------------
// This is wrong place for [Revertible]
//[RangeOverrideDisplayName(" A", 0, 1)]
//[Revertible]
//public float settingA = 1;
//[Range(0, 1)]
//[Revertible]
//public float settingA = 1;
//--------------------------------------------------------
using UnityEngine;
[System.AttributeUsage(System.AttributeTargets.Field, AllowMultiple = false)]
public class RevertibleAttribute : PropertyAttribute
{
public RevertibleAttribute()
{
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f681129f48865942b5266e946fa4bec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -7,16 +7,23 @@ public static class NiloBakeSmoothNormalTSToMeshUv8
// you can turn on when debug is needed
public static bool LOG_ERROR = false;
public static void GenGOSmoothedNormalToUV8(GameObject inputGO)
public static void GenGOSmoothedNormalToUV8(GameObject inputGO, bool forceRebake = false)
{
void GenMeshSmoothedNormalToUV8(Mesh mesh)
{
// only generate if uv#8 is missing and unused
// to prevent overwriting user's data / NiloToon editor generated uv8 data
if (mesh != null && mesh.uv8.Length == 0)
if (forceRebake)
{
GenSmoothedNormalsToUV8(mesh);
}
else
{
// only generate if uv#8 is missing and unused
// to prevent overwriting user's data / NiloToon editor generated uv8 data
if (mesh != null && mesh.uv8.Length == 0)
{
GenSmoothedNormalsToUV8(mesh);
}
}
}
foreach (var item in inputGO.GetComponentsInChildren<MeshFilter>())

View File

@ -16,33 +16,40 @@ namespace NiloToon.NiloToonURP
[Header("Main Light - Tint Color")]
[OverrideDisplayName("Enable?")]
[Revertible]
public bool enableMainLightTintColor = false;
[DisableIf("enableMainLightTintColor",false)]
[OverrideDisplayName(" Color")]
[Revertible]
public Color mainLightTintColor = Color.white;
[DisableIf("enableMainLightTintColor",false)]
[OverrideDisplayName(" Intensity")]
[Revertible]
public float mainLightIntensityMultiplier = 1;
//-----------------------------------------------------------------------------
[Header("Main Light - Tint Color (by Light)")]
[OverrideDisplayName("Enable?")]
[Revertible]
public bool enableMainLightTintColorByLight = false;
[DisableIf("enableMainLightTintColorByLight",false)]
[OverrideDisplayName(" Strength")]
[Revertible]
[Range(0,1)]
public float mainLightTintColorByLight_Strength = 1;
[DisableIf("enableMainLightTintColorByLight",false)]
[OverrideDisplayName(" From Light")]
//[Revertible] // won't work for reference type field
public Light mainLightTintColorByLight_Target = null;
[DisableIf("enableMainLightTintColorByLight",false)]
[OverrideDisplayName(" Desaturate")]
[Revertible]
[Range(0,1)]
public float mainLightTintColorByLight_Desaturate = 0;
@ -50,33 +57,40 @@ namespace NiloToon.NiloToonURP
[Header("Main Light - Add Color")]
[OverrideDisplayName("Enable?")]
[Revertible]
public bool enableMainLightAddColor = false;
[DisableIf("enableMainLightAddColor",false)]
[OverrideDisplayName(" Color")]
[Revertible]
public Color mainLightAddColor = Color.black;
[DisableIf("enableMainLightAddColor",false)]
[OverrideDisplayName(" Intensity")]
[Revertible]
public float mainLightAddColorIntensity = 1;
//-----------------------------------------------------------------------------
[Header("Main Light - Add Color (by Light)")]
[OverrideDisplayName("Enable?")]
[Revertible]
public bool enableMainLightAddColorByLight = false;
[DisableIf("enableMainLightAddColorByLight",false)]
[OverrideDisplayName(" Strength")]
[Revertible]
[Range(0,1)]
public float mainLightAddColorByLight_Strength = 1;
[DisableIf("enableMainLightAddColorByLight",false)]
[OverrideDisplayName(" From Light")]
//[Revertible] // won't work for reference type field
public Light mainLightAddColorByLight_Target = null;
[DisableIf("enableMainLightAddColorByLight",false)]
[OverrideDisplayName(" Desaturate")]
[Revertible]
[Range(0,1)]
public float mainLightAddColorByLight_Desaturate = 0;
@ -85,6 +99,7 @@ namespace NiloToon.NiloToonURP
[HelpBox("- When List is empty, this script will apply to all characters.\n" +
"- When List is not empty, this script will only apply to target characters in the list.")]
[OverrideDisplayName("Enabled?")]
[Revertible]
public bool enableTargetCharacterMask = true;
[OverrideDisplayName(" Mask")]

View File

@ -20,20 +20,27 @@ namespace NiloToon.NiloToonURP
[Header("OverrideTiming")]
[OverrideDisplayName("Timing")]
[Revertible]
public OverrideTiming overrideTiming = OverrideTiming.BeforeVolumeOverride;
[Header("Direction")]
[OverrideDisplayName("Override?")]
[Revertible]
public bool overrideDirection = true;
[Header("Color & Intensity")]
[OverrideDisplayName("Override?")]
[Revertible]
public bool overrideColorAndIntensity = true;
[DisableIf("overrideColorAndIntensity")]
[OverrideDisplayName(" Color")]
[Revertible]
public Color color = Color.white;
[DisableIf("overrideColorAndIntensity")]
[OverrideDisplayName(" Intensity")]
[Revertible]
public float intensity = 1;
[Header("Priority")]
@ -41,6 +48,7 @@ namespace NiloToon.NiloToonURP
/// The Overrider priority. A higher value means higher priority. This supports negative values.
/// </summary>
[Tooltip("When multiple active overriders with the same 'Timing' exist in scene, NiloToon uses this value to determine which overrider to use. The overrider with the highest Priority value will be used, other overriders will be ignored.")]
[Revertible]
public float priority = 0;
/// <summary>

View File

@ -20,16 +20,20 @@ namespace NiloToon.NiloToonURP
"- When it is 1, target lights are main light (default result)\n" +
"- When it is 0, target lights are 'Additive / Rim Light' only light\n\n" +
"Default: 1")]
[Revertible]
public float contributeToMainLightColor = 1;
[OverrideDisplayName(" Desaturate")]
[Revertible]
[Range(0, 1)]
[Tooltip("Should target lights desaturate its color before contributing to character's main light color?\n\n" +
"- When the light color has very high saturation, you can increase the desaturation to make the character's lighting result become more natural\n\n" +
"Default: 0")]
public float applyDesaturateWhenContributeToMainLightColor = 0;
[OverrideDisplayName(" Back Light Occlusion (2D)")]
[Revertible]
[Range(0, 1)]
[Tooltip("When a light is from the back side of the character in camera view, should that light be occluded by the character? (occlude the back light in a 2D way, without using character's normal)\n\n" +
"- When it is 0, a back light will completely pass through the character without any occlusion (default result)\n" +
@ -38,6 +42,7 @@ namespace NiloToon.NiloToonURP
public float backLightOcclusion2DWhenContributeToMainLightColor = 0;
[OverrideDisplayName(" Back Light Occlusion (3D)")]
[Revertible]
[Range(0, 1)]
[Tooltip("When a light is from the back side of the character in camera view, should that light be occluded by the character? (occlude the back light in a 3D way, using character's normal)\n\n" +
"- When it is 0, a back light will completely pass through the character without any occlusion (default result)\n" +
@ -46,6 +51,7 @@ namespace NiloToon.NiloToonURP
public float backLightOcclusion3DWhenContributeToMainLightColor = 0;
[OverrideDisplayName("Direction")]
[Revertible]
[Range(0,1)]
[Tooltip("NiloToon will weighted sum all light's direction and use the average direction as main light's direction.\n\n" +
"- When it is 1, target lights will be considered in the light direction weighted sum, hence affecting the result main light direction\n" +
@ -57,7 +63,15 @@ namespace NiloToon.NiloToonURP
[Header("Contribution To Additive/Rim Light")]
[OverrideDisplayName("Intensity")]
[Tooltip("Default: 1")]
[Revertible]
public float contributeToAdditiveOrRimLightIntensity = 1;
//-----------------------------------------------------------------------------
[Header("Rendering Layer (Additional lights)")]
[Tooltip("When enabled, this light will ignore Rendering Layer settings for NiloToon characters.\n\n" +
"Default: false")]
[Revertible]
public bool ignoreRenderingLayer = false;
//-----------------------------------------------------------------------------
[Header("Light Mask")]
@ -65,11 +79,52 @@ namespace NiloToon.NiloToonURP
"- When disabled, this script will apply to all Unity Lights.")]
[Tooltip("Default: true")]
[OverrideDisplayName("Enabled?")]
[Revertible]
public bool enableTargetLightMask = true;
[DisableIf("enableTargetLightMask")]
[OverrideDisplayName(" Target Lights List")]
//[Revertible]
public List<Light> targetLightsMask = new();
// Preset methods for editor
public void ApplyDefaultPreset()
{
contributeToMainLightColor = 1;
applyDesaturateWhenContributeToMainLightColor = 0;
backLightOcclusion2DWhenContributeToMainLightColor = 0;
backLightOcclusion3DWhenContributeToMainLightColor = 0;
contributeToMainLightDirection = 1;
contributeToAdditiveOrRimLightIntensity = 1;
}
public void ApplyColorAndRimLightOnlyPreset()
{
contributeToMainLightColor = 1;
contributeToMainLightDirection = 0;
contributeToAdditiveOrRimLightIntensity = 1;
}
public void ApplyColorOnlyPreset()
{
contributeToMainLightColor = 1;
contributeToMainLightDirection = 0;
contributeToAdditiveOrRimLightIntensity = 0;
}
public void ApplyRimLightOnlyPreset()
{
contributeToMainLightColor = 0;
contributeToMainLightDirection = 0;
contributeToAdditiveOrRimLightIntensity = 1;
}
public void ApplyNoEffectPreset()
{
contributeToMainLightColor = 0;
contributeToMainLightDirection = 0;
contributeToAdditiveOrRimLightIntensity = 0;
}
private void OnEnable()
{
@ -170,13 +225,117 @@ namespace NiloToon.NiloToonURP
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox(
"This script controls how each Unity light source affects NiloToon character(s)\n\n" +
"This script controls how each Unity light source affects NiloToon character(s)\n\n" +
"NiloToon combines all active NiloToonLightSourceModifiers for each light source in the background." +
"The final modifier settings are then applied to the corresponding Unity Light," +
"influencing the lighting of all NiloToon characters affected by that light.", MessageType.Info);
// Add preset buttons section
EditorGUILayout.Space();
EditorGUILayout.LabelField("Presets", EditorStyles.boldLabel);
// Calculate if we should use vertical layout based on inspector width
float inspectorWidth = EditorGUIUtility.currentViewWidth;
bool useVerticalLayout = inspectorWidth < 400; // Switch to vertical when less than 400 pixels
// For narrow windows, use 2-column grid layout
if (useVerticalLayout)
{
// First row
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Reset to Default", GUILayout.Height(25)))
{
ApplyPreset("Default", (modifier) => modifier.ApplyDefaultPreset());
}
if (GUILayout.Button("Color+Rim", GUILayout.Height(25)))
{
ApplyPreset("Color+Rim Light Only", (modifier) => modifier.ApplyColorAndRimLightOnlyPreset());
}
EditorGUILayout.EndHorizontal();
// Second row
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Color Only", GUILayout.Height(25)))
{
ApplyPreset("Color Only", (modifier) => modifier.ApplyColorOnlyPreset());
}
if (GUILayout.Button("Rim Only", GUILayout.Height(25)))
{
ApplyPreset("Rim Light Only", (modifier) => modifier.ApplyRimLightOnlyPreset());
}
EditorGUILayout.EndHorizontal();
// Third row
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("No Effect", GUILayout.Height(25)))
{
ApplyPreset("No Effect", (modifier) => modifier.ApplyNoEffectPreset());
}
GUILayout.FlexibleSpace(); // Fill remaining space
EditorGUILayout.EndHorizontal();
}
else
{
// Wide window - show all buttons in one row
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Reset to Default", GUILayout.Height(25)))
{
ApplyPreset("Default", (modifier) => modifier.ApplyDefaultPreset());
}
if (GUILayout.Button("Color+Rim", GUILayout.Height(25)))
{
ApplyPreset("Color+Rim Light Only", (modifier) => modifier.ApplyColorAndRimLightOnlyPreset());
}
if (GUILayout.Button("Color Only", GUILayout.Height(25)))
{
ApplyPreset("Color Only", (modifier) => modifier.ApplyColorOnlyPreset());
}
if (GUILayout.Button("Rim Only", GUILayout.Height(25)))
{
ApplyPreset("Rim Light Only", (modifier) => modifier.ApplyRimLightOnlyPreset());
}
if (GUILayout.Button("No Effect", GUILayout.Height(25)))
{
ApplyPreset("No Effect", (modifier) => modifier.ApplyNoEffectPreset());
}
EditorGUILayout.EndHorizontal();
}
// Add a small help box explaining the presets
EditorGUILayout.HelpBox(
"• Reset to Default: Color=1, Direction=1, Rim=1\n" +
"• Color+Rim: Color=1, Direction=0, Rim=1\n" +
"• Color Only: Color=1, Direction=0, Rim=0\n" +
"• Rim Only: Color=0, Direction=0, Rim=1\n" +
"• No Effect: Color=0, Direction=0, Rim=0",
MessageType.None);
EditorGUILayout.Space();
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
EditorGUILayout.Space();
DrawDefaultInspector();
}
private void ApplyPreset(string presetName, System.Action<NiloToonLightSourceModifier> applyAction)
{
Undo.RecordObjects(targets, $"Apply {presetName} Preset");
foreach (var t in targets)
{
var modifier = t as NiloToonLightSourceModifier;
if (modifier != null)
{
applyAction(modifier);
EditorUtility.SetDirty(modifier);
}
}
}
}
#endif
}

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.XR;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering;
@ -15,18 +16,36 @@ namespace NiloToon.NiloToonURP
[ExecuteAlways]
public class NiloToonPerCharacterRenderController : MonoBehaviour
{
static readonly string PlayerPrefsKey_NiloToonNeedPreserveEditorPlayModeMaterialChange = "NiloToonPreserveEditorPlayModeMaterialChange";
#if UNITY_EDITOR
static readonly string PlayerPrefsKey_NiloToonNeedPreserveEditorPlayModeMaterialChange = "NiloToonPreserveEditorPlayModeMaterialChange";
// cache to avoid calling PlayerPrefs.GetInt per frame,in order to speed up editor
private static bool? _cachedPreserveEditorPlayMode;
// clear cache, user may disable domain reload
[InitializeOnEnterPlayMode]
static void OnEnterPlayMode()
{
// Clear cache when entering play mode to ensure fresh read
_cachedPreserveEditorPlayMode = null;
}
public static bool GetNiloToonNeedPreserveEditorPlayModeMaterialChange_EditorOnly()
{
return PlayerPrefs.GetInt(PlayerPrefsKey_NiloToonNeedPreserveEditorPlayModeMaterialChange) == 1;
if (_cachedPreserveEditorPlayMode == null)
{
_cachedPreserveEditorPlayMode = PlayerPrefs.GetInt(PlayerPrefsKey_NiloToonNeedPreserveEditorPlayModeMaterialChange) == 1;
}
return _cachedPreserveEditorPlayMode.Value;
}
public static void SetNiloToonNeedPreserveEditorPlayModeMaterialChange_EditorOnly(bool preserveEditorPlayModeMaterialChange)
{
PlayerPrefs.SetInt(PlayerPrefsKey_NiloToonNeedPreserveEditorPlayModeMaterialChange, preserveEditorPlayModeMaterialChange ? 1 : 0);
_cachedPreserveEditorPlayMode = preserveEditorPlayModeMaterialChange;
}
#endif
public enum RefillRenderersMode
{
Always,
@ -229,6 +248,19 @@ namespace NiloToon.NiloToonURP
[RangeOverrideDisplayName(" Method",0, 1)]
public float fixFaceNormalUseFlattenOrProxySphereMethod = 0.75f;
//------------------------------------------------------------
/*
[Foldout("Foot Shadow")]
[Tooltip(
"You should assign character's foot bone transforms here, it will affect foot shadow.\n\n" +
"Click \"Auto Setup this character\" button may fill this correctly.\n" +
"If your model has \"foot\" bone with name \"foot\", usually clicking \"Auto Setup this character\" button will assign it for you already, so you don't need to edit this.\n\n" +
"Name: footTransforms\n" +
"Default: Empty")]
[OverrideDisplayName("Foots")]
public List<Transform> footTransforms;
*/
//------------------------------------------------------------
[Foldout("Bounding Sphere")]
[Tooltip(
@ -694,9 +726,10 @@ namespace NiloToon.NiloToonURP
[RangeOverrideDisplayName(" NormalScaleFix", 0, 16)]
public float ditherNormalScaleFix = 1;
//-------------------------------------------------------------------------
[Foldout("Dissolve (PlayMode)")]
// WIP
/*
[Foldout("Dissolve (PlayMode)")]
[Tooltip(
"Enable to force NiloToon material always enable dissolve keywords in playmode.\n\n" +
@ -1174,35 +1207,50 @@ namespace NiloToon.NiloToonURP
{
// it is possible that the bone doesn't exist in the character,
// which will waste the CPU time checking per frame
// so we only allow the check in editor
// so we only allow the check in editor
Profiler.BeginSample("AutoFillInMissingProperties");
if (!Application.isPlaying)
{
AutoFillInMissingProperties();
}
Profiler.EndSample();
// must call this first before others, because others rely on this
Profiler.BeginSample("CacheCurrentFrameCalculations");
CacheCurrentFrameCalculations();
Profiler.EndSample();
Profiler.BeginSample("UpdateRequireMaterialSetFlags");
UpdateRequireMaterialSetFlags();
Profiler.EndSample();
// auto clear ExternalRenderOverrider to null, if not needed anymore
Profiler.BeginSample("ExternalRenderOverrider");
if (ExternalRenderOverrider)
{
// if ExternalRenderOverrider removed this controller already
if (!ExternalRenderOverrider.targets.Contains(this))
ExternalRenderOverrider = null;
}
Profiler.EndSample();
// register this character into global character list
Profiler.BeginSample("AddCharIfNotExist");
NiloToonAllInOneRendererFeature.AddCharIfNotExist(this);
Profiler.EndSample();
Profiler.BeginSample("RefillAllRenderersIfNeeded");
RefillAllRenderersIfNeeded();
Profiler.EndSample();
Profiler.BeginSample("ShouldEditMaterial");
// https://docs.unity3d.com/ScriptReference/ExecuteAlways.html
// If a MonoBehaviour runs Play logic in Play Mode and fails to check if its GameObject is part of the playing world,
// a Prefab being edited in Prefab Mode may incorrectly get modified and saved by logic intended only to be run as part of the game.
bool shouldEditMaterial = Application.isPlaying && Application.IsPlaying(gameObject);
#if UNITY_EDITOR
// shouldEditMaterial can be overridden if user enable "Keep mat edit in playmode?" in [MenuItem("Window/NiloToonURP/Debug Window")]
// In build, NiloToon always use SRPBatching (make material instances and edit materials directly), because there is almost no reason to not use it in build
@ -1219,7 +1267,9 @@ namespace NiloToon.NiloToonURP
{
shouldEditMaterial = false;
}
Profiler.EndSample();
Profiler.BeginSample("Per renderer work: material/MPB set");
if (shouldEditMaterial)
{
////////////////////////////////////////////////////////////////////////////////
@ -1302,6 +1352,7 @@ namespace NiloToon.NiloToonURP
// since NiloToonRendererRedrawer already use the material property block of the original Renderer
// (X)
}
Profiler.EndSample();
forceMaterialIgnoreCacheAndUpdate = false; // each frame reset, will turn on again when needed
@ -1311,7 +1362,9 @@ namespace NiloToon.NiloToonURP
lastFrameShouldEditMaterial = shouldEditMaterial;
CacheProprtiesForNextFrameOptimizationCheck();
Profiler.BeginSample("CachePropertiesForNextFrameOptimizationCheck");
CachePropertiesForNextFrameOptimizationCheck();
Profiler.EndSample();
// when allRenderers list changed, force update once to ensure all material set
if (refillAllRenderersRequired || requestForceMaterialUpdate /*|| !allowCacheSystem*/)
@ -1481,6 +1534,10 @@ namespace NiloToon.NiloToonURP
for (int i = 0; i < allRenderersFound.Count; i++)
{
Renderer renderer = allRenderersFound[i];
// we don't want to add particle/vfx/trail....renderers
if(!(renderer is MeshRenderer or SkinnedMeshRenderer)) continue;
var NiloToonPerCharacterRenderControllerFound = renderer.transform.GetComponentInParent<NiloToonPerCharacterRenderController>();
if(NiloToonPerCharacterRenderControllerFound)
{
@ -1690,10 +1747,10 @@ namespace NiloToon.NiloToonURP
ShouldEnableDissolve_RequireKeywordChangeCall = ShouldEnableDissolve_Cache != GetShouldEnableDissolve();
ShouldEnablePerCharacterBaseMapOverride_RequireKeywordChangeCall = ShouldEnablePerCharacterBaseMapOverride_Cache != GetShouldEnablePerCharacterBaseMapOverride();
}
private void CacheProprtiesForNextFrameOptimizationCheck()
private void CachePropertiesForNextFrameOptimizationCheck()
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// save this frame's value in cache, for next frame's optimization
// save this frame's value in cache, for next frame's dirty check optimization
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
renderCharacter_Cache = renderCharacter;
controlledByNiloToonPerCharacterRenderController_Cache = true;
@ -2418,6 +2475,17 @@ namespace NiloToon.NiloToonURP
// should we produce a warning here if we can't find any head/neck bone?
// = no, since this function can run on non-characters
}
/*
void SearchAllFootBones(Transform footSearchStartTransform)
{
// Block colliders or special nodes
string[] banned = { "collider", "Footsteps" };
NiloToonUtils.DepthSearchAllAddUnique(footSearchStartTransform, "foot", banned, footTransforms);
NiloToonUtils.DepthSearchAllAddUnique(footSearchStartTransform, "Ankle", banned, footTransforms);
}
*/
// 1. find hip/pelvis bone first, full search from script transform
SearchHipBone(transform);
@ -2453,6 +2521,28 @@ namespace NiloToon.NiloToonURP
// Don't always call AutoFillInFaceForwardDirAndFaceUpDir(),
// only call in auto setup, or when headbone is auto assigned
// it will produce wrong result when character is in motion, where character GO root forward is not always face forward
//---------------------------------
/*
if (footTransforms == null) footTransforms = new List<Transform>();
// 3a. find all foots
if (footTransforms.Count == 0 && customCharacterBoundCenter)
{
// usually foot bone is a child of hip bone's parent transform
Transform startTransform = customCharacterBoundCenter.parent;
if (startTransform == null)
{
startTransform = customCharacterBoundCenter;
}
SearchAllFootBones(startTransform);
}
// 3b. if still no foot, search from root instead
if (footTransforms.Count == 0)
{
SearchAllFootBones(transform);
}
*/
}
public void AutoFillInFaceForwardDirAndFaceUpDir()

View File

@ -81,11 +81,13 @@ namespace NiloToon.NiloToonURP
[Header("Sync options")]
[Tooltip("Should this script also stop rendering when the Renderer of this GameObject is disabled?")]
[Revertible]
public bool deactivateWithRenderer = true;
[Header("Optimization")]
[Tooltip("Should this script also stop rendering when the Renderer of this GameObject is not visible by any camera?\n" +
"*Please note that the editor scene window camera is considered also. To profile the game window CPU/GPU performance, you should hide the scene window.")]
[Revertible]
public bool deactivateWhenRendererIsNotVisible = true;
private NiloToonPerCharacterRenderController _niloToonPerCharacterRenderController;

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Serialization;
namespace NiloToon.NiloToonURP
{
@ -27,6 +28,10 @@ namespace NiloToon.NiloToonURP
[Header("Motion Blur")]
public NiloToonMotionBlurPass.Settings motionBlurSettings = new NiloToonMotionBlurPass.Settings();
[Header("Prepass Buffer")]
[Revertible]
public bool forceRenderPrepassBuffer = false;
[Header("Override Shader stripping")]
[OverrideDisplayName("Shader Stripping Settings")]
[Tooltip("This slot is useful when you are in the following situation:\n" +
@ -150,7 +155,7 @@ namespace NiloToon.NiloToonURP
// (ToonOutlinePass_RightAfterTransparent) After Transparent (= After RenderQueue 5000)
//---------------------------------------
ToonOutlinePass.renderPassEvent = RenderPassEvent.AfterRenderingSkybox; // use AfterRenderingSkybox instead of BeforeRenderingSkybox, to make "semi-transparent(ZWrite) + outline" blend with skybox correctly
ToonOutlinePass_RightAfterTransparent.renderPassEvent = RenderPassEvent.BeforeRenderingTransparents + 1; // right after transparent materials finish drawing, draw this outline pass
ToonOutlinePass_RightAfterTransparent.renderPassEvent = RenderPassEvent.AfterRenderingTransparents + 0; // right after transparent materials finish drawing, draw this outline pass
ExtraThickOutlinePass.renderPassEvent = settings.outlineSettings.extraThickOutlineRenderTiming; // default use AfterRenderingTransparents, because we want this outline not being blocked by transparent effects
@ -204,6 +209,12 @@ namespace NiloToon.NiloToonURP
if (settings.MiscSettings.EnableSkyboxDrawBeforeOpaque && renderingData.cameraData.camera.clearFlags == CameraClearFlags.Skybox)
renderer.EnqueuePass(SkyboxRedrawBeforeOpaquePass);
//--------------------------------------------------------------------------
// skip prepass buffer when all condition meet:
// - no NiloToonBloom
// - no NiloToonTonemapping
// - no character is using [Color Fill] feature
// - no force render
var tonemappingEffect = VolumeManager.instance.stack.GetComponent<NiloToonTonemappingVolume>();
var bloomEffect = VolumeManager.instance.stack.GetComponent<NiloToonBloomVolume>();
@ -211,7 +222,7 @@ namespace NiloToon.NiloToonURP
isAnyNiloPostEnabled |= tonemappingEffect.IsActive();
isAnyNiloPostEnabled |= bloomEffect.IsActive() && settings.uberPostProcessSettings.allowRenderNiloToonBloom;
// optimization when no character is using Color Fill feature
bool isAnyNiloToonPerCharacterScriptRequiresPrepass = false;
foreach (var characterRenderController in characterList)
{
@ -228,11 +239,14 @@ namespace NiloToon.NiloToonURP
bool shouldDrawPrepass = renderingData.cameraData.postProcessEnabled && isAnyNiloPostEnabled;
shouldDrawPrepass |= isAnyNiloToonPerCharacterScriptRequiresPrepass;
shouldDrawPrepass |= settings.forceRenderPrepassBuffer;
if (shouldDrawPrepass)
{
renderer.EnqueuePass(PrepassBufferRTPass);
}
//--------------------------------------------------------------------------
renderer.EnqueuePass(UberPostProcessPass);
#if UNITY_2022_3_OR_NEWER
if (renderingData.cameraData.postProcessEnabled &&

View File

@ -25,6 +25,7 @@ namespace NiloToon.NiloToonURP
[Serializable]
public class Settings
{
[Revertible]
[Tooltip("Can turn off to prevent rendering NiloToonAnimePostProcessVolume, which will improve performance for low quality graphics setting renderer")]
[OverrideDisplayName("Allow render?")]
public bool allowRender = true;
@ -53,6 +54,9 @@ namespace NiloToon.NiloToonURP
m_ProfilingSampler = new ProfilingSampler("NiloToonAnimePostProcessPass");
}
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
SetRenderPassEvent();
@ -72,6 +76,9 @@ namespace NiloToon.NiloToonURP
}
}
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
Render(context, ref renderingData);

View File

@ -8,6 +8,13 @@ using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;
#endif
#if UNITY_2021 || UNITY_2022
// On old Unity versions, alias our code's GraphicsFormatUsage to FormatUsage
using GraphicsFormatUsage = UnityEngine.Experimental.Rendering.FormatUsage;
#else
using GraphicsFormatUsage = UnityEngine.Experimental.Rendering.GraphicsFormatUsage;
#endif
namespace NiloToon.NiloToonURP
{
public class NiloToonAverageShadowTestRTPass : ScriptableRenderPass
@ -19,6 +26,7 @@ namespace NiloToon.NiloToonURP
[Serializable]
public class Settings
{
[Revertible]
[Tooltip( "If you want NiloToon character to receive URP shadow map in an extremely soft and blurry way(a special URP shadow sampling that is blurry across the whole character, darken the character uniformly), turn this on.\n" +
"When turned on, character won't receive main directional light's direct lighting when occluded by URP's shadow casters (e.g. character completely under a bridge, where the bridge is casting URP shadow).\n\n" +
"Default is OFF, since some users don't want this kind of shadow ON by default when character is completely indoor")]
@ -63,6 +71,9 @@ namespace NiloToon.NiloToonURP
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in a performant manner.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
// [possible optimization note]
@ -109,15 +120,15 @@ namespace NiloToon.NiloToonURP
// Some Samsung phones didn't support GraphicsFormat.R16_UNorm, so we need to do a full fallback chain
// Devices that can't support R16_UNorm = Galaxy S8, S7, and S21
if(SystemInfo.IsFormatSupported(GraphicsFormat.R16_UNorm,FormatUsage.Render))
if(SystemInfo.IsFormatSupported(GraphicsFormat.R16_UNorm,GraphicsFormatUsage.Render))
{
renderTextureDescriptor.graphicsFormat = GraphicsFormat.R16_UNorm;
}
else if (SystemInfo.IsFormatSupported(GraphicsFormat.R8_UNorm, FormatUsage.Render))
else if (SystemInfo.IsFormatSupported(GraphicsFormat.R8_UNorm, GraphicsFormatUsage.Render))
{
renderTextureDescriptor.graphicsFormat = GraphicsFormat.R8_UNorm;
}
else if (SystemInfo.IsFormatSupported(GraphicsFormat.R8G8B8A8_UNorm, FormatUsage.Render))
else if (SystemInfo.IsFormatSupported(GraphicsFormat.R8G8B8A8_UNorm, GraphicsFormatUsage.Render))
{
renderTextureDescriptor.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm;
}
@ -127,6 +138,9 @@ namespace NiloToon.NiloToonURP
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (!shouldRenderRT(renderingData.cameraData.camera)) return;
@ -155,8 +169,7 @@ namespace NiloToon.NiloToonURP
// remove this when the problem is solved
#if UNITY_WEBGL
return false;
#endif
#else
if (camera.cameraType == CameraType.Preview)
return false;
@ -165,6 +178,7 @@ namespace NiloToon.NiloToonURP
// in NiloToon 0.11.1, we changed the merge method from simple override to a "&&" merge, so renderer feature can force disable all average shadow even if volume has overridden and enabled it.
bool enableAverageShadow = shadowControlVolumeEffect.enableCharAverageShadow.value && settings.enableAverageShadow;
return enableAverageShadow;
#endif
}
private void renderPerCharacterAverageShadowAtlaRT(ScriptableRenderContext context, RenderingData renderingData)
{

View File

@ -42,6 +42,7 @@ namespace NiloToon.NiloToonURP
"- Very bad for a group of visible characters that are far away from each other, shadow artifacts will appear easily\n\n" +
"Default: ON")]
[OverrideDisplayName("Enable?")]
[Revertible]
public bool enableCharSelfShadow = true;
[Header("> Style")]
@ -50,15 +51,18 @@ namespace NiloToon.NiloToonURP
"Turn it ON if you don't want this shadow affected by camera transform(rotation)\n\n" +
"*Default: ON, since many user expect it to act the same as URP's shadow casting direction by default")]
[OverrideDisplayName("MainLight as Shadow Dir?")]
[Revertible]
public bool useMainLightAsCastShadowDirection = true;
[Tooltip( "Only useful if 'MainLight as Shadow Dir?' is OFF.\n\n" +
"Default: 30 (30 degrees pointing downward)")]
[Revertible]
[RangeOverrideDisplayName(" Vertical angle",-90, 90)]
public float shadowAngle = 30f;
[Tooltip( "Only useful if 'MainLight as Shadow Dir?' is OFF.\n\n" +
"Default: 0 (0 degrees, no rotation to left or right by default")]
[Revertible]
[RangeOverrideDisplayName(" Horizontal angle", -90, 90)]
public float shadowLRAngle = 0;
@ -66,28 +70,37 @@ namespace NiloToon.NiloToonURP
[Tooltip( "The higher the better(shadow quality), but larger shadow map size = GPU slower.\n" +
"*You will want to max it when making high quality editor recordings (e.g. using Recorder)\n\n" +
"Default: 4096")]
[Revertible]
[RangeOverrideDisplayName("Resolution",256, 16384)]
public int shadowMapSize = 4096;
[Tooltip( "Enable to make shadow blurrier with nice AA, but adding more GPU cost\n\n" +
"Default: true")]
[OverrideDisplayName("Soft Shadow?")]
[Revertible]
public bool useSoftShadow = true;
[Tooltip( "Blurriness of soft shadow, the higher the blurrier and slower in GPU\n\n" +
"Default: Low")]
[Revertible]
[OverrideDisplayName(" Quality")]
public SoftShadowQuality softShadowQuality = SoftShadowQuality.Medium;
[Tooltip( "Enable to resharpen the result of soft shadow to produce a more cel-shade look\n\n" +
"Default: false")]
[OverrideDisplayName(" Resharpen?")]
[Revertible]
public bool useSoftShadowResharpen = false;
[Tooltip( "Strength of the resharpen, the higher the sharper\n\n" +
"Default: 0.5")]
[OverrideDisplayName(" Strength")]
[Revertible]
[Range(0, 1)]
public float resharpenStregth = 0.5f;
[Header("> Fix shadow artifacts options")]
[Revertible]
[Tooltip("The shorter the range, the higher the quality of shadow rendering, but characters outside the range will not render/receive shadows\n\n" +
"Default: 5(meter), shadowRange starts from the first visible character, not from the camera.")]
[Range(SHADOW_RANGE_MIN, SHADOW_RANGE_MAX)]
@ -95,6 +108,7 @@ namespace NiloToon.NiloToonURP
[Tooltip( "The higher the depthBias, the less artifact(shadow acne) will appear, but more Peter panning will appear\n\n" +
"Default: 1")]
[Revertible]
[Range(0, 10)]
public float depthBias = 1f;
@ -102,22 +116,26 @@ namespace NiloToon.NiloToonURP
"*but higher = more shadow caster model deform will appear (e.g. very thin finger in shadow map)\n" +
"*You can set it to 0 if this is producing more shadow acne artifact instead, usually it may happen on flat cloth double side surface.\n\n" +
"Default: 0.5")]
[Revertible]
[Range(0, 4)]
public float normalBias = 0.5f;
[Tooltip( "The higher the receiverDepthBias, the less artifact(shadow acne) will appear, but more Peter panning will appear\n" +
"*This is the shadow receiver's shadow test position depth bias, it will not affect the shadow caster's bias.\n\n" +
"Default: 1")]
[Revertible]
[Range(0,10)]
public float receiverDepthBias = 1f;
[Tooltip( "The inflate amount of shadow receiver's shadow test position. The higher the receiverNormalBias, the less artifact(shadow acne) will appear.\n" +
"Unlike the shadowcaster's normal bias, this will not change the shape of shadow caster, so you can use a much bigger value if shadow acne appears.\n\n" +
"Default: 1")]
[Revertible]
[Range(0,10)]
public float receiverNormalBias = 1f;
[Tooltip( "Apply an additional local diffuse(dot(N,L)) cel shading to hide more shadowmap's artifact(shadow acne).\n\n" +
"Default: On")]
[Revertible]
public bool useNdotLFix = true;
[Tooltip( "Extra CPU culling to improve shadow correctness for making sure shadow caster that is not visible still render shadow map correctly, " +
@ -125,6 +143,7 @@ namespace NiloToon.NiloToonURP
"Disable this if you find that it affects other plugin's rendering.(e.g., Volumetric Light Beam's SRP Batcher Mode may not work if you enable this toggle.\n\n" +
"Default: On")]
[OverrideDisplayName("High Quality Culling")]
[Revertible]
public bool perfectCullingForShadowCasters = true;
[Header("> If Unity crash (terrain), enable it!")]
@ -134,6 +153,7 @@ namespace NiloToon.NiloToonURP
"If you use terrain, and don't want any GC alloc, turn off this and 'High Quality Culling' together\n\n" +
"Default: ON")]
[OverrideDisplayName("UnityCrash Safe Guard")]
[Revertible]
public bool terrainCrashSafeGuard = true;
}
public Settings settings { get; }
@ -177,6 +197,9 @@ namespace NiloToon.NiloToonURP
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in a performant manner.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
var volumeEffect = VolumeManager.instance.stack.GetComponent<NiloToonShadowControlVolume>();
@ -209,6 +232,9 @@ namespace NiloToon.NiloToonURP
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
renderCharacterSelfShadowmapRT(context, renderingData);

View File

@ -1,3 +1,4 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
@ -21,7 +22,9 @@ namespace NiloToon.NiloToonURP
renderPassEvent = evt;
}
/// <inheritdoc/>
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CameraData cameraData = renderingData.cameraData;

View File

@ -1,3 +1,4 @@
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
@ -15,6 +16,9 @@ namespace NiloToon.NiloToonURP
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in a performant manner.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
// do nothing
@ -24,6 +28,9 @@ namespace NiloToon.NiloToonURP
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
// Never draw in Preview
@ -88,9 +95,50 @@ namespace NiloToon.NiloToonURP
// RenderQueueRange.Transparent should not be considered, since alpha can be 0~1, but stencil draw bit is 0/1 only
// Imagine a character with mostly transparent cloths where many pixels using 0~0.5 alpha for alpha blending, it will destroy all stencil-related rendering if we use RenderQueueRange.all
// optimization, check for all Nilo char, only render pass if needed
bool needColorFill = false;
bool needExtraThickOutline = false;
var characters = NiloToonAllInOneRendererFeature.characterList;
// early exit if list is null or empty
if (characters == null || characters.Count == 0)
return;
// Use an index-based loop to avoid foreach allocations
for (int i = 0, count = characters.Count; i < count; i++)
{
var c = characters[i];
if (c == null)
continue;
// Skip inactive or non-hierarchy objects quickly
if (!c.isActiveAndEnabled || !c.gameObject.activeInHierarchy)
continue;
// Check rendering flags
if (!needColorFill && c.shouldRenderCharacterAreaColorFill)
needColorFill = true;
if (!needExtraThickOutline && c.shouldRenderExtraThickOutline)
needExtraThickOutline = true;
// Stop checking once both are required
if (needColorFill && needExtraThickOutline)
break;
}
// No need to run any pass if neither is required
if (!needColorFill && !needExtraThickOutline)
return;
renderPass_NiloToonCharacterAreaStencilBufferFill(context, renderingData);
renderPass_NiloToonExtraThickOutline(context, renderingData);
renderPass_NiloToonCharacterAreaColorFill(context, renderingData);
if(needExtraThickOutline)
renderPass_NiloToonExtraThickOutline(context, renderingData);
if(needColorFill)
renderPass_NiloToonCharacterAreaColorFill(context, renderingData);
}
private void renderPass_NiloToonCharacterAreaColorFill(ScriptableRenderContext context, RenderingData renderingData)
@ -201,12 +249,68 @@ namespace NiloToon.NiloToonURP
// RenderQueueRange.Transparent should not be considered, since alpha can be 0~1, but stencil draw bit is 0/1 only
// Imagine a character with mostly transparent cloths where many pixels using 0~0.5 alpha for alpha blending, it will destroy all stencil-related rendering if we use RenderQueueRange.all
DrawToActiveColorBufferByLightMode(renderGraph, frameContext, "NiloToonCharacterAreaStencilBufferFill", NiloToonCharacterAreaStencilBufferFill_LightModeShaderTagId,
SortingCriteria.CommonOpaque, RenderQueueRange.opaque);
DrawToActiveColorBufferByLightMode(renderGraph, frameContext, "NiloToonExtraThickOutline", NiloToonExtraThickOutline_LightModeShaderTagId,
SortingCriteria.CommonTransparent, RenderQueueRange.opaque);
DrawToActiveColorBufferByLightMode(renderGraph, frameContext, "NiloToonCharacterAreaColorFill", NiloToonCharacterAreaColorFill_LightModeShaderTagId,
SortingCriteria.CommonTransparent, RenderQueueRange.opaque);
// optimization, check for all Nilo char, only render pass if needed
bool needColorFill = false;
bool needExtraThickOutline = false;
var characters = NiloToonAllInOneRendererFeature.characterList;
// early exit if list is null or empty
if (characters == null || characters.Count == 0)
return;
// Use an index-based loop to avoid foreach allocations
for (int i = 0, count = characters.Count; i < count; i++)
{
var c = characters[i];
if (c == null)
continue;
// Skip inactive or non-hierarchy objects quickly
if (!c.isActiveAndEnabled || !c.gameObject.activeInHierarchy)
continue;
// Check rendering flags
if (!needColorFill && c.shouldRenderCharacterAreaColorFill)
needColorFill = true;
if (!needExtraThickOutline && c.shouldRenderExtraThickOutline)
needExtraThickOutline = true;
// Stop checking once both are required
if (needColorFill && needExtraThickOutline)
break;
}
// No need to run any pass if neither is required
if (!needColorFill && !needExtraThickOutline)
return;
DrawToActiveColorBufferByLightMode(
renderGraph,
frameContext,
"NiloToonCharacterAreaStencilBufferFill",
NiloToonCharacterAreaStencilBufferFill_LightModeShaderTagId,
SortingCriteria.CommonOpaque,
RenderQueueRange.opaque);
if(needExtraThickOutline)
DrawToActiveColorBufferByLightMode(
renderGraph,
frameContext,
"NiloToonExtraThickOutline",
NiloToonExtraThickOutline_LightModeShaderTagId,
SortingCriteria.CommonTransparent,
RenderQueueRange.opaque);
if(needColorFill)
DrawToActiveColorBufferByLightMode(
renderGraph,
frameContext,
"NiloToonCharacterAreaColorFill",
NiloToonCharacterAreaColorFill_LightModeShaderTagId,
SortingCriteria.CommonTransparent,
RenderQueueRange.opaque);
}
void DrawToActiveColorBufferByLightMode(RenderGraph renderGraph, ContextContainer frameContext, string passName, ShaderTagId lightMode, SortingCriteria sortFlags, RenderQueueRange renderQueueRange)

View File

@ -10,6 +10,8 @@
// https://github.com/EpicGames/UnrealEngine/tree/release/Engine/Shaders/Private/MotionBlur
// https://john-chapman-graphics.blogspot.com/2013/01/per-object-motion-blur.html
// https://youtu.be/b0S6WMAfi0o?si=8KSxKDHz9Z95VbVt (A Reconstruction Filter for Plausible Motion Blur (I3D 12))
using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
@ -26,6 +28,7 @@ namespace NiloToon.NiloToonURP
[System.Serializable]
public class Settings
{
[Revertible]
public bool allowRender = true;
}
#if UNITY_2022_3_OR_NEWER
@ -77,7 +80,12 @@ namespace NiloToon.NiloToonURP
if (blurMaterial == null)
{
blurMaterial = CoreUtils.CreateEngineMaterial("Hidden/NiloToon/NiloToonKinoMotionBlur");
string shaderPath = "Hidden/NiloToon/NiloToonKinoMotionBlur";
Shader shader = Shader.Find(shaderPath);
if (shader != null)
{
blurMaterial = CoreUtils.CreateEngineMaterial(shader);
}
}
}
@ -94,6 +102,9 @@ namespace NiloToon.NiloToonURP
ConfigureInput(input);
}
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
if(!ShouldRender(renderingData.cameraData.camera)) return;
@ -336,6 +347,9 @@ namespace NiloToon.NiloToonURP
/////////////////////////////////////////////////////////////////////
// NON-RG EXECUTE METHOD - Uses shared algorithm
/////////////////////////////////////////////////////////////////////
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if(!ShouldRender(renderingData.cameraData.camera)) return;

View File

@ -5,8 +5,8 @@
/*
_NiloToonPrepassBufferRT is storing the following data
-r: unused
-g: character visible area (for NiloToon Bloom)
-r: face
-g: character visible area (for NiloToon Bloom / NiloToon Tonemapping)
-b: unused
-a: unused
@ -56,6 +56,9 @@ namespace NiloToon.NiloToonURP
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in a performant manner.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
// When doing prepass rendering, the RT's depth format(depth bit/depthStencilFormat/MSAA) need to be exactly matching formats from _CameraDepthTexture, else when rejecting blocked character pixels(using _CameraDepthTexture) will fail
@ -117,6 +120,9 @@ namespace NiloToon.NiloToonURP
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
// since this pass is only enqueued when conditions are met in NiloToonAllInOneRendererFeature's AddRenderPasses method.

View File

@ -15,6 +15,9 @@ namespace NiloToon.NiloToonURP
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in a performant manner.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
// do nothing
@ -24,6 +27,9 @@ namespace NiloToon.NiloToonURP
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
/*

View File

@ -69,6 +69,9 @@ namespace NiloToon.NiloToonURP
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in a performant manner.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
ConfigureInput(renderingData.cameraData.cameraType);
@ -135,6 +138,9 @@ namespace NiloToon.NiloToonURP
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
renderScreenSpaceOutline(context, renderingData);

View File

@ -38,10 +38,12 @@ namespace NiloToon.NiloToonURP
"- However, if you are using a high-quality/high-resolution URP shadow map (e.g. 4 cascade + 4096 size + 10 Shadow Range), then you can turn this ON if it looks good.\n\n" +
"Default: OFF")]
[OverrideDisplayName("Enable?")]
[Revertible]
public bool ShouldReceiveURPShadows = false;
[Tooltip("Lower this value will fadeout URP shadow map for NiloToon Characters\n\n" +
"Default: 1 (apply 100% URP shadow map)")]
[Revertible]
[RangeOverrideDisplayName(" Intensity",0,1)]
public float URPShadowIntensity = 1;
@ -50,6 +52,7 @@ namespace NiloToon.NiloToonURP
"For example,\n" +
"set to 2(meters) will force all NiloToon characters to only receive URP shadow map casted by far objects(e.g. tree and buildings) and not receiving URP shadow map that was cast by the character himself(self shadow).\n\n" +
"Default: 0 meter")]
[Revertible]
[RangeOverrideDisplayName(" DepthBias Extra",0,2)]
public float URPShadowDepthBias = 0;
@ -59,6 +62,7 @@ namespace NiloToon.NiloToonURP
"- increase it can add more normal bias for removing shadow acne, but shadow caster polygon will become smaller(e.g. very thin finger), and shadow holes may appear.\n\n" +
"You can reset it to 1(default) if you are not sure about what value is good.\n\n" +
"Default: 1 (apply 100% normal bias)")]
[Revertible]
[RangeOverrideDisplayName(" NormalBias Multiplier",0,2)]
public float URPShadowNormalBiasMultiplier = 1;
@ -69,16 +73,19 @@ namespace NiloToon.NiloToonURP
"- turn OFF to fallback to classic fresnel(dot(N,V)) rim light, which will improve performance if you are targeting slow mobile\n\n" +
"Default: ON")]
[OverrideDisplayName("Enable?")]
[Revertible]
public bool EnableDepthTextureRimLigthAndShadow = true;
[Tooltip("Controls the depth texture(screen space) rim light and shadow's width multiplier. You can edit it for artistic reason.\n\n" +
"Default: 1")]
[Revertible]
[RangeOverrideDisplayName(" Width",0,10)]
public float DepthTextureRimLightAndShadowWidthMultiplier = 1;
[Tooltip("How easy is rim light occluded by the character himself? You can increase it for artistic reason.\n" +
"When the value is high enough(e.g. 0.5 meter), rim light will be blocked by the character himself and only appear on the character silhouette edge.\n\n" +
"Default: 0(meter)")]
[Revertible]
[RangeOverrideDisplayName(" Rim Light Self Occlude",0,2)]
public float DepthTexRimLightDepthDiffThresholdOffset = 0;
@ -93,6 +100,7 @@ namespace NiloToon.NiloToonURP
"*If you are very sure you don't need it, turn it off to improve performance.\n\n" +
"Default: ON")]
[OverrideDisplayName("Redraw Skybox before Opaque?")]
[Revertible]
public bool EnableSkyboxDrawBeforeOpaque = true;
//--------------------------------------------------------------------------
@ -101,16 +109,19 @@ namespace NiloToon.NiloToonURP
[Tooltip("Force NiloToonCharacter shader becomes an Unlit shader, used for debug vertex+fragment shader cost of NiloToonCharacter shader.\n\n" +
"Default: OFF")]
[OverrideDisplayName("Min Char shader")]
[Revertible]
public bool ForceMinimumShader = false;
[Tooltip("Force NiloToonEnvironment shader becomes a simple diffuse shader, used for debug vertex+fragment shader cost of NiloToonEnvironment shader.\n\n" +
"Default: OFF")]
[OverrideDisplayName("Min Envi shader")]
[Revertible]
public bool ForceMinimumEnviShader = false;
[Tooltip("Force disable Outline, used for debug the CPU&GPU cost of rendering 'Classic Outline pass'.\n\n" +
"Default: OFF")]
[OverrideDisplayName("Remove outline")]
[Revertible]
public bool ForceNoOutline = false;
}
@ -205,7 +216,12 @@ namespace NiloToon.NiloToonURP
static readonly int _GlobalCinematic3DRimMaskEnabled_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskEnabled");
static readonly int _GlobalCinematic3DRimMaskStrength_ClassicStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskStrength_ClassicStyle");
static readonly int _GlobalCinematic3DRimMaskSharpness_ClassicStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskSharpness_ClassicStyle");
static readonly int _GlobalCinematic3DRimMaskWidth_ClassicStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskWidth_ClassicStyle");
static readonly int _GlobalCinematic3DRimMaskBlur_ClassicStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskBlur_ClassicStyle");
static readonly int _GlobalCinematic3DRimMaskStrength_DynamicStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskStrength_DynamicStyle");
static readonly int _GlobalCinematic3DRimMaskWidth_DynamicStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskWidth_DynamicStyle");
static readonly int _GlobalCinematic3DRimMaskBlur_DynamicStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskBlur_DynamicStyle");
static readonly int _GlobalCinematic3DRimMaskSharpness_DynamicStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskSharpness_DynamicStyle");
static readonly int _GlobalCinematic3DRimMaskStrength_StableStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskStrength_StableStyle");
static readonly int _GlobalCinematic3DRimMaskSharpness_StableStyle_SID = Shader.PropertyToID("_GlobalCinematic3DRimMaskSharpness_StableStyle");
@ -239,6 +255,8 @@ namespace NiloToon.NiloToonURP
static readonly int _GlobalDepthTexRimLightCameraDistanceFadeoutStartDistance_SID = Shader.PropertyToID("_GlobalDepthTexRimLightCameraDistanceFadeoutStartDistance");
static readonly int _GlobalDepthTexRimLightCameraDistanceFadeoutEndDistance_SID = Shader.PropertyToID("_GlobalDepthTexRimLightCameraDistanceFadeoutEndDistance");
static readonly int _GlobalCharacterOverallShadowTintColor_SID = Shader.PropertyToID("_GlobalCharacterOverallShadowTintColor");
static readonly int _GlobalCharacterOverallShadowTintColorForSkinFace_SID = Shader.PropertyToID("_GlobalCharacterOverallShadowTintColorForSkinFace");
static readonly int _GlobalCharacterOverallShadowTintColorForNonSkinFace_SID = Shader.PropertyToID("_GlobalCharacterOverallShadowTintColorForNonSkinFace");
static readonly int _GlobalCharacterOverallShadowStrength_SID = Shader.PropertyToID("_GlobalCharacterOverallShadowStrength");
static readonly int _NiloToonGlobalEnviGITintColor_SID = Shader.PropertyToID("_NiloToonGlobalEnviGITintColor");
@ -262,7 +280,7 @@ namespace NiloToon.NiloToonURP
static readonly int _NiloToonGlobalPerCharMainDirectionalLightAddColorArray_SID = Shader.PropertyToID("_NiloToonGlobalPerCharMainDirectionalLightAddColorArray");
static readonly int _NiloToonGlobalPerUnityLightDataArray_SID = Shader.PropertyToID("_NiloToonGlobalPerUnityLightDataArray");
private static readonly int _NiloToonGlobalPerUnityLightDataArray2_SID = Shader.PropertyToID("_NiloToonGlobalPerUnityLightDataArray2");
static readonly int _NiloToonGlobalPerUnityLightDataArray2_SID = Shader.PropertyToID("_NiloToonGlobalPerUnityLightDataArray2");
// Constructor(will not call every frame)
// *Be careful when calling VolumeManager in constructor, since VolumeManager can be not yet ready to use.
@ -281,6 +299,9 @@ namespace NiloToon.NiloToonURP
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in a performant manner.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
ConfigureInputs(renderingData.cameraData.renderer);
@ -356,11 +377,14 @@ namespace NiloToon.NiloToonURP
return isDeferredRendering;
}
// Here you can implement the rendering logic.
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
setParam(context, renderingData);
@ -778,7 +802,7 @@ namespace NiloToon.NiloToonURP
cmd.SetGlobalFloat(_GlobalAdditionalLightApplyRimMask_SID, c.additionalLightApplyRimMask.value);
cmd.SetGlobalFloat(_GlobalAdditionalLightRimMaskPower_SID, c.additionalLightRimMaskPower.value);
cmd.SetGlobalFloat(_GlobalAdditionalLightRimMaskSoftness_SID, c.additionalLightRimMaskSoftness.value * 0.5f);
cmd.SetGlobalColor(_GlobalAdditionalLightMaxContribution_SID, c.additionalLightMaxContribution.value * c.additionalLightMaxContributionColor.value + Color.white * 100 * (cinematicAdditionalLightVolume.strengthRimMask3D_DynmaicStyle.value+ cinematicAdditionalLightVolume.strengthRimMask3D_StableStyle.value));
cmd.SetGlobalColor(_GlobalAdditionalLightMaxContribution_SID, c.additionalLightMaxContribution.value * c.additionalLightMaxContributionColor.value + Color.white * 100 * (cinematicAdditionalLightVolume.strengthRimMask3D_DynamicStyle.value+ cinematicAdditionalLightVolume.strengthRimMask3D_StableStyle.value));
cmd.SetGlobalColor(_GlobalRimLightMultiplier_SID, c.charRimLightMultiplier.value * c.charRimLightTintColor.value * mainLightRimMultiplier);
cmd.SetGlobalColor(_GlobalRimLightMultiplierForOutlineArea_SID, c.charRimLightMultiplierForOutlineArea.value * c.charRimLightTintColorForOutlineArea.value);
cmd.SetGlobalFloat(_GlobalDepthTexRimLightCameraDistanceFadeoutStartDistance_SID, c.charRimLightCameraDistanceFadeoutStartDistance.value);
@ -787,16 +811,24 @@ namespace NiloToon.NiloToonURP
cmd.SetGlobalFloat(_GlobalSpecularInShadowMinIntensity_SID, c.specularInShadowMinIntensity.value);
cmd.SetGlobalFloat(_GlobalSpecularReactToLightDirectionChange_SID, c.specularReactToLightDirectionChange.value ? 1 : 0);
cmd.SetGlobalColor(_GlobalCharacterOverallShadowTintColor_SID, c.characterOverallShadowTintColor.value * shadowControlVolume.characterOverallShadowTintColor.value);
cmd.SetGlobalColor(_GlobalCharacterOverallShadowTintColorForSkinFace_SID, c.characterOverallShadowTintColorForSkinFace.value * shadowControlVolume.characterOverallShadowTintColorForSkinFace.value);
cmd.SetGlobalColor(_GlobalCharacterOverallShadowTintColorForNonSkinFace_SID, c.characterOverallShadowTintColorForNonSkinFace.value * shadowControlVolume.characterOverallShadowTintColorForNonSkinFace.value);
cmd.SetGlobalFloat(_GlobalCharacterOverallShadowStrength_SID, c.characterOverallShadowStrength.value * shadowControlVolume.characterOverallShadowStrength.value);
//////////////////////////////////////////////////////////////////////////////////////////////////
// global volume (NiloToonCinematicAdditionalLightVolume)
//////////////////////////////////////////////////////////////////////////////////////////////////
float finalCinematic3DStrength_ClassicStyle = Mathf.Pow(cinematicAdditionalLightVolume.strengthRimMask3D_ClassicStyle.value, 0.1f);
float finalCinematic3DStrength_DynamicStyle = Mathf.Pow(cinematicAdditionalLightVolume.strengthRimMask3D_DynmaicStyle.value, 0.1f);
float finalCinematic3DStrength_DynamicStyle = Mathf.Pow(cinematicAdditionalLightVolume.strengthRimMask3D_DynamicStyle.value, 0.1f);
float finalCinematic3DStrength_StableStyle = Mathf.Pow(cinematicAdditionalLightVolume.strengthRimMask3D_StableStyle.value, 0.1f);
float finalCinematic2DStrength = cinematicAdditionalLightVolume.strengthRimMask2D.value;
float finalCinematic3DWidth_ClassicStyle = 1f - cinematicAdditionalLightVolume.widthRimMask3D_ClassicStyle.value;
float finalCinematic3DBlur_ClassicStyle = cinematicAdditionalLightVolume.blurRimMask3D_ClassicStyle.value;
float finalCinematic3Dsharpness_ClassicStyle = Mathf.Lerp(1f, 16f, cinematicAdditionalLightVolume.sharpnessRimMask3D_ClassicStyle.value);
float finalCinematic3DWidth_DynamicStyle = 1f - cinematicAdditionalLightVolume.widthRimMask3D_DynamicStyle.value;
float finalCinematic3DBlur_DynamicStyle = cinematicAdditionalLightVolume.blurRimMask3D_DynamicStyle.value;
float finalCinematic3DSharpness_DynamicStyle = Mathf.Lerp(4f, 19 * 4f, cinematicAdditionalLightVolume.sharpnessRimMask3D_DynamicStyle.value);
// ^5 is the PBR physical power from F term of DFG, which is the lowest power possible
@ -849,7 +881,12 @@ namespace NiloToon.NiloToonURP
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskEnabled_SID, finalCinematicEnabled);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskStrength_ClassicStyle_SID, finalCinematic3DStrength_ClassicStyle);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskSharpness_ClassicStyle_SID, finalCinematic3Dsharpness_ClassicStyle);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskWidth_ClassicStyle_SID,finalCinematic3DWidth_ClassicStyle);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskBlur_ClassicStyle_SID, finalCinematic3DBlur_ClassicStyle);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskStrength_DynamicStyle_SID, finalCinematic3DStrength_DynamicStyle);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskWidth_DynamicStyle_SID, finalCinematic3DWidth_DynamicStyle);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskBlur_DynamicStyle_SID, finalCinematic3DBlur_DynamicStyle);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskSharpness_DynamicStyle_SID, finalCinematic3DSharpness_DynamicStyle);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskStrength_StableStyle_SID, finalCinematic3DStrength_StableStyle);
cmd.SetGlobalFloat(_GlobalCinematic3DRimMaskSharpness_StableStyle_SID, finalCinematic3DSharpness_StableStyle);
@ -902,11 +939,11 @@ namespace NiloToon.NiloToonURP
{
// Must match: NiloToon character shader's MAX_CHARACTER_COUNT
bool isMobile = GraphicsSettings.HasShaderDefine(BuiltinShaderDefine.SHADER_API_MOBILE);
if (isMobile && (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES2 || (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3 && Graphics.minOpenGLESVersion <= OpenGLESVersion.OpenGLES30)))
if (isMobile && SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3 && Graphics.minOpenGLESVersion <= OpenGLESVersion.OpenGLES30)
return k_MaxCharacterCountMobileShaderLevelLessThan45;
// GLES can be selected as platform on Windows (not a mobile platform) but uniform buffer size so we must use a low light count.
return (isMobile || SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLCore || SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES2 || SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3)
return (isMobile || SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLCore || SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3)
? k_MaxCharacterCountMobile : k_MaxCharacterCountNonMobile;
}
}
@ -1015,7 +1052,8 @@ namespace NiloToon.NiloToonURP
Color finalTintColor = Color.Lerp(Color.white,light.intensity * finalLightColor, controller.mainLightTintColorByLight_Strength);
finalTint *= finalTintColor;
}
finalPerCharMainDirectionalLightTintColorArray[characterID] *= finalTint;
finalPerCharMainDirectionalLightTintColorArray[characterID].Scale((Vector4)finalTint);
}
//--------------------------------------------------------
@ -1171,6 +1209,7 @@ namespace NiloToon.NiloToonURP
Vector4 data2 = perUnityVisibleLightNiloToonDataArray2[lightIndex];
data2.x = Mathf.Lerp(data2.x,1,script.backLightOcclusion2DWhenContributeToMainLightColor);
data2.y = Mathf.Lerp(data2.y,1,script.backLightOcclusion3DWhenContributeToMainLightColor);
data2.z = script.ignoreRenderingLayer ? 1 : 0;
perUnityVisibleLightNiloToonDataArray2[lightIndex] = data2;
}

View File

@ -16,6 +16,9 @@ namespace NiloToon.NiloToonURP
// When empty this render pass will render to the active camera render target.
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
// The render pipeline will ensure target setup and clearing happens in a performant manner.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
// do nothing
@ -25,6 +28,9 @@ namespace NiloToon.NiloToonURP
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
renderClassicOutline(context, renderingData);
@ -52,20 +58,24 @@ namespace NiloToon.NiloToonURP
"Can turn OFF to improve performance.\n\n" +
"Default: ON")]
[OverrideDisplayName("Enable?")]
[Revertible]
public bool ShouldRenderOutline = true;
[Tooltip("Optional 'Classic Outline' width multiplier for all Classic Outline.\n\n" +
"Default: 1")]
[Revertible]
[RangeOverrideDisplayName(" Width", 0, 4)]
public float outlineWidthMultiplier = 1;
[Tooltip("VR will apply an extra 'Classic Outline' width multiplier, due to high FOV(90)\n\n" +
"Default: 0.5")]
[Revertible]
[RangeOverrideDisplayName(" Width multiplier(XR)",0, 4)]
public float outlineWidthExtraMultiplierForXR = 0.5f;
[Tooltip("Optional outline color multiplier.\n\n" +
"Default: White")]
[Revertible]
[ColorUsageOverrideDisplayName(" Tint Color", false, true)]
public Color outlineTintColor = Color.white;
@ -77,6 +87,7 @@ namespace NiloToon.NiloToonURP
"- Outline width will be always constant in world space\n" +
"\n" +
"Default: 1 (apply 100% adjustment)")]
[Revertible]
[RangeOverrideDisplayName(" Auto width adjustment",0, 1)]
public float outlineWidthAutoAdjustToCameraDistanceAndFOV = 1;
@ -88,6 +99,7 @@ namespace NiloToon.NiloToonURP
"\n" +
"Default: OFF")]
[OverrideDisplayName(" Draw in planar reflection?")]
[Revertible]
public bool allowClassicOutlineInPlanarReflection = false;
//-----------------------------------------------------------------------
@ -98,12 +110,14 @@ namespace NiloToon.NiloToonURP
"- allow Screen Space Outline's rendering in Game window, since Depth and Normal textures are now rendered.\n\n" +
"Default: OFF")]
[OverrideDisplayName("Allow render?")]
[Revertible]
public bool AllowRenderScreenSpaceOutline = false;
// TODO: when the minimum support version for NiloToon is Unity2021.3, we should move this to a global setting file, similar to URP12's global setting
[Tooltip("Screen space outline may be very disturbing in scene view window(scene view window = high fov, small window, lowest resolution), this toggle allows you to turn it on/off.\n\n" +
"Default: OFF")]
[OverrideDisplayName(" Allow in Scene View?")]
[Revertible]
public bool AllowRenderScreenSpaceOutlineInSceneView = false;
//-----------------------------------------------------------------------
@ -116,6 +130,7 @@ namespace NiloToon.NiloToonURP
"- extra thick outline will NOT render on top of transparent material (= extra thick outline covered by transparent material)\n\n" +
"*You can also control extra thick outline's ZWrite in each NiloToonPerCharacterRenderController.\n\n" +
"Default: AfterRenderingTransparents")]
[Revertible]
[OverrideDisplayName("RenderPassEvent")]
public RenderPassEvent extraThickOutlineRenderTiming = RenderPassEvent.AfterRenderingTransparents;
}

View File

@ -59,6 +59,13 @@ using UnityEngine.XR;
using UnityEngine.Rendering.RenderGraphModule;
#endif
#if UNITY_2021 || UNITY_2022
// On old Unity versions, alias our code's GraphicsFormatUsage to FormatUsage
using GraphicsFormatUsage = UnityEngine.Experimental.Rendering.FormatUsage;
#else
using GraphicsFormatUsage = UnityEngine.Experimental.Rendering.GraphicsFormatUsage;
#endif
namespace NiloToon.NiloToonURP
{
#if UNITY_2022_2_OR_NEWER
@ -78,11 +85,13 @@ namespace NiloToon.NiloToonURP
[Header("Render Timing")]
[Tooltip("The default value is BeforeRenderingPostProcess + 0, you can edit it to make NiloToon work with other renderer features")]
[OverrideDisplayName("Renderer Feature Order Offset")]
[Revertible]
public int renderPassEventTimingOffset = 0;
[Header("Bloom")]
[Tooltip("Can turn off to prevent rendering NiloToonBloomVolume, which will improve performance for low quality graphics setting renderer")]
[OverrideDisplayName("Allow render Bloom?")]
[Revertible]
public bool allowRenderNiloToonBloom = true;
}
public Settings settings { get; }
@ -154,8 +163,15 @@ namespace NiloToon.NiloToonURP
ShaderConstants._BloomMipDown[i] = Shader.PropertyToID("_NiloToonBloomMipDown" + i);
}
// [Copy from Unity6000.2.6f2 > PostProcessPass.cs]
// Texture format pre-lookup
const FormatUsage usage = FormatUsage.Linear | FormatUsage.Render;
// UUM-41070: We require `Linear | Render` but with the deprecated FormatUsage this was checking `Blend`
// For now, we keep checking for `Blend` until the performance hit of doing the correct checks is evaluated
//const FormatUsage usage = FormatUsage.Linear | FormatUsage.Render; // old, but still correct, don't use it anymore due to warning of FormatUsage obsolete API
//const GraphicsFormatUsage usage = GraphicsFormatUsage.Linear | GraphicsFormatUsage.Render; // naive change FormatUsage->GraphicsFormatUsage = wrong! fk unity why? don't use it!
const GraphicsFormatUsage usage = GraphicsFormatUsage.Blend; // correct, matching Unity6000.2.6f2 URP PostProcessPass.cs code
if (SystemInfo.IsFormatSupported(GraphicsFormat.B10G11R11_UFloatPack32, usage)) // HDR fallback
{
m_DefaultHDRFormat = GraphicsFormat.B10G11R11_UFloatPack32;
@ -189,11 +205,17 @@ namespace NiloToon.NiloToonURP
//m_Source = source;
}
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
//overrideCameraTarget = true;
}
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
// [NiloToon added]
@ -256,6 +278,9 @@ namespace NiloToon.NiloToonURP
return desc;
}
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
void Render(CommandBuffer cmd, ref RenderingData renderingData)
{
ref var cameraData = ref renderingData.cameraData;
@ -310,6 +335,10 @@ namespace NiloToon.NiloToonURP
}
}
}
#if UNITY_6000_0_OR_NEWER
[Obsolete]
#endif
void SetupBloom(CommandBuffer cmd, RTHandle source, Material uberMaterial)
{
// [NiloToon edited]
@ -988,11 +1017,13 @@ namespace NiloToon.NiloToonURP
[Header("Render Timing")]
[Tooltip("The default value is BeforeRenderingPostProcess + 0, you can edit it to make NiloToon work with other renderer features")]
[OverrideDisplayName("Renderer Feature Order Offset")]
[Revertible]
public int renderPassEventTimingOffset = 0;
[Header("Bloom")]
[Tooltip("Can turn off to prevent rendering NiloToonBloomVolume, which will improve performance for low quality graphics setting renderer")]
[OverrideDisplayName("Allow render Bloom?")]
[Revertible]
public bool allowRenderNiloToonBloom = true;
}
public Settings settings { get; }

View File

@ -56,5 +56,54 @@ namespace NiloToon.NiloToonURP
// find nothing
return null;
}
/// <summary>
/// Searches all descendants and adds matching transforms to the provided list <b>only if not already present</b>.
/// This avoids duplicates and new list allocations.
/// </summary>
/// <param name="parent">Root transform to search.</param>
/// <param name="targetName">Keyword to match (case-insensitive substring).</param>
/// <param name="banNameList">Optional banned keywords (case-insensitive).</param>
/// <param name="outputList">Existing list to be appended (duplicates avoided, no clearing).</param>
public static void DepthSearchAllAddUnique(Transform parent, string targetName, string[] banNameList, List<Transform> outputList)
{
if (outputList == null)
throw new ArgumentNullException(nameof(outputList));
if (parent == null || string.IsNullOrEmpty(targetName))
return;
DepthSearchAllAddUniqueRecursive(parent, targetName, banNameList, outputList);
}
private static void DepthSearchAllAddUniqueRecursive(Transform current, string targetName, string[] banNameList, List<Transform> results)
{
foreach (Transform child in current)
{
if (NameHasKeyword(child.name, targetName))
{
bool isBanned = false;
if (banNameList != null)
{
foreach (string banName in banNameList)
{
if (NameHasKeyword(child.name, banName))
{
isBanned = true;
break;
}
}
}
if (!isBanned && !results.Contains(child))
{
results.Add(child);
}
}
DepthSearchAllAddUniqueRecursive(child, targetName, banNameList, results);
}
}
}
}

View File

@ -151,6 +151,10 @@ namespace NiloToon.NiloToonURP
public ClampedFloatParameter characterOverallShadowStrength = new ClampedFloatParameter(1, 0, 2);
[OverrideDisplayName("Tint Color")]
public ColorParameter characterOverallShadowTintColor = new ColorParameter(new Color(1, 1, 1, 0), true, false, true);
[OverrideDisplayName(" Skin/Face")]
public ColorParameter characterOverallShadowTintColorForSkinFace = new ColorParameter(new Color(1, 1, 1, 0), true, false, true);
[OverrideDisplayName(" Non Skin/Face")]
public ColorParameter characterOverallShadowTintColorForNonSkinFace = new ColorParameter(new Color(1, 1, 1, 0), true, false, true);
[Header("Classic Outline")]
[OverrideDisplayName("Width")]

View File

@ -1,6 +1,7 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Serialization;
namespace NiloToon.NiloToonURP
{
@ -14,10 +15,21 @@ namespace NiloToon.NiloToonURP
[Header("Rim (3D Classic Style)")]
[OverrideDisplayName("Strength")]
public ClampedFloatParameter strengthRimMask3D_ClassicStyle = new ClampedFloatParameter(0, 0, 1);
[OverrideDisplayName(" Rim Width")]
public ClampedFloatParameter widthRimMask3D_ClassicStyle = new ClampedFloatParameter(0.3f, 0, 1);
[OverrideDisplayName(" Rim Blur")]
public ClampedFloatParameter blurRimMask3D_ClassicStyle = new ClampedFloatParameter(0.02f, 0, 1);
[OverrideDisplayName(" Rim Sharpness")]
public ClampedFloatParameter sharpnessRimMask3D_ClassicStyle = new ClampedFloatParameter(0f, 0, 1);
[FormerlySerializedAs("strengthRimMask3D_DynmaicStyle")]
[Header("Rim (3D Dynamic Style)")]
[OverrideDisplayName("Strength")]
public ClampedFloatParameter strengthRimMask3D_DynmaicStyle = new ClampedFloatParameter(0, 0, 1);
public ClampedFloatParameter strengthRimMask3D_DynamicStyle = new ClampedFloatParameter(0, 0, 1);
[OverrideDisplayName(" Rim Width")]
public ClampedFloatParameter widthRimMask3D_DynamicStyle = new ClampedFloatParameter(0.5f, 0, 1);
[OverrideDisplayName(" Rim Blur")]
public ClampedFloatParameter blurRimMask3D_DynamicStyle = new ClampedFloatParameter(0.5f, 0, 1);
[OverrideDisplayName(" Rim Sharpness")]
public ClampedFloatParameter sharpnessRimMask3D_DynamicStyle = new ClampedFloatParameter(0.375f, 0, 1);

View File

@ -10,6 +10,10 @@ namespace NiloToon.NiloToonURP
[Header("All Shadows")]
[OverrideDisplayName("Shadow Tint Color")]
public ColorParameter characterOverallShadowTintColor = new ColorParameter(Color.white, true, false, true);
[OverrideDisplayName(" Skin/Face")]
public ColorParameter characterOverallShadowTintColorForSkinFace = new ColorParameter(Color.white, true, false, true);
[OverrideDisplayName(" Non Skin/Face")]
public ColorParameter characterOverallShadowTintColorForNonSkinFace = new ColorParameter(Color.white, true, false, true);
[OverrideDisplayName("Shadow Strength")]
public ClampedFloatParameter characterOverallShadowStrength = new ClampedFloatParameter(1, 0, 2);

View File

@ -25,7 +25,7 @@ namespace NiloToon.NiloToonURP
NiloHybirdACES
}
[Serializable, VolumeComponentMenuForRenderPipeline("NiloToon/Tonemapping (NiloToon)", typeof(UniversalRenderPipeline))]
[Serializable, VolumeComponentMenu("NiloToon/Tonemapping (NiloToon)")]
public class NiloToonTonemappingVolume : VolumeComponent, IPostProcessComponent
{
[Tooltip("Select a tonemapping algorithm to use for the color grading process.\n" +

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 972a343cf44ee2646a23237169b04641
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fbe2dfa40dbbd3b4fb732eff10997212
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7a6f689f7fed7bf4091597c76f54c24b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -10,6 +10,10 @@
#include "NiloDefineURPGlobalTextures.hlsl"
#include "NiloScaledScreenParamUtil.hlsl"
// NiloPrepassBufferTextureUtil must be included before NiloCommonUtil and NiloScreenSpaceOutlineUtil
// because they both use _NiloToonPrepassBufferTex
#include "NiloPrepassBufferTextureUtil.hlsl"
#include "NiloCommonUtil.hlsl"
#include "NiloInvLerpRemapUtil.hlsl"
#include "NiloAAUtil.hlsl"
@ -26,4 +30,5 @@
#include "NiloStrandSpecular.hlsl"
#include "NiloPerspectiveRemovalUtil.hlsl"
#include "NiloDitherFadeoutClipUtil.hlsl"
#include "NiloShadows.hlsl"

View File

@ -30,7 +30,7 @@ struct NiloPrepassBufferRTData
half characterVisibleArea; // g
};
TEXTURE2D_X(_NiloToonPrepassBufferTex);
// _NiloToonPrepassBufferTex is now defined in NiloPrepassBufferTextureUtil.hlsl
NiloPrepassBufferRTData NiloSamplePrepassBufferRT(float2 normalizeScreenSpaceUV)
{
half4 sample = SAMPLE_TEXTURE2D_X(_NiloToonPrepassBufferTex, sampler_PointClamp, normalizeScreenSpaceUV);

View File

@ -20,4 +20,37 @@ void NiloDoDitherFadeoutClip(float2 SV_POSITIONxy, float ditherOpacity)
uint index = (uint(SV_POSITIONxy.x) % 4) * 4 + uint(SV_POSITIONxy.y) % 4;
clip(ditherOpacity - DITHER_THRESHOLDS[index]);
}
// this will work for iPhone15Pro, but the original function wont, why? must be due to % or array.
/*
void NiloDoDitherFadeoutClip(float2 SV_POSITIONxy, float ditherOpacity)
{
// Use integer coordinates
int x = int(SV_POSITIONxy.x) & 3; // Using bitwise AND instead of modulo
int y = int(SV_POSITIONxy.y) & 3;
// Calculate threshold without array
float threshold;
int index = x * 4 + y;
// Unroll the array access
if (index == 0) threshold = 1.0 / 17.0;
else if (index == 1) threshold = 9.0 / 17.0;
else if (index == 2) threshold = 3.0 / 17.0;
else if (index == 3) threshold = 11.0 / 17.0;
else if (index == 4) threshold = 13.0 / 17.0;
else if (index == 5) threshold = 5.0 / 17.0;
else if (index == 6) threshold = 15.0 / 17.0;
else if (index == 7) threshold = 7.0 / 17.0;
else if (index == 8) threshold = 4.0 / 17.0;
else if (index == 9) threshold = 12.0 / 17.0;
else if (index == 10) threshold = 2.0 / 17.0;
else if (index == 11) threshold = 10.0 / 17.0;
else if (index == 12) threshold = 16.0 / 17.0;
else if (index == 13) threshold = 8.0 / 17.0;
else if (index == 14) threshold = 14.0 / 17.0;
else threshold = 6.0 / 17.0;
clip(ditherOpacity - threshold);
}
*/

View File

@ -114,7 +114,7 @@ float GetOutlineCameraFovAndDistanceFixMultiplier(float positionVS_Z, float came
return outlineWidthMulFix * 0.00005; // mul a const to make return result = default normal expand amount WS
}
/*
// [currently not being used in NiloToonURP]
// If your project has a faster way to get camera fov in shader, you don't need to use this method.
// For example, you write cmd.SetGlobalFloat("_CurrentCameraFOV",cameraFOV) using a new RendererFeature in C#
@ -133,3 +133,4 @@ float GetOutlineCameraFovAndDistanceFixMultiplier(float positionVS_Z, float appl
{
return GetOutlineCameraFovAndDistanceFixMultiplier(positionVS_Z, GetCameraFOV(), applyPercentage);
}
*/

View File

@ -0,0 +1,44 @@
// SPDX-License-Identifier: (Not available for this version, you are only allowed to use this software if you have express permission from the copyright holder and agreed to the latest NiloToonURP EULA)
// Copyright (c) 2021 Kuroneko ShaderLab Limited
// For more information, visit -> https://github.com/ColinLeung-NiloCat/UnityURPToonLitShaderExample
// #pragma once is a safe guard best practice in almost every .hlsl,
// doing this can make sure your .hlsl's user can include this .hlsl anywhere anytime without producing any multi include conflict
#pragma once
// NOTE: This file requires NiloScaledScreenParamUtil.hlsl to be included before it
// because it uses GetScaledScreenWidthHeight() function
TEXTURE2D_X(_NiloToonPrepassBufferTex);
SAMPLER(sampler_NiloToonPrepassBufferTex);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// core functions
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Sample with UV coordinates (0-1 range)
half4 SampleNiloToonPrepassColor(float2 uv)
{
return SAMPLE_TEXTURE2D_X(_NiloToonPrepassBufferTex, sampler_NiloToonPrepassBufferTex, UnityStereoTransformScreenSpaceTex(uv));
}
// Load with pixel coordinates
half4 LoadNiloToonPrepassColor(uint2 uv)
{
return LOAD_TEXTURE2D_X(_NiloToonPrepassBufferTex, uv);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// high level helper functions
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
half4 LoadNiloToonPrepassColorSafe(int2 loadTexPos)
{
// clamp loadTexPos to prevent loading outside of _CameraDepthTexture's valid area
loadTexPos.x = max(loadTexPos.x,0);
loadTexPos.y = max(loadTexPos.y,0);
loadTexPos = min(loadTexPos,GetScaledScreenWidthHeight()-1);
return LoadNiloToonPrepassColor(loadTexPos);
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: cde009dea17d669409f3694ff0433dba
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,11 +3,14 @@
// For more information, visit -> https://github.com/ColinLeung-NiloCat/UnityURPToonLitShaderExample
// #pragma once is a safe guard best practice in almost every .hlsl,
// #pragma once is a safe guard best practice in almost every .hlsl,
// doing this can make sure your .hlsl's user can include this .hlsl anywhere anytime without producing any multi include conflict
#pragma once
// _ScaledScreenParams doesn't exist in URP10 (only exist in URP13 or higher),
#ifndef NILO_SCALED_SCREEN_PARAM_UTIL_INCLUDED
#define NILO_SCALED_SCREEN_PARAM_UTIL_INCLUDED
// _ScaledScreenParams doesn't exist in URP10 (only exist in URP13 or higher),
// so for old URP versions, we use _CameraDepthTexture_TexelSize as a fallback
// _CameraDepthTexture_TexelSize is not the best fallback solution, but works for NiloToonURP for now
float2 GetScaledScreenWidthHeight()
@ -28,10 +31,8 @@ float2 GetScaledScreenTexelSize()
return 1.0/_ScaledScreenParams.xy;
// return _ScaledScreenParams.zw-float2(1.0,1.0); // this line will produce wrong result, due to precision?
#else
return _CameraDepthTexture_TexelSize.xy;
return _CameraDepthTexture_TexelSize.xy;
#endif
}
#endif // NILO_SCALED_SCREEN_PARAM_UTIL_INCLUDED

View File

@ -113,7 +113,7 @@ float3 positionWSToFlatNormalWSUnitVector(float3 positionWS)
return normal;
}
TEXTURE2D_X(_NiloToonPrepassBufferTex);
// _NiloToonPrepassBufferTex is now defined in NiloPrepassBufferTextureUtil.hlsl
// Unity Core defined common inline sampler already in URP14
// see GlobalSamplers.hlsl

View File

@ -0,0 +1,102 @@
// SPDX-License-Identifier: (Not available for this version, you are only allowed to use this software if you have express permission from the copyright holder and agreed to the latest NiloToonURP EULA)
// Copyright (c) 2021 Kuroneko ShaderLab Limited
// For more information, visit -> https://github.com/ColinLeung-NiloCat/UnityURPToonLitShaderExample
// #pragma once is a safe guard best practice in almost every .hlsl,
// doing this can make sure your .hlsl's user can include this .hlsl anywhere anytime without producing any multi include conflict
#pragma once
//-----------------------------------------------------------------------
// direct copy of Unity2022.3.62f1 URP's Shadows.hlsl
// copied everything needed by SampleShadowmapFiltered_Nilo()
// rename methods with _Nilo suffix to avoid naming conflict
//-----------------------------------------------------------------------
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Shadow/ShadowSamplingTent.hlsl"
// Should match: UnityEngine.Rendering.Universal + 1
#define NILO_SOFT_SHADOW_QUALITY_OFF half(0.0)
#define NILO_SOFT_SHADOW_QUALITY_LOW half(1.0)
#define NILO_SOFT_SHADOW_QUALITY_MEDIUM half(2.0)
#define NILO_SOFT_SHADOW_QUALITY_HIGH half(3.0)
struct ShadowSamplingData_Nilo
{
half4 shadowOffset0;
half4 shadowOffset1;
float4 shadowmapSize;
half softShadowQuality;
};
real SampleShadowmapFilteredLowQuality_Nilo(TEXTURE2D_SHADOW_PARAM(ShadowMap, sampler_ShadowMap), float4 shadowCoord, ShadowSamplingData_Nilo samplingData)
{
// 4-tap hardware comparison
real4 attenuation4;
attenuation4.x = real(SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, shadowCoord.xyz + float3(samplingData.shadowOffset0.xy, 0)));
attenuation4.y = real(SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, shadowCoord.xyz + float3(samplingData.shadowOffset0.zw, 0)));
attenuation4.z = real(SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, shadowCoord.xyz + float3(samplingData.shadowOffset1.xy, 0)));
attenuation4.w = real(SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, shadowCoord.xyz + float3(samplingData.shadowOffset1.zw, 0)));
return dot(attenuation4, real(0.25));
}
real SampleShadowmapFilteredMediumQuality_Nilo(TEXTURE2D_SHADOW_PARAM(ShadowMap, sampler_ShadowMap), float4 shadowCoord, ShadowSamplingData_Nilo samplingData)
{
real fetchesWeights[9];
real2 fetchesUV[9];
SampleShadow_ComputeSamples_Tent_5x5(samplingData.shadowmapSize, shadowCoord.xy, fetchesWeights, fetchesUV);
return fetchesWeights[0] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[0].xy, shadowCoord.z))
+ fetchesWeights[1] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[1].xy, shadowCoord.z))
+ fetchesWeights[2] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[2].xy, shadowCoord.z))
+ fetchesWeights[3] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[3].xy, shadowCoord.z))
+ fetchesWeights[4] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[4].xy, shadowCoord.z))
+ fetchesWeights[5] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[5].xy, shadowCoord.z))
+ fetchesWeights[6] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[6].xy, shadowCoord.z))
+ fetchesWeights[7] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[7].xy, shadowCoord.z))
+ fetchesWeights[8] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[8].xy, shadowCoord.z));
}
real SampleShadowmapFilteredHighQuality_Nilo(TEXTURE2D_SHADOW_PARAM(ShadowMap, sampler_ShadowMap), float4 shadowCoord, ShadowSamplingData_Nilo samplingData)
{
real fetchesWeights[16];
real2 fetchesUV[16];
SampleShadow_ComputeSamples_Tent_7x7(samplingData.shadowmapSize, shadowCoord.xy, fetchesWeights, fetchesUV);
return fetchesWeights[0] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[0].xy, shadowCoord.z))
+ fetchesWeights[1] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[1].xy, shadowCoord.z))
+ fetchesWeights[2] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[2].xy, shadowCoord.z))
+ fetchesWeights[3] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[3].xy, shadowCoord.z))
+ fetchesWeights[4] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[4].xy, shadowCoord.z))
+ fetchesWeights[5] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[5].xy, shadowCoord.z))
+ fetchesWeights[6] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[6].xy, shadowCoord.z))
+ fetchesWeights[7] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[7].xy, shadowCoord.z))
+ fetchesWeights[8] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[8].xy, shadowCoord.z))
+ fetchesWeights[9] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[9].xy, shadowCoord.z))
+ fetchesWeights[10] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[10].xy, shadowCoord.z))
+ fetchesWeights[11] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[11].xy, shadowCoord.z))
+ fetchesWeights[12] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[12].xy, shadowCoord.z))
+ fetchesWeights[13] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[13].xy, shadowCoord.z))
+ fetchesWeights[14] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[14].xy, shadowCoord.z))
+ fetchesWeights[15] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[15].xy, shadowCoord.z));
}
real SampleShadowmapFiltered_Nilo(TEXTURE2D_SHADOW_PARAM(ShadowMap, sampler_ShadowMap), float4 shadowCoord, ShadowSamplingData_Nilo samplingData)
{
real attenuation = real(1.0);
if (samplingData.softShadowQuality == NILO_SOFT_SHADOW_QUALITY_LOW)
{
attenuation = SampleShadowmapFilteredLowQuality_Nilo(TEXTURE2D_SHADOW_ARGS(ShadowMap, sampler_ShadowMap), shadowCoord, samplingData);
}
else if(samplingData.softShadowQuality == NILO_SOFT_SHADOW_QUALITY_MEDIUM)
{
attenuation = SampleShadowmapFilteredMediumQuality_Nilo(TEXTURE2D_SHADOW_ARGS(ShadowMap, sampler_ShadowMap), shadowCoord, samplingData);
}
else // SOFT_SHADOW_QUALITY_HIGH
{
attenuation = SampleShadowmapFilteredHighQuality_Nilo(TEXTURE2D_SHADOW_ARGS(ShadowMap, sampler_ShadowMap), shadowCoord, samplingData);
}
return attenuation;
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 8106dd51df3640a489250a89b92b983f
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7503e5fa6d74529409406a811b7626fe
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -642,6 +642,17 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
[Tex(_RENDER_OUTLINE,_OutlineWidthTexChannelMask)][NoScaleOffset]_OutlineWidthTex("Mask Map", 2D) = "white" {}
[HideInInspector]_OutlineWidthTexChannelMask("", Vector) = (0,1,0,0)
[Title(_RENDER_OUTLINE, Auto width)]
[Tooltip(Should Outline width auto adjust to camera distance and FOV.)]
[Tooltip()]
[Tooltip(If set to 1,)]
[Tooltip(. When camera is closer to character or camera FOV is lower, outline width in world space will be smaller automatically)]
[Tooltip(. When camera is further away from character or camera FOV is higher, outline width in world space will be larger automatically)]
[Tooltip()]
[Tooltip(If set to 0,)]
[Tooltip(. Outline width will be always constant in world space)]
[Sub(_RENDER_OUTLINE)]_OutlineApplyAutoWidthAdjustment("Auto Width?", Range(0,1)) = 1
[Title(_RENDER_OUTLINE, Width Mask(Vertex Color))]
[Tooltip(Enable to let outline width multiply with a 0 to 1 value extracted from vertex color.)]
[Advanced][SubToggle(_RENDER_OUTLINE,_)]_UseOutlineWidthMaskFromVertexColor("Enable Mask?", Float) = 0
@ -659,6 +670,10 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
[Tooltip(The default alpha is 1, which means the outline color of Skin will be overridden to this color by default.)]
[Sub(_RENDER_OUTLINE)][HDR]_OutlineTintColorSkinAreaOverride("Tint Color(Skin Override)", Color) = (0.4,0.2,0.2,1)
[SubToggle(_RENDER_OUTLINE,_OUTLINETINTCOLORMAP)]_UseOutlineTintColorMap("Enable Tint Color map?", Float) = 0
[ShowIf(_UseOutlineTintColorMap,Equal,1)]
[Tex(_RENDER_OUTLINE,_OUTLINETINTCOLORMAP)][NoScaleOffset]_OutlineTintColorMap("Tint Color Map", 2D) = "white" {}
[Advanced]
[Title(Extra Tint Color)]
[Tooltip(An extra outline tint color for occlusion area.)]
@ -749,12 +764,17 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
[HideInInspector]_OutlineZOffsetMaskRemapStart("", Range(0,1)) = 0
[HideInInspector]_OutlineZOffsetMaskRemapEnd("", Range(0,1)) = 1
[Title(_RENDER_OUTLINE, Z Offset Mask(Vertex Color))]
[Tooltip(Enable to let outline Z Offset multiply by a float value extracted from vertex color.)]
[Advanced][SubToggle(_RENDER_OUTLINE,_)]_UseOutlineZOffsetMaskFromVertexColor("Enable Mask?", Float) = 0
[Tooltip(Select which vertex color channel should be extracted to multiply with outline Z Offset, or pick a convertion method to extract a float value to multiply with outline Z Offset.)]
[Advanced][ChannelDrawer(_RENDER_OUTLINE)]_OutlineZOffsetMaskFromVertexColor(" Use channel", Vector) = (0,1,0,0)
[Tooltip(If you want to use a Z Offset Mask from vertex color that is,)]
[Tooltip(. White is apply Z Offset as usual)]
[Tooltip(. Darker is reduce Z Offset)]
[Tooltip(. Black is not apply Z Offset)]
[Tooltip(then you need to enable this toggle.)]
[Advanced][SubToggle(_RENDER_OUTLINE, _)]_OutlineZOffsetMaskTexFromVertexColorInvertColor(" Invert?", Float) = 0
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// RimLight+Shadow 2D
@ -809,8 +829,6 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
[Title(_DepthTextureRimLightAndShadowGroup, Style)]
[Sub(_DepthTextureRimLightAndShadowGroup)]_DepthTexRimLightIgnoreLightDir("360 Rim light", Range(0,1)) = 0
[Sub(_DepthTextureRimLightAndShadowGroup)]_DepthTexShadowIgnoreLightDir("360 Shadow (deprecated)", Range(0,1)) = 0
[Title(_DepthTextureRimLightAndShadowGroup, Style (face))]
[Tooltip(When set to 1, the face 2D shadow will be static on the face, ignoring light direction)]
[Tooltip()]
@ -839,6 +857,8 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
[Title(. Setting)]
[Sub(_DepthTextureRimLightAndShadowGroup)]_DepthTexRimLightWidthMultiplier(" Width", Range(0,10)) = 1
[Tooltip(Default clamp for face is 0.5 width, to prevent 2D rim too large for face.)]
[Sub(_DepthTextureRimLightAndShadowGroup)]_DepthTexRimLightWidthClampForFace(" Clamp (face)", Range(0,10)) = 0.5
[Tooltip(The intensity or brightness of rim light.)]
[Tooltip(In HDR mode, a high value will produce bloom at rim light area, usually you will control this in NiloToonCharRenderingControlVolume instead of material.)]
[Sub(_DepthTextureRimLightAndShadowGroup)]_DepthTexRimLightIntensity(" Brightness", Range(0,32)) = 1.5
@ -862,6 +882,10 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
[Tooltip()]
[Tooltip(Recommend increase it to 0.5 for hair material to produce a cleaner hair 2D rim light.)]
[Advanced][Sub(_DepthTextureRimLightAndShadowGroup)]_DepthTexRimLightThresholdOffset("Occlusion bias", Range(0,1)) = 0
[Tooltip(A default minimum 0.5m occlusion bias for face, to prevent mouth and eye showing 2D rim light due to geometry hole of mouth and eye.)]
[Advanced][Sub(_DepthTextureRimLightAndShadowGroup)]_DepthTexRimLightMinimumThresholdOffsetForFace("Occlusion bias (face minimum)", Range(0,1)) = 0.5
[Tooltip(Rim light will fadeout softly when a nearby occulder appears, you can control the fadeout softness.)]
[Advanced][Sub(_DepthTextureRimLightAndShadowGroup)]_DepthTexRimLightFadeoutRange("Fadeout Softness", Range(0.01,10)) = 1
@ -3552,6 +3576,13 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
[Sub(_EMISSION)]_MultiplyBaseColorToEmissionColor(" Multiply Base Map", Range(0,1)) = 0
[Tooltip(Enable to tint the emission result by Main Directional Light Color, usually you will turn this on when you want to make emission result acts like a non self glow or reflective material.)]
[Sub(_EMISSION)]_MultiplyLightColorToEmissionColor(" Multiply Light Color", Range(0,1)) = 0
[Title(_EMISSION, Blink Animation)]
[SubToggle(_EMISSION, _EMISSION_ANIM_TINT_RAMPMAP)]_EnableEmissionAnimTintRampMap("Enable Anim Tint Ramp Map?", Float) = 0
[ShowIf(_EnableEmissionAnimTintRampMap,Equal,1)]
[Ramp(_EMISSION)][NoScaleOffset]_EmissionAnimTintRampMap("Anim Map", 2D) = "white" {}
[ShowIf(_EnableEmissionAnimTintRampMap,Equal,1)]
[Sub(_EMISSION)]_EmissionAnimTintRampMapSpeed(" Anim Speed (loop/second)", Float) = 1
[Title(_EMISSION, ........................................................................................................................................................................................................................................................................................................................................................................)]
@ -4204,6 +4235,7 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
#pragma shader_feature_local _DETAIL // need TangentWS from vertex shader also, so shader_feature_local_fragment is not enough
#pragma shader_feature_local_fragment _EMISSION
#pragma shader_feature_local_fragment _EMISSION_ANIM_TINT_RAMPMAP
#pragma shader_feature_local_fragment _SMOOTHNESSMAP
#pragma shader_feature_local_fragment _OCCLUSIONMAP
#pragma shader_feature_local_fragment _SPECULARHIGHLIGHTS // URP ComplexLit.shader use _SPECULARHIGHLIGHTS_OFF to save a keyword, here we use an inverted keyword since it is default off
@ -4487,6 +4519,7 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
// Note: outline need to receive URP shadow, else outline is not correctly darken when character is within URP shadow
#pragma shader_feature_local_fragment _RECEIVE_URP_SHADOW
//#pragma shader_feature_local_fragment _EMISSION // TODO: do we need emission?
//#pragma shader_feature_local_fragment _EMISSION_ANIM_TINT_RAMPMAP // TODO: do we need emission?
#pragma shader_feature_local_fragment _OCCLUSIONMAP // needs to affect outline color
// -------------------------------------
@ -4494,6 +4527,7 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
// -------------------------------------
#pragma shader_feature_local_vertex _OUTLINEWIDTHMAP
#pragma shader_feature_local_vertex _OUTLINEZOFFSETMAP
#pragma shader_feature_local_fragment _OUTLINETINTCOLORMAP
// -------------------------------------
// Material keywords (NiloToon specific shader_feature)
@ -4841,7 +4875,7 @@ Shader "Universal Render Pipeline/NiloToon/NiloToon_Character"
UVData uvData;
ToonLightingData lightingData;
ToonSurfaceData surfaceData;
InitAllData(input, facing, uvData, lightingData, surfaceData);
InitAllData(input, facing, 0, uvData, lightingData, surfaceData);
half charVisibleArea = SAMPLE_TEXTURE2D_X(_NiloToonPrepassBufferTex, sampler_PointClamp, lightingData.normalizedScreenSpaceUV).g;

View File

@ -50,6 +50,7 @@ void ApplyCustomUserLogicToBaseColor(inout half4 baseColor, Varyings input, UVDa
// edit baseColor by your custom logic here
//baseColor *= half4(1,0,0,1); // example code, tint character's baseColor with red color
//baseColor = half4(input.uv,0,1); // example code, replace baseColor as character's uv
}
void ApplyCustomUserLogicBeforeFog(inout half3 color, ToonSurfaceData surfaceData, ToonLightingData lightingData, Varyings input, UVData uvData)

View File

@ -454,16 +454,16 @@ half4 ShadeMainLight(inout ToonSurfaceData surfaceData, Varyings input, ToonLigh
float3 DirVS360 = mul(input.smoothedNormalWS, (float3x3)UNITY_MATRIX_V);
float3 userOverridenMainLightDirVSForShadow = mul((float3x3)UNITY_MATRIX_V, lerp(lightingData.mainLight.direction, _NiloToonGlobalPerCharFaceUpwardDirWSArray[_CharacterID], lightingData.isFaceArea * _DepthTexShadowFixedDirectionForFace));
float depthTexRimLightWidthMultiplier = _DepthTexRimLightWidthMultiplier;
#if _ISFACE
depthTexRimLightWidthMultiplier = lerp(depthTexRimLightWidthMultiplier, min(depthTexRimLightWidthMultiplier, _DepthTexRimLightWidthClampForFace), lightingData.isFaceArea);
#endif
float2 depthTexRimlightFinalUVOffset = UvOffsetMultiplier * normalize(lerp(userOverridenMainLightDirVS.xy, DirVS360.xy, _DepthTexRimLightIgnoreLightDir)) * _DepthTexRimLightWidthMultiplier;
float2 depthTexShadowFinalUVOffset = UvOffsetMultiplier * normalize(lerp(userOverridenMainLightDirVSForShadow.xy, DirVS360.xy, _DepthTexShadowIgnoreLightDir)) * _DepthTexShadowWidthMultiplier;
float2 depthTexRimlightFinalUVOffset = UvOffsetMultiplier * normalize(lerp(userOverridenMainLightDirVS.xy, DirVS360.xy, _DepthTexRimLightIgnoreLightDir)) * depthTexRimLightWidthMultiplier;
float2 depthTexShadowFinalUVOffset = UvOffsetMultiplier * normalize(userOverridenMainLightDirVSForShadow.xy) * _DepthTexShadowWidthMultiplier;
float2 depthTexRimlightUvOffsetMultiplier = originalUvOffsetMultiplier * _DepthTexRimLightWidthMultiplier;
float2 depthTexShadowUvOffsetMultiplier = originalUvOffsetMultiplier * _DepthTexShadowWidthMultiplier;
float2 depthTexRimlightUvOffsetMultiplier = originalUvOffsetMultiplier * depthTexRimLightWidthMultiplier;
// WIP(Danger)
/*
@ -509,7 +509,11 @@ half4 ShadeMainLight(inout ToonSurfaceData surfaceData, Varyings input, ToonLigh
float depthTexRimLightDepthDiffThreshold = 0.05;
// give user per material control (default 0)
depthTexRimLightDepthDiffThreshold += _DepthTexRimLightThresholdOffset;
float thresholdOffset = _DepthTexRimLightThresholdOffset;
#if _ISFACE
thresholdOffset = max(thresholdOffset, _DepthTexRimLightMinimumThresholdOffsetForFace * lightingData.isFaceArea);
#endif
depthTexRimLightDepthDiffThreshold += thresholdOffset;
float rimLightdepthDiffThreshold = saturate(depthTexRimLightDepthDiffThreshold + _GlobalDepthTexRimLightDepthDiffThresholdOffset);
@ -547,6 +551,9 @@ half4 ShadeMainLight(inout ToonSurfaceData surfaceData, Varyings input, ToonLigh
rimAttenuation *= smoothstep(_DepthTexRimLight3DRimMaskThreshold-blur, _DepthTexRimLight3DRimMaskThreshold + blur, (saturate(NoL) * (1.0 - saturate(NoV)))); // 0.2(no blur) or 0.05~0.075(blur) threshold seems good
}
// possible method to make rim light not that uniform in color
//rimAttenuation *= pow(saturateNoL,2);
// rim light AA (test)
//rimAttenuation = saturate(applyAA(rimAttenuation,0.33333,0.6666)); // assume rimAttenuation is 0~1
@ -565,8 +572,13 @@ half4 ShadeMainLight(inout ToonSurfaceData surfaceData, Varyings input, ToonLigh
// let shadow fadeout softly and smoothly when depth difference is too small
// _DepthTexShadowFadeoutRange will allow user controlling how the fadeout should look like
depthDiffShadow = saturate((depthTexShadowLinearDepthVS - (lightingData.selfLinearEyeDepth - depthTexShadowDepthDiffThreshold)) * 50 / _DepthTexShadowFadeoutRange);
depthDiffShadow = lerp(1,depthDiffShadow,_DepthTexShadowUsage * _NiloToonGlobalAllowUnityCameraDepthTextureWriteFaceZOffset);
depthDiffShadow = saturate((depthTexShadowLinearDepthVS - (lightingData.selfLinearEyeDepth - depthTexShadowDepthDiffThreshold)) * 50.0 / _DepthTexShadowFadeoutRange);
half depthTexShadowAmount = _DepthTexShadowUsage;
#if _ISFACE
depthTexShadowAmount *= lerp(1, _NiloToonGlobalAllowUnityCameraDepthTextureWriteFaceZOffset, lightingData.isFaceArea);
#endif
depthDiffShadow = lerp(1,depthDiffShadow,depthTexShadowAmount);
}
else
{
@ -674,30 +686,6 @@ half4 ShadeMainLight(inout ToonSurfaceData surfaceData, Varyings input, ToonLigh
#endif
float4 selfShadowmapUV = float4(shadowMapUV_XY,ndcZCompareValue,0); // packing for SAMPLE_TEXTURE2D_SHADOW
// [Shadow test code, not used]
// URP's 4 tap(mobile)/ 9 tap(non-mobile) soft shadow, reuse URP's _SHADOWS_SOFT keyword to avoid using more multi_compile,
// but it may be still too costly for mobile even it is just 4 tap
#if _SHADOWS_SOFT && false // disabled soft shadow due to filter bug in 2021.3 or later
// SHADER_LIBRARY_VERSION_MAJOR is deprecated for Unity2022.2 or later, so we will use UNITY_VERSION instead
// see -> https://github.com/Cyanilux/URP_ShaderCodeTemplates/blob/main/URP_SimpleLitTemplate.shader#L145
#if UNITY_VERSION >= 202220 // (for URP 14 or above)
ShadowSamplingData shadowData;
shadowData.shadowOffset0 = float4(+_NiloToonSelfShadowParam.x,+_NiloToonSelfShadowParam.y,-_NiloToonSelfShadowParam.x,+_NiloToonSelfShadowParam.y);
shadowData.shadowOffset1 = float4(+_NiloToonSelfShadowParam.x,-_NiloToonSelfShadowParam.y,-_NiloToonSelfShadowParam.x,-_NiloToonSelfShadowParam.y);
shadowData.shadowmapSize = _NiloToonSelfShadowParam;
shadowData.softShadowQuality = SOFT_SHADOW_QUALITY_HIGH;
#else
ShadowSamplingData shadowData;
shadowData.shadowOffset0 = float4(+_NiloToonSelfShadowParam.x,+_NiloToonSelfShadowParam.y,0,0);
shadowData.shadowOffset1 = float4(-_NiloToonSelfShadowParam.x,+_NiloToonSelfShadowParam.y,0,0);
shadowData.shadowOffset2 = float4(+_NiloToonSelfShadowParam.x,-_NiloToonSelfShadowParam.y,0,0);
shadowData.shadowOffset3 = float4(-_NiloToonSelfShadowParam.x,-_NiloToonSelfShadowParam.y,0,0);
shadowData.shadowmapSize = _NiloToonSelfShadowParam;
#endif
selfShadowMapShadow = SampleShadowmapFiltered(TEXTURE2D_SHADOW_ARGS(_NiloToonCharSelfShadowMapRT, sampler_NiloToonCharSelfShadowMapRT),selfShadowmapUV,shadowData);
#endif
// 4 shadow options(Off, low, medium, high)
// the if-else chain pattern is similar to URP Shadows.hlsl -> SampleShadowmapFiltered(...)
@ -705,30 +693,22 @@ half4 ShadeMainLight(inout ToonSurfaceData surfaceData, Varyings input, ToonLigh
{
// use URP's SampleShadowmapFiltered(...) directly
ShadowSamplingData shadowSamplingData;
ShadowSamplingData_Nilo shadowSamplingData;
// just for low quality 4-tap, offset is half pixel uv size to 4 directions
float offset = _NiloToonSelfShadowParam.x / 2.0;
#if UNITY_VERSION >= 202220 // (for URP 14 or above)
shadowSamplingData.shadowOffset0 = float4(-offset, -offset, -offset, +offset);
shadowSamplingData.shadowOffset1 = float4(+offset, +offset, +offset, -offset);
shadowSamplingData.shadowmapSize = _NiloToonSelfShadowParam; // (1/w,1/h,w,h) of shadow map RT
shadowSamplingData.softShadowQuality = _NiloToonSelfShadowSoftShadowParam.x; // (1~3 quality)
#else
shadowSamplingData.shadowOffset0 = float4(+offset,+offset,0,0);
shadowSamplingData.shadowOffset1 = float4(-offset,+offset,0,0);
shadowSamplingData.shadowOffset2 = float4(+offset,-offset,0,0);
shadowSamplingData.shadowOffset3 = float4(-offset,-offset,0,0);
shadowSamplingData.shadowmapSize = _NiloToonSelfShadowParam;
#endif
selfShadowMapShadow = SampleShadowmapFiltered(TEXTURE2D_SHADOW_ARGS(_NiloToonCharSelfShadowMapRT, sampler_NiloToonCharSelfShadowMapRT), selfShadowmapUV, shadowSamplingData);
selfShadowMapShadow = SampleShadowmapFiltered_Nilo(TEXTURE2D_SHADOW_ARGS(_NiloToonCharSelfShadowMapRT, sampler_NiloToonCharSelfShadowMapRT_LinearClampCompare), selfShadowmapUV, shadowSamplingData);
// NiloToon added: add a stupid method to temp fix shadow acne, as URP's SampleShadowmapFiltered doesn't apply shadow bias cone for uv away from the center sample
selfShadowMapShadow = saturate(selfShadowMapShadow * 1.375);
// re-sharp shadow
// re-sharp soft shadow
if(_NiloToonSelfShadowSoftShadowParam.y)
{
selfShadowMapShadow = smoothstep(0.5-_NiloToonSelfShadowSoftShadowParam.z,0.5+_NiloToonSelfShadowSoftShadowParam.z,selfShadowMapShadow);
@ -738,47 +718,8 @@ half4 ShadeMainLight(inout ToonSurfaceData surfaceData, Varyings input, ToonLigh
{
// a simple shadow map sample. The hardware will perform a 1-tap bilinear filter,
// which is a no-cost filtering operation.
selfShadowMapShadow = SAMPLE_TEXTURE2D_SHADOW(_NiloToonCharSelfShadowMapRT, sampler_NiloToonCharSelfShadowMapRT, selfShadowmapUV);
selfShadowMapShadow = SAMPLE_TEXTURE2D_SHADOW(_NiloToonCharSelfShadowMapRT, sampler_NiloToonCharSelfShadowMapRT_LinearClampCompare, selfShadowmapUV);
}
// [Shadow test code, not used]
// URP16's high quality softshadow test code
#if 0
{
float attenuation;
ShadowSamplingData samplingData;
samplingData.shadowmapSize = _NiloToonSelfShadowParam;
float3 shadowCoord = selfShadowmapUV;
TEXTURE2D(ShadowMap) = _NiloToonCharSelfShadowMapRT;
SAMPLER_CMP(sampler_ShadowMap) = sampler_NiloToonCharSelfShadowMapRT;
//-------------------------------------------------------------------------------------------------------------------------
real fetchesWeights[16];
real2 fetchesUV[16];
SampleShadow_ComputeSamples_Tent_7x7(samplingData.shadowmapSize, shadowCoord.xy, fetchesWeights, fetchesUV);
attenuation = fetchesWeights[0] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[0].xy, shadowCoord.z))
+ fetchesWeights[1] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[1].xy, shadowCoord.z))
+ fetchesWeights[2] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[2].xy, shadowCoord.z))
+ fetchesWeights[3] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[3].xy, shadowCoord.z))
+ fetchesWeights[4] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[4].xy, shadowCoord.z))
+ fetchesWeights[5] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[5].xy, shadowCoord.z))
+ fetchesWeights[6] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[6].xy, shadowCoord.z))
+ fetchesWeights[7] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[7].xy, shadowCoord.z))
+ fetchesWeights[8] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[8].xy, shadowCoord.z))
+ fetchesWeights[9] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[9].xy, shadowCoord.z))
+ fetchesWeights[10] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[10].xy, shadowCoord.z))
+ fetchesWeights[11] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[11].xy, shadowCoord.z))
+ fetchesWeights[12] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[12].xy, shadowCoord.z))
+ fetchesWeights[13] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[13].xy, shadowCoord.z))
+ fetchesWeights[14] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[14].xy, shadowCoord.z))
+ fetchesWeights[15] * SAMPLE_TEXTURE2D_SHADOW(ShadowMap, sampler_ShadowMap, float3(fetchesUV[15].xy, shadowCoord.z));
//-------------------------------------------------------------------------------------------------------------------------
selfShadowMapShadow = attenuation;
//return selfShadowMapShadow;
}
#endif
// fadeout self shadow map if reaching the end of shadow distance (always use 2m from start fade to end fade)
float fadeTotalDistance = 1; // hardcode now, can expose to C# if needed
@ -894,6 +835,7 @@ half4 ShadeMainLight(inout ToonSurfaceData surfaceData, Varyings input, ToonLigh
// global volume -> shadow tint color
lightColorIndependentLitColor *= lerp(_GlobalCharacterOverallShadowTintColor,1,finalShadowArea);
lightColorIndependentLitColor *= lerp(lerp(_GlobalCharacterOverallShadowTintColorForNonSkinFace,_GlobalCharacterOverallShadowTintColorForSkinFace,max(lightingData.isSkinArea, lightingData.isFaceArea)),1,finalShadowArea);
#endif
// for all additive light logic to use in the following code(specular,rim light, hair strand specular....),
@ -1135,8 +1077,14 @@ half3 CalculateAdditiveSingleAdditionalLight(Light light, ToonLightingData light
// LdotV = is light infront of the character? (is light comes from camera's direction?)
half LdotV = dot(L,V);
// ------------------------------------------------
// [2D rim gradient]
// possible method to make rim light not that uniform in color
//lightAttenuation *= lerp(1, saturate(NdotL), _GlobalCinematic2DRimMaskStrength);
// ------------------------------------------------
// [dynamic style]
UNITY_BRANCH
if(_GlobalCinematic3DRimMaskStrength_DynamicStyle > 0)
{
// forcing the light comes from the "side direction" of the character
@ -1145,12 +1093,18 @@ half3 CalculateAdditiveSingleAdditionalLight(Light light, ToonLightingData light
half3 editedL = normalize(L+(-V * 0.999 * LdotV)); // can remove LdotV to produce "less bright+more stable" rim light
// perform dot(N,L), where L is always at the "side" of character
half editedNdotL = saturate(dot(N,editedL));
half width = _GlobalCinematic3DRimMaskBlur_DynamicStyle; // default 0.5
half midPoint = _GlobalCinematic3DRimMaskWidth_DynamicStyle; // default 0.5
editedNdotL = invLerpClamp(saturate(midPoint-width),saturate(midPoint+width),editedNdotL); // possible to optimize to C# passing start & end
half editedRim = pow(editedNdotL,_GlobalCinematic3DRimMaskSharpness_DynamicStyle);
lightAttenuation *= lerp(1,editedRim * 5.0,_GlobalCinematic3DRimMaskStrength_DynamicStyle);
}
// ------------------------------------------------
// [stable style]
// similar to PBR's DFG's Fresnel term ^2
UNITY_BRANCH
if(_GlobalCinematic3DRimMaskStrength_StableStyle > 0)
{
// Fresnel reflection(F) = F0 + (1-Fo) * (1-costheta)^5, where costheta is dot(N,V)
@ -1163,11 +1117,14 @@ half3 CalculateAdditiveSingleAdditionalLight(Light light, ToonLightingData light
}
// ------------------------------------------------
// [classic rim]
UNITY_BRANCH
if(_GlobalCinematic3DRimMaskStrength_ClassicStyle > 0)
{
half width = 0.02;
half midPoint = 0.7;
lightAttenuation *= lerp(1,smoothstep(midPoint-width,midPoint+width, sqrt(NdotL) * fresnelTerm),_GlobalCinematic3DRimMaskStrength_ClassicStyle);
half width =_GlobalCinematic3DRimMaskBlur_ClassicStyle; // default 0.02
half midPoint = _GlobalCinematic3DRimMaskWidth_ClassicStyle; // default 0.7
half rim = smoothstep(saturate(midPoint-width),saturate(midPoint+width), sqrt(NdotL) * fresnelTerm); // possible to optimize to C# passing start & end
rim = pow(rim, _GlobalCinematic3DRimMaskSharpness_ClassicStyle);
lightAttenuation *= lerp(1,rim,_GlobalCinematic3DRimMaskStrength_ClassicStyle);
}
// ------------------------------------------------

View File

@ -26,6 +26,7 @@
#define _MATCAP_BLEND 1
#define _ENVIRONMENTREFLECTIONS 1
#define _EMISSION 1
#define _EMISSION_ANIM_TINT_RAMPMAP 1
#define _BASEMAP_STACKING_LAYER1 1
#define _BASEMAP_STACKING_LAYER2 1
#define _BASEMAP_STACKING_LAYER3 1
@ -54,6 +55,7 @@
#define _FACE_MASK_ON 1
#define _ZOFFSETMAP 1
#define _OUTLINEWIDTHMAP 1
#define _OUTLINETINTCOLORMAP 1
#define _OUTLINEZOFFSETMAP 1
#define _DETAIL 1
#define _OVERRIDE_OUTLINECOLOR_BY_TEXTURE 1
@ -79,6 +81,7 @@
#define _DBUFFER 1
#define USE_FORWARD_PLUS 1
#define _LIGHT_LAYERS 1
#define _SCREEN_SPACE_OCCLUSION 1
// NiloToon global define
#define _NILOTOON_GLOBAL_ENABLE_SCREENSPACE_OUTLINE 1

View File

@ -260,6 +260,9 @@ TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
#if _EMISSION
sampler2D _EmissionMap;
TEXTURE2D(_EmissionMaskMap);
#if _EMISSION_ANIM_TINT_RAMPMAP
TEXTURE2D(_EmissionAnimTintRampMap);
#endif
#endif
#if _ENVIRONMENTREFLECTIONS
TEXTURE2D(_EnvironmentReflectionMaskMap);
@ -315,6 +318,9 @@ TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
#if _OUTLINEWIDTHMAP
sampler2D _OutlineWidthTex;
#endif
#if _OUTLINETINTCOLORMAP
sampler2D _OutlineTintColorMap;
#endif
#if _OUTLINEZOFFSETMAP
sampler2D _OutlineZOffsetMaskTex;
#endif
@ -385,7 +391,8 @@ TEXTURE2D(_NiloToonAverageShadowMapRT);
#endif
#if _NILOTOON_RECEIVE_SELF_SHADOW
TEXTURE2D(_NiloToonCharSelfShadowMapRT); SAMPLER_CMP(sampler_NiloToonCharSelfShadowMapRT);
TEXTURE2D(_NiloToonCharSelfShadowMapRT);
SAMPLER_CMP(sampler_NiloToonCharSelfShadowMapRT_LinearClampCompare); // need LinearClampCompare, else Unity6 will sample the shadow map in point filter
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -716,6 +723,7 @@ CBUFFER_START(UnityPerMaterial)
half3 _EmissionColor;
half _MultiplyBaseColorToEmissionColor;
half _MultiplyLightColorToEmissionColor;
float _EmissionAnimTintRampMapSpeed;
half _EmissionMapUseSingleChannelOnly;
half4 _EmissionMapSingleChannelMask;
half4 _EmissionMaskMapChannelMask;
@ -988,10 +996,10 @@ CBUFFER_START(UnityPerMaterial)
float _DepthTexRimLightAndShadowSafeViewDistance;
float _DepthTexRimLightIgnoreLightDir;
float _DepthTexShadowIgnoreLightDir;
float _DepthTexShadowFixedDirectionForFace;
float _DepthTexRimLightWidthMultiplier;
float _DepthTexRimLightWidthClampForFace;
float _DepthTexShadowWidthMultiplier;
float _UseDepthTexRimLightAndShadowWidthMultiplierFromVertexColor;
@ -1006,6 +1014,7 @@ CBUFFER_START(UnityPerMaterial)
half _DepthTexRimLightMixWithBaseMapColor;
half _DepthTexRimLightBlockByShadow;
float _DepthTexRimLightThresholdOffset;
float _DepthTexRimLightMinimumThresholdOffsetForFace;
float _DepthTexRimLightFadeoutRange;
half _DepthTexRimLight3DFallbackMidPoint;
@ -1047,7 +1056,7 @@ CBUFFER_START(UnityPerMaterial)
float _RenderOutline;
float _PerCharacterRenderOutline;
float _OutlineUseBakedSmoothNormal;
float _UnityCameraDepthTextureWriteOutlineExtrudedPosition;
// float _UnityCameraDepthTextureWriteOutlineExtrudedPosition; // removed since NiloToon0.17.10
float _OutlineUniformLengthInViewSpace;
half3 _OutlineTintColor;
half4 _OutlineTintColorSkinAreaOverride;
@ -1060,6 +1069,8 @@ CBUFFER_START(UnityPerMaterial)
float _OutlineWidth;
float _OutlineWidthExtraMultiplier;
float _OutlineApplyAutoWidthAdjustment;
float _OutlineBaseZOffset;
float _OutlineZOffset;
float _OutlineZOffsetForFaceArea;
@ -1070,6 +1081,7 @@ CBUFFER_START(UnityPerMaterial)
float _OutlineZOffsetMaskRemapEnd;
float _UseOutlineZOffsetMaskFromVertexColor;
float4 _OutlineZOffsetMaskFromVertexColor;
float _OutlineZOffsetMaskTexFromVertexColorInvertColor;
float _UseOutlineWidthMaskFromVertexColor;
float4 _OutlineWidthMaskFromVertexColor;
float4 _OutlineWidthTexChannelMask;
@ -1335,11 +1347,18 @@ half _GlobalAdditionalLightRimMaskPower;
half _GlobalAdditionalLightRimMaskSoftness;
half3 _GlobalVolumeBaseColorTintColor;
half3 _GlobalCharacterOverallShadowTintColor;
half3 _GlobalCharacterOverallShadowTintColorForSkinFace;
half3 _GlobalCharacterOverallShadowTintColorForNonSkinFace;
half _GlobalCharacterOverallShadowStrength;
half _GlobalCinematic3DRimMaskEnabled;
half _GlobalCinematic3DRimMaskStrength_ClassicStyle;
half _GlobalCinematic3DRimMaskSharpness_ClassicStyle;
half _GlobalCinematic3DRimMaskBlur_ClassicStyle;
half _GlobalCinematic3DRimMaskWidth_ClassicStyle;
half _GlobalCinematic3DRimMaskStrength_DynamicStyle;
half _GlobalCinematic3DRimMaskWidth_DynamicStyle;
half _GlobalCinematic3DRimMaskBlur_DynamicStyle;
half _GlobalCinematic3DRimMaskSharpness_DynamicStyle;
half _GlobalCinematic3DRimMaskStrength_StableStyle;
half _GlobalCinematic3DRimMaskSharpness_StableStyle;
@ -1725,7 +1744,7 @@ float3 GetPossibleBakedSmoothedNormalWS(VertexNormalInputs vertexNormalInputs, b
}
float3 TransformPositionWSToOutlinePositionWS(float width, VertexPositionInputs vertexPositionInputs, float3 extrudeDirectionWS)
{
width *= GetOutlineCameraFovAndDistanceFixMultiplier(vertexPositionInputs.positionVS.z, _CurrentCameraFOV, _GlobalOutlineWidthAutoAdjustToCameraDistanceAndFOV);
width *= GetOutlineCameraFovAndDistanceFixMultiplier(vertexPositionInputs.positionVS.z, _CurrentCameraFOV, _GlobalOutlineWidthAutoAdjustToCameraDistanceAndFOV * _OutlineApplyAutoWidthAdjustment);
// [normalize length in view space]
if(_OutlineUniformLengthInViewSpace)
@ -2009,7 +2028,7 @@ Varyings VertexShaderAllWork(Attributes input)
if( ShouldRenderOutline()
#if !NiloToonCharacterAreaStencilBufferFillPass
&& shouldOutlineUseBakedSmoothNormal
&& _UnityCameraDepthTextureWriteOutlineExtrudedPosition
&& false // _UnityCameraDepthTextureWriteOutlineExtrudedPosition, removed since NiloToon 0.17.10, not allow to use anymore
&& _NiloToonGlobalAllowUnityCameraDepthTextureWriteOutlineExtrudedPosition
#endif
)
@ -2105,10 +2124,14 @@ Varyings VertexShaderAllWork(Attributes input)
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Find out face area, and edit normalWS if vertex is within face area
// output normalWS
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
half4 lightingNormalWS_faceArea = GetLightingNormalWS_FaceArea(vertexNormalInput.normalWS, positionWS, GetUV(output));
output.normalWS_averageShadowAttenuation.xyz = lightingNormalWS_faceArea.xyz; //normalized already by GetLightingNormalWS_FaceArea(...)
output.normalWS_averageShadowAttenuation.xyz = vertexNormalInput.normalWS;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// faceArea
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
half faceArea = GetFaceArea(GetUV(output));
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// viewDirTS
@ -2133,11 +2156,17 @@ Varyings VertexShaderAllWork(Attributes input)
// Only apply to _CameraColorTexture's outline pass(NiloToonSelfOutlinePass), don't apply to any depth texture pass
#if NiloToonSelfOutlinePass
// we have separated settings for "face" and "not face" vertices
float outlineZOffset = lerp(_OutlineZOffset,_OutlineZOffsetForFaceArea,lightingNormalWS_faceArea.w);
float outlineZOffset = lerp(_OutlineZOffset,_OutlineZOffsetForFaceArea,faceArea);
// [ZOffset mask from vertex color]
outlineZOffset *= _UseOutlineZOffsetMaskFromVertexColor? dot(input.color, _OutlineZOffsetMaskFromVertexColor) : 1;
if(_UseOutlineZOffsetMaskFromVertexColor)
{
float zoffsetFromVertexColor = dot(input.color, _OutlineZOffsetMaskFromVertexColor);
zoffsetFromVertexColor = _OutlineZOffsetMaskTexFromVertexColorInvertColor ? 1 - zoffsetFromVertexColor : zoffsetFromVertexColor;
outlineZOffset *= zoffsetFromVertexColor;
}
// [ZOffset mask texture]
#if _OUTLINEZOFFSETMAP
float outlineZOffsetMask = 1;
@ -2165,7 +2194,7 @@ Varyings VertexShaderAllWork(Attributes input)
// If we don't do this, once camera is far away, zoffset will become not enough because outline width keep growing larger
// also stop reduce zoffset when camera is too close using max(1,x)
// TODO: we should share the GetOutlineCameraFovAndDistanceFixMultiplier() call to save some performance?
outlineZOffset *= max(1,GetOutlineCameraFovAndDistanceFixMultiplier(positionVS.z, _CurrentCameraFOV, _GlobalOutlineWidthAutoAdjustToCameraDistanceAndFOV) / 0.0025);
outlineZOffset *= max(1,GetOutlineCameraFovAndDistanceFixMultiplier(positionVS.z, _CurrentCameraFOV, _GlobalOutlineWidthAutoAdjustToCameraDistanceAndFOV * _OutlineApplyAutoWidthAdjustment) / 0.0025);
ZOffsetFinalSum += -outlineZOffset;
#endif
@ -2305,7 +2334,7 @@ Varyings VertexShaderAllWork(Attributes input)
// but here we don't hardcode 0, instead we use a uniform variable(_IndirectLightFlatten) to control the normal,
// which is slower but allow more flexibility for user
#if NiloToonIsAnyLitColorPass
half3 normalWSForSH = lightingNormalWS_faceArea.xyz;
half3 normalWSForSH = output.normalWS_averageShadowAttenuation.xyz;
normalWSForSH *= 1-_IndirectLightFlatten; // make the normal become 0 when _IndirectLightFlatten is 1
half3 SH = SampleSH(normalWSForSH) * _GlobalIndirectLightMultiplier;
@ -2338,7 +2367,7 @@ Varyings VertexShaderAllWork(Attributes input)
#if NiloToonDepthOnlyOrDepthNormalPass && _ISFACE
float cameraDepthTextureZOffsetMask = 1;
#if NeedFaceMaskArea
cameraDepthTextureZOffsetMask = lightingNormalWS_faceArea.w;
cameraDepthTextureZOffsetMask = faceArea;
#endif
// zoffset should be always greater or equal to depthDiffThreshold, to avoid face cast 2D depth texture self shadow
ZOffsetFinalSum += -_FaceAreaCameraDepthTextureZWriteOffset * cameraDepthTextureZOffsetMask * _NiloToonGlobalAllowUnityCameraDepthTextureWriteFaceZOffset;
@ -2885,6 +2914,12 @@ half3 GetFinalEmissionColor(Varyings input, half3 baseColor)
emissionResult *= _EmissionColor.rgb * _EmissionIntensity;
emissionResult *= lerp(1,baseColor,_MultiplyBaseColorToEmissionColor); // let user optionally mix base color to emission color
// anim tint ramp map
#if _EMISSION_ANIM_TINT_RAMPMAP
half3 rampSampleColor = SAMPLE_TEXTURE2D_LOD(_EmissionAnimTintRampMap, sampler_linear_clamp, half2(frac(_Time.y * _EmissionAnimTintRampMapSpeed), 0.5),0).rgb;
emissionResult *= rampSampleColor;
#endif
// mask by an optional mask texture
// (decided to not use shader_feature for this mask section, else too much shader_feature is used)
float2 maskMapUV = GetUV(input);
@ -3126,6 +3161,8 @@ struct NiloToonPerAdditionalLightData
half injectIntoMainLightBackLightOcclusion2D;
half injectIntoMainLightBackLightOcclusion3D;
bool ignoreRenderingLayer;
};
NiloToonPerAdditionalLightData GetNiloToonPerAdditionalLightData(int lightIndex)
@ -3149,12 +3186,14 @@ NiloToonPerAdditionalLightData GetNiloToonPerAdditionalLightData(int lightIndex)
data.injectIntoMainLightBackLightOcclusion2D = niloToonPerUnityLightData2.x;
data.injectIntoMainLightBackLightOcclusion3D = niloToonPerUnityLightData2.y;
data.ignoreRenderingLayer = niloToonPerUnityLightData2.z > 0.5;
return data;
}
#endif
// similar to URP's LitForwardPass.hlsl -> InitializeInputData()
ToonLightingData InitializeLightingData(Varyings input, half3 normalTS, float facing)
ToonLightingData InitializeLightingData(Varyings input, half3 normalTS, float facing, half faceArea)
{
ToonLightingData lightingData;
@ -3222,7 +3261,7 @@ ToonLightingData InitializeLightingData(Varyings input, half3 normalTS, float fa
// if is not face: don't edit normal, use mesh's normal directly
// normalWS face area edit already done in vertex shader
// so here we don't need to edit normalWS
lightingData.isFaceArea = GetFaceArea(lightingData.uv);
lightingData.isFaceArea = faceArea;
lightingData.isSkinArea = GetSkinArea(lightingData.uv);
@ -3397,9 +3436,9 @@ ToonLightingData InitializeLightingData(Varyings input, half3 normalTS, float fa
#endif
Light light = GetAdditionalLight(lightIndex, input.positionWS_ZOffsetFinalSum.xyz); // since URP10, you must provide shadowMask in order to receive shadowmap
NiloToonPerAdditionalLightData niloToonPerAdditionalLightData = GetNiloToonPerAdditionalLightData(lightIndex);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
if (niloToonPerAdditionalLightData.ignoreRenderingLayer || IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
// support additional directional light's light cookie
@ -3411,8 +3450,6 @@ ToonLightingData InitializeLightingData(Varyings input, half3 normalTS, float fa
// - don't * light.shadowAttenuation, shadow map looks ugly (shadow map doesn't exist for additional directional light in URP)
half3 additionalLightPixelColor = light.color * light.distanceAttenuation;
NiloToonPerAdditionalLightData niloToonPerAdditionalLightData = GetNiloToonPerAdditionalLightData(lightIndex);
half Avg3AdditionalLightPixelColor = NiloAvg3(additionalLightPixelColor);
// simple sum, don't need to multiply any dot(N,L) mask, keep the color sum clean and blurry!
@ -3437,9 +3474,10 @@ ToonLightingData InitializeLightingData(Varyings input, half3 normalTS, float fa
// TODO: try characterBoundCenterPosWS for GetAdditionalLight(...)
Light light = GetAdditionalLight(lightIndex, lightingData.positionWS); // not provide shadowMask in order to not receive additional light's shadowmap
NiloToonPerAdditionalLightData niloToonPerAdditionalLightData = GetNiloToonPerAdditionalLightData(lightIndex);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
if (niloToonPerAdditionalLightData.ignoreRenderingLayer || IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
// support additional directional light's light cookie
@ -3453,7 +3491,7 @@ ToonLightingData InitializeLightingData(Varyings input, half3 normalTS, float fa
// - optionally apply saturate() to light.distanceAttenuation to cap it in 0~1, since it is 1/(d^2), it can go very high when light is close to character where d < 1
half3 additionalLightPixelColor = light.color * lerp(saturate(light.distanceAttenuation),light.distanceAttenuation,_GlobalAdditionalLightInjectIntoMainLightColor_AllowCloseLightOverBright);
NiloToonPerAdditionalLightData niloToonPerAdditionalLightData = GetNiloToonPerAdditionalLightData(lightIndex);
half Avg3AdditionalLightPixelColor = NiloAvg3(additionalLightPixelColor);
@ -3502,6 +3540,15 @@ ToonLightingData InitializeLightingData(Varyings input, half3 normalTS, float fa
// [final override mainLight]
mainLight.direction = _GlobalUserOverriddenFinalMainLightDirWSParam.w ? _GlobalUserOverriddenFinalMainLightDirWSParam.xyz : mainLight.direction;
mainLight.color = _GlobalUserOverriddenFinalMainLightColorParam.w ? _GlobalUserOverriddenFinalMainLightColorParam.rgb : mainLight.color;
/*
// TODO: possible mainLight.color tonemapping?
half uselightColorTonemapping = sin(_Time.y * 3.1415 * 2) > 0;
if(uselightColorTonemapping > 0)
{
mainLight.color = lerp(mainLight.color, mainLight.color / (mainLight.color+1.0), uselightColorTonemapping);
}
*/
// [_ReceiveSelfShadowMappingPosOffset]
// this uniform will control the extra depth bias of URP shadowmap,
@ -3877,13 +3924,11 @@ half3 ShadeAllLights(inout ToonSurfaceData surfaceData, ToonLightingData lightin
#endif
Light light = GetAdditionalLight(lightIndex, input.positionWS_ZOffsetFinalSum.xyz, shadowMask); // since URP10, you must provide shadowMask in order to receive shadowmap
NiloToonPerAdditionalLightData niloToonPerAdditionalLightData = GetNiloToonPerAdditionalLightData(lightIndex);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
if (niloToonPerAdditionalLightData.ignoreRenderingLayer || IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
NiloToonPerAdditionalLightData niloToonPerAdditionalLightData = GetNiloToonPerAdditionalLightData(lightIndex);
// Different function(simpler and faster function) used to shade additional lights.
additionalLightSum += CalculateAdditiveSingleAdditionalLight(light, lightingData) * niloToonPerAdditionalLightData.additiveLightIntensity;
}
@ -3898,13 +3943,11 @@ half3 ShadeAllLights(inout ToonSurfaceData surfaceData, ToonLightingData lightin
// loop can include any additional directional/point/spot lights
LIGHT_LOOP_BEGIN(pixelLightCount)
Light light = GetAdditionalLight(lightIndex, input.positionWS_ZOffsetFinalSum.xyz, shadowMask); // you must provide shadowMask in order to receive additional light's shadowmap
NiloToonPerAdditionalLightData niloToonPerAdditionalLightData = GetNiloToonPerAdditionalLightData(lightIndex);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
if (niloToonPerAdditionalLightData.ignoreRenderingLayer || IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
NiloToonPerAdditionalLightData niloToonPerAdditionalLightData = GetNiloToonPerAdditionalLightData(lightIndex);
// A different function(simpler and faster function) is used to shade additional lights.
// which do not look as good as ShadeMainLight, but it is faster and support NiloToonCinematicRimLightVolume
additionalLightSum += CalculateAdditiveSingleAdditionalLight(light, lightingData) * niloToonPerAdditionalLightData.additiveLightIntensity;
@ -3974,6 +4017,11 @@ void ApplyOutlineColorOverrideByTexture(inout half3 originalSurfaceColor, ToonLi
void ApplySurfaceToClassicOutlineColorEdit(inout half3 originalSurfaceColor, ToonSurfaceData surfaceData, ToonLightingData lightingData)
{
half3 outlineTintColor = lerp(_OutlineTintColor, _OutlineTintColorSkinAreaOverride.rgb, _OutlineTintColorSkinAreaOverride.a * lightingData.isSkinArea);
#if _OUTLINETINTCOLORMAP
outlineTintColor *= tex2D(_OutlineTintColorMap, lightingData.uv);
#endif
originalSurfaceColor *= outlineTintColor * _PerCharacterOutlineColorTint * _GlobalOutlineTintColor;
originalSurfaceColor *= lerp(_OutlineOcclusionAreaTintColor, 1, surfaceData.occlusion);
@ -4298,7 +4346,7 @@ void ApplyOverrideOutputAlpha(inout half outputAlpha)
#endif
}
void InitAllData(inout Varyings input, float facing, out UVData uvData, out ToonLightingData lightingData, out ToonSurfaceData surfaceData)
void InitAllData(inout Varyings input, float facing, half faceArea, out UVData uvData, out ToonLightingData lightingData, out ToonSurfaceData surfaceData)
{
//////////////////////////////////////////////////////////////////////////////////////////
// Apply Parallax, edit uv before any uv copy or texture sampling
@ -4326,7 +4374,7 @@ void InitAllData(inout Varyings input, float facing, out UVData uvData, out Toon
normalTS = ApplyDetailNormal(detailUV, normalTS, detailMask);
#endif
lightingData = InitializeLightingData(input,normalTS, facing);
lightingData = InitializeLightingData(input,normalTS, facing, faceArea);
// fill-in remaining UVData slots
uvData.allUVs[4] = lightingData.matcapUV * 0.5 + 0.5;
@ -4401,6 +4449,15 @@ void FragmentShaderAllWork(Varyings input, FRONT_FACE_TYPE IsFrontFace : FRONT_F
input.normalWS_averageShadowAttenuation.xyz *= facing;
input.smoothedNormalWS *= facing;
#endif
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Find out face area, and edit normalWS if pixel is within face area
// (must do this in fragment shader, else if we interpolate normalWS result based on vertex level "IsFace", it looks very bad)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
half4 lightingNormal_faceArea = GetLightingNormalWS_FaceArea(input.normalWS_averageShadowAttenuation.xyz,input.positionWS_ZOffsetFinalSum.xyz,input.uv01.xy);
input.normalWS_averageShadowAttenuation.xyz = lightingNormal_faceArea.xyz;
half faceArea = lightingNormal_faceArea.w;
//////////////////////////////////////////////////////////////////////////////////////////
// insert a performance debug minimum shader early exit section here
@ -4419,7 +4476,7 @@ void FragmentShaderAllWork(Varyings input, FRONT_FACE_TYPE IsFrontFace : FRONT_F
UVData uvData;
ToonLightingData lightingData;
ToonSurfaceData surfaceData;
InitAllData(input, facing, uvData, lightingData, surfaceData);
InitAllData(input, facing, faceArea, uvData, lightingData, surfaceData);
//////////////////////////////////////////////////////////////////////////////////////////
// insert debug shading early exit section here
@ -4562,7 +4619,7 @@ half BaseColorAlphaClipTest(Varyings input, FRONT_FACE_TYPE IsFrontFace : FRONT_
UVData uvData;
ToonLightingData lightingData;
ToonSurfaceData surfaceData;
InitAllData(input, facing, uvData, lightingData, surfaceData);
InitAllData(input, facing, 0, uvData, lightingData, surfaceData);
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
@ -4647,18 +4704,24 @@ float4 BaseColorAlphaClipTest_AndNiloToonPrepassBufferColorOutput(Varyings input
// When the RT depth and MSAA format of _CameraDepthTexture match _NiloToonPrepassBufferRT,
// we can perform precise depth comparisons to reject "scene blocked char pixels."
// but still, it is possible to have problems similar Shadow acne, so a very small depth bias may help
float depthBias;
// Bias should not be affected by platform, since platform difference (Z reverse) is handled inside Convert_SV_PositionZ_ToLinearViewSpaceDepth()'s LinearEyeDepth()
// DX11 = - correct , + wrong
// Vulkan = - correct , + wrong
// OPENGLES = - correct , + wrong
// -0.00003 is the minimum number to work for a 24bit depth texture
// no reasonable value works for 16bit depth texture (should we allow user to increase it? expose in renderer feature?)
depthBias = - 0.0001; // we use a "~3x larger than -0.00003" bias just in case
float depthBias = - 0.0001; // we use a "~3.3x larger than -0.00003" bias just in case
// Add gradient bias for edges to fix pixel holes
float2 depthGradient = float2(ddx(selfLinearDepth), ddy(selfLinearDepth));
float gradientBias = length(depthGradient) * 0.5;
depthBias = depthBias - gradientBias;
if(sceneLinearDepth < selfLinearDepth + depthBias)
return 0;
float isFace = GetFaceArea(input.uv01.xy);
// if character pixel is still visible(not blocked by scene), draw to _NiloToonPrepassBufferTex
return float4(0,_AllowNiloToonBloomCharacterAreaOverride * _AllowedNiloToonBloomOverrideStrength,0,1);
return float4(isFace,_AllowNiloToonBloomCharacterAreaOverride * _AllowedNiloToonBloomOverrideStrength,0,1);
}

View File

@ -505,19 +505,7 @@ void LitPassFragment(
inputData.bakedGI = lerp(inputData.bakedGI, _NiloToonGlobalEnviGIOverride.rgb, _NiloToonGlobalEnviGIOverride.a);
//==========================================================================================================================================================
half4 color;
//[NiloToon] add: Unlit mode check
if(_UnlitMode > 0.5)
{
// Unlit mode: just use albedo with brightness multiplier
color = half4(surfaceData.albedo * _BrightnessMultiplier, surfaceData.alpha);
}
else
{
// Normal lit mode
color = UniversalFragmentPBR(inputData, surfaceData);
}
half4 color = UniversalFragmentPBR(inputData, surfaceData);
//[NiloToon] add:
//==========================================================================================================================================================

View File

@ -12,6 +12,8 @@ Shader "Hidden/Universal Render Pipeline/NiloToonBloom"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Filtering.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl"
#include "../../../ShaderLibrary/NiloUtilityHLSL/NiloScaledScreenParamUtil.hlsl"
#include "../../../ShaderLibrary/NiloUtilityHLSL/NiloPrepassBufferTextureUtil.hlsl"
#include "../../../ShaderLibrary/NiloUtilityHLSL/NiloHSVRGBConvert.hlsl"
#if UNITY_VERSION < 202220
@ -36,7 +38,7 @@ Shader "Hidden/Universal Render Pipeline/NiloToonBloom"
// [NiloToon added]
//==========================================================
TEXTURE2D_X(_NiloToonPrepassBufferTex);
// _NiloToonPrepassBufferTex is now defined in NiloPrepassBufferTextureUtil.hlsl
float _NiloToonBloomCharacterAreaThreshold;
float _NiloToonBloomCharacterAreaThresholdKnee;

View File

@ -20,6 +20,8 @@ Shader "Hidden/Universal Render Pipeline/NiloToonUberPost"
// [NiloToon added]
//==========================================================
#include "../../../ShaderLibrary/NiloUtilityHLSL/NiloScaledScreenParamUtil.hlsl"
#include "../../../ShaderLibrary/NiloUtilityHLSL/NiloPrepassBufferTextureUtil.hlsl"
#include "../../../ShaderLibrary/NiloUtilityHLSL/GranTurismoTonemap/NiloGranTurismoTonemap.hlsl"
#include "../../../ShaderLibrary/NiloUtilityHLSL/NiloCustomACES.hlsl"
#include "../../../ShaderLibrary/NiloUtilityHLSL/KhronosPBRNeutralTonemapper/NiloKhronosPBRNeutralTonemap.hlsl"
@ -66,7 +68,7 @@ Shader "Hidden/Universal Render Pipeline/NiloToonUberPost"
// [NiloToon added]
//==========================================================
TEXTURE2D_X(_NiloToonPrepassBufferTex);
// _NiloToonPrepassBufferTex is now defined in NiloPrepassBufferTextureUtil.hlsl
half _NiloToonBloomCharacterAreaIntensity;
half _NiloToonTonemappingCharacterAreaRemove;

Some files were not shown because too many files have changed in this diff Show More