补齐备份工程打开依赖
This commit is contained in:
@@ -1,2 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52abdb4a4468700439c02356e8f3eb64
|
||||
guid: 52abdb4a4468700439c02356e8f3eb64
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
9
Assets/Plugins/IngameDebugConsole.meta
Normal file
9
Assets/Plugins/IngameDebugConsole.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c57523b63ddb094b835b6613da12763
|
||||
folderAsset: yes
|
||||
timeCreated: 1596819199
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Plugins/IngameDebugConsole/Android.meta
Normal file
9
Assets/Plugins/IngameDebugConsole/Android.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d7d7a61a5341904eb3c65af025b1d86
|
||||
folderAsset: yes
|
||||
timeCreated: 1510075633
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
// Credit: https://stackoverflow.com/a/41018028/2373034
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class DebugLogLogcatListener : AndroidJavaProxy
|
||||
{
|
||||
private Queue<string> queuedLogs;
|
||||
private AndroidJavaObject nativeObject;
|
||||
|
||||
public DebugLogLogcatListener() : base( "com.yasirkula.unity.DebugConsoleLogcatLogReceiver" )
|
||||
{
|
||||
queuedLogs = new Queue<string>( 16 );
|
||||
}
|
||||
|
||||
~DebugLogLogcatListener()
|
||||
{
|
||||
Stop();
|
||||
|
||||
if( nativeObject != null )
|
||||
nativeObject.Dispose();
|
||||
}
|
||||
|
||||
public void Start( string arguments )
|
||||
{
|
||||
if( nativeObject == null )
|
||||
nativeObject = new AndroidJavaObject( "com.yasirkula.unity.DebugConsoleLogcatLogger" );
|
||||
|
||||
nativeObject.Call( "Start", this, arguments );
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if( nativeObject != null )
|
||||
nativeObject.Call( "Stop" );
|
||||
}
|
||||
|
||||
public void OnLogReceived( string log )
|
||||
{
|
||||
queuedLogs.Enqueue( log );
|
||||
}
|
||||
|
||||
public string GetLog()
|
||||
{
|
||||
if( queuedLogs.Count > 0 )
|
||||
return queuedLogs.Dequeue();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd3b7385882055d4a8c2b91deb6b2470
|
||||
timeCreated: 1510076185
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Plugins/IngameDebugConsole/Android/IngameDebugConsole.aar
Normal file
BIN
Assets/Plugins/IngameDebugConsole/Android/IngameDebugConsole.aar
Normal file
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf909fab1c14af446b0a854de42289b2
|
||||
timeCreated: 1510086220
|
||||
licenseType: Free
|
||||
PluginImporter:
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
data:
|
||||
first:
|
||||
Android: Android
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Plugins/IngameDebugConsole/Editor.meta
Normal file
9
Assets/Plugins/IngameDebugConsole/Editor.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86f54622630720f4abe279acdbb8886f
|
||||
folderAsset: yes
|
||||
timeCreated: 1561217660
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,160 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
[CustomEditor( typeof( DebugLogManager ) )]
|
||||
public class DebugLogManagerEditor : Editor
|
||||
{
|
||||
private SerializedProperty singleton;
|
||||
private SerializedProperty minimumHeight;
|
||||
private SerializedProperty enableHorizontalResizing;
|
||||
private SerializedProperty resizeFromRight;
|
||||
private SerializedProperty minimumWidth;
|
||||
private SerializedProperty enablePopup;
|
||||
private SerializedProperty startInPopupMode;
|
||||
private SerializedProperty startMinimized;
|
||||
private SerializedProperty toggleWithKey;
|
||||
private SerializedProperty toggleKey;
|
||||
private SerializedProperty enableSearchbar;
|
||||
private SerializedProperty topSearchbarMinWidth;
|
||||
private SerializedProperty receiveLogsWhileInactive;
|
||||
private SerializedProperty receiveInfoLogs;
|
||||
private SerializedProperty receiveWarningLogs;
|
||||
private SerializedProperty receiveErrorLogs;
|
||||
private SerializedProperty receiveExceptionLogs;
|
||||
private SerializedProperty captureLogTimestamps;
|
||||
private SerializedProperty alwaysDisplayTimestamps;
|
||||
private SerializedProperty queuedLogLimit;
|
||||
private SerializedProperty clearCommandAfterExecution;
|
||||
private SerializedProperty commandHistorySize;
|
||||
private SerializedProperty showCommandSuggestions;
|
||||
private SerializedProperty receiveLogcatLogsInAndroid;
|
||||
private SerializedProperty logcatArguments;
|
||||
private SerializedProperty avoidScreenCutout;
|
||||
private SerializedProperty popupAvoidsScreenCutout;
|
||||
private SerializedProperty autoFocusOnCommandInputField;
|
||||
|
||||
private readonly GUIContent receivedLogTypesLabel = new GUIContent( "Received Log Types", "Only these logs will be received by the console window, other logs will simply be skipped" );
|
||||
private readonly GUIContent receiveInfoLogsLabel = new GUIContent( "Info" );
|
||||
private readonly GUIContent receiveWarningLogsLabel = new GUIContent( "Warning" );
|
||||
private readonly GUIContent receiveErrorLogsLabel = new GUIContent( "Error" );
|
||||
private readonly GUIContent receiveExceptionLogsLabel = new GUIContent( "Exception" );
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
singleton = serializedObject.FindProperty( "singleton" );
|
||||
minimumHeight = serializedObject.FindProperty( "minimumHeight" );
|
||||
enableHorizontalResizing = serializedObject.FindProperty( "enableHorizontalResizing" );
|
||||
resizeFromRight = serializedObject.FindProperty( "resizeFromRight" );
|
||||
minimumWidth = serializedObject.FindProperty( "minimumWidth" );
|
||||
enablePopup = serializedObject.FindProperty( "enablePopup" );
|
||||
startInPopupMode = serializedObject.FindProperty( "startInPopupMode" );
|
||||
startMinimized = serializedObject.FindProperty( "startMinimized" );
|
||||
toggleWithKey = serializedObject.FindProperty( "toggleWithKey" );
|
||||
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
|
||||
toggleKey = serializedObject.FindProperty( "toggleBinding" );
|
||||
#else
|
||||
toggleKey = serializedObject.FindProperty( "toggleKey" );
|
||||
#endif
|
||||
enableSearchbar = serializedObject.FindProperty( "enableSearchbar" );
|
||||
topSearchbarMinWidth = serializedObject.FindProperty( "topSearchbarMinWidth" );
|
||||
receiveLogsWhileInactive = serializedObject.FindProperty( "receiveLogsWhileInactive" );
|
||||
receiveInfoLogs = serializedObject.FindProperty( "receiveInfoLogs" );
|
||||
receiveWarningLogs = serializedObject.FindProperty( "receiveWarningLogs" );
|
||||
receiveErrorLogs = serializedObject.FindProperty( "receiveErrorLogs" );
|
||||
receiveExceptionLogs = serializedObject.FindProperty( "receiveExceptionLogs" );
|
||||
captureLogTimestamps = serializedObject.FindProperty( "captureLogTimestamps" );
|
||||
alwaysDisplayTimestamps = serializedObject.FindProperty( "alwaysDisplayTimestamps" );
|
||||
queuedLogLimit = serializedObject.FindProperty( "queuedLogLimit" );
|
||||
clearCommandAfterExecution = serializedObject.FindProperty( "clearCommandAfterExecution" );
|
||||
commandHistorySize = serializedObject.FindProperty( "commandHistorySize" );
|
||||
showCommandSuggestions = serializedObject.FindProperty( "showCommandSuggestions" );
|
||||
receiveLogcatLogsInAndroid = serializedObject.FindProperty( "receiveLogcatLogsInAndroid" );
|
||||
logcatArguments = serializedObject.FindProperty( "logcatArguments" );
|
||||
avoidScreenCutout = serializedObject.FindProperty( "avoidScreenCutout" );
|
||||
popupAvoidsScreenCutout = serializedObject.FindProperty( "popupAvoidsScreenCutout" );
|
||||
autoFocusOnCommandInputField = serializedObject.FindProperty( "autoFocusOnCommandInputField" );
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField( singleton );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField( minimumHeight );
|
||||
|
||||
EditorGUILayout.PropertyField( enableHorizontalResizing );
|
||||
if( enableHorizontalResizing.boolValue )
|
||||
{
|
||||
DrawSubProperty( resizeFromRight );
|
||||
DrawSubProperty( minimumWidth );
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField( avoidScreenCutout );
|
||||
DrawSubProperty( popupAvoidsScreenCutout );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField( enablePopup );
|
||||
if( enablePopup.boolValue )
|
||||
DrawSubProperty( startInPopupMode );
|
||||
else
|
||||
DrawSubProperty( startMinimized );
|
||||
|
||||
EditorGUILayout.PropertyField( toggleWithKey );
|
||||
if( toggleWithKey.boolValue )
|
||||
DrawSubProperty( toggleKey );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField( enableSearchbar );
|
||||
if( enableSearchbar.boolValue )
|
||||
DrawSubProperty( topSearchbarMinWidth );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField( receiveLogsWhileInactive );
|
||||
|
||||
EditorGUILayout.PrefixLabel( receivedLogTypesLabel );
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField( receiveInfoLogs, receiveInfoLogsLabel );
|
||||
EditorGUILayout.PropertyField( receiveWarningLogs, receiveWarningLogsLabel );
|
||||
EditorGUILayout.PropertyField( receiveErrorLogs, receiveErrorLogsLabel );
|
||||
EditorGUILayout.PropertyField( receiveExceptionLogs, receiveExceptionLogsLabel );
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUILayout.PropertyField( receiveLogcatLogsInAndroid );
|
||||
if( receiveLogcatLogsInAndroid.boolValue )
|
||||
DrawSubProperty( logcatArguments );
|
||||
|
||||
EditorGUILayout.PropertyField( captureLogTimestamps );
|
||||
if( captureLogTimestamps.boolValue )
|
||||
DrawSubProperty( alwaysDisplayTimestamps );
|
||||
|
||||
EditorGUILayout.PropertyField( queuedLogLimit );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField( clearCommandAfterExecution );
|
||||
EditorGUILayout.PropertyField( commandHistorySize );
|
||||
EditorGUILayout.PropertyField( showCommandSuggestions );
|
||||
EditorGUILayout.PropertyField( autoFocusOnCommandInputField );
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
DrawPropertiesExcluding( serializedObject, "m_Script" );
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void DrawSubProperty( SerializedProperty property )
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField( property );
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c23e5c521cb0c54b9a638b2a653d1d3
|
||||
timeCreated: 1561217671
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "IngameDebugConsole.Editor",
|
||||
"references": [
|
||||
"IngameDebugConsole.Runtime"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 466e67dabd1db22468246c39eddb6c3f
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "IngameDebugConsole.Runtime",
|
||||
"references": [
|
||||
"Unity.InputSystem"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3de88c88fbbb8f944b9210d496af9762
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
Assets/Plugins/IngameDebugConsole/README.txt
Normal file
7
Assets/Plugins/IngameDebugConsole/README.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
= In-game Debug Console (v1.6.2) =
|
||||
|
||||
Documentation: https://github.com/yasirkula/UnityIngameDebugConsole
|
||||
FAQ: https://github.com/yasirkula/UnityIngameDebugConsole#faq
|
||||
E-mail: yasirkula@gmail.com
|
||||
|
||||
You can simply place the IngameDebugConsole prefab to your scene. Hovering the cursor over its properties in the Inspector will reveal explanatory tooltips.
|
||||
8
Assets/Plugins/IngameDebugConsole/README.txt.meta
Normal file
8
Assets/Plugins/IngameDebugConsole/README.txt.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: edf2ac73f7bc3064c96d53009106dc53
|
||||
timeCreated: 1563307881
|
||||
licenseType: Free
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Plugins/IngameDebugConsole/Scripts.meta
Normal file
9
Assets/Plugins/IngameDebugConsole/Scripts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 860c08388401a6d4e858fe4910ea9337
|
||||
folderAsset: yes
|
||||
timeCreated: 1465930645
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
119
Assets/Plugins/IngameDebugConsole/Scripts/CircularBuffer.cs
Normal file
119
Assets/Plugins/IngameDebugConsole/Scripts/CircularBuffer.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
// #define RESET_REMOVED_ELEMENTS
|
||||
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class CircularBuffer<T>
|
||||
{
|
||||
private T[] arr;
|
||||
private int startIndex;
|
||||
|
||||
public int Count { get; private set; }
|
||||
public T this[int index] { get { return arr[( startIndex + index ) % arr.Length]; } }
|
||||
|
||||
public CircularBuffer( int capacity )
|
||||
{
|
||||
arr = new T[capacity];
|
||||
}
|
||||
|
||||
// Old elements are overwritten when capacity is reached
|
||||
public void Add( T value )
|
||||
{
|
||||
if( Count < arr.Length )
|
||||
arr[Count++] = value;
|
||||
else
|
||||
{
|
||||
arr[startIndex] = value;
|
||||
if( ++startIndex >= arr.Length )
|
||||
startIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DynamicCircularBuffer<T>
|
||||
{
|
||||
private T[] arr;
|
||||
private int startIndex;
|
||||
|
||||
public int Count { get; private set; }
|
||||
public int Capacity { get { return arr.Length; } }
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
get { return arr[( startIndex + index ) % arr.Length]; }
|
||||
set { arr[( startIndex + index ) % arr.Length] = value; }
|
||||
}
|
||||
|
||||
public DynamicCircularBuffer( int initialCapacity = 2 )
|
||||
{
|
||||
arr = new T[initialCapacity];
|
||||
}
|
||||
|
||||
public void Add( T value )
|
||||
{
|
||||
if( Count >= arr.Length )
|
||||
{
|
||||
int prevSize = arr.Length;
|
||||
int newSize = prevSize > 0 ? prevSize * 2 : 2; // Size must be doubled (at least), or the shift operation below must consider IndexOutOfRange situations
|
||||
|
||||
System.Array.Resize( ref arr, newSize );
|
||||
|
||||
if( startIndex > 0 )
|
||||
{
|
||||
if( startIndex <= ( prevSize - 1 ) / 2 )
|
||||
{
|
||||
// Move elements [0,startIndex) to the end
|
||||
for( int i = 0; i < startIndex; i++ )
|
||||
{
|
||||
arr[i + prevSize] = arr[i];
|
||||
#if RESET_REMOVED_ELEMENTS
|
||||
arr[i] = default( T );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move elements [startIndex,prevSize) to the end
|
||||
int delta = newSize - prevSize;
|
||||
for( int i = prevSize - 1; i >= startIndex; i-- )
|
||||
{
|
||||
arr[i + delta] = arr[i];
|
||||
#if RESET_REMOVED_ELEMENTS
|
||||
arr[i] = default( T );
|
||||
#endif
|
||||
}
|
||||
|
||||
startIndex += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this[Count++] = value;
|
||||
}
|
||||
|
||||
public T RemoveFirst()
|
||||
{
|
||||
T element = arr[startIndex];
|
||||
#if RESET_REMOVED_ELEMENTS
|
||||
arr[startIndex] = default( T );
|
||||
#endif
|
||||
|
||||
if( ++startIndex >= arr.Length )
|
||||
startIndex = 0;
|
||||
|
||||
Count--;
|
||||
return element;
|
||||
}
|
||||
|
||||
public T RemoveLast()
|
||||
{
|
||||
int index = ( startIndex + Count - 1 ) % arr.Length;
|
||||
T element = arr[index];
|
||||
#if RESET_REMOVED_ELEMENTS
|
||||
arr[index] = default( T );
|
||||
#endif
|
||||
|
||||
Count--;
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6136cb3c00eac0149901b8e7f2fecef8
|
||||
timeCreated: 1550943949
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Plugins/IngameDebugConsole/Scripts/Commands.meta
Normal file
8
Assets/Plugins/IngameDebugConsole/Scripts/Commands.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb9b6e1ab379cec46bfae8f8abcc1f45
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace IngameDebugConsole.Commands
|
||||
{
|
||||
public class PlayerPrefsCommands
|
||||
{
|
||||
[ConsoleMethod( "prefs.int", "Returns the value of an Integer PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
|
||||
public static string PlayerPrefsGetInt( string key )
|
||||
{
|
||||
if( !PlayerPrefs.HasKey( key ) ) return "Key Not Found";
|
||||
return PlayerPrefs.GetInt( key ).ToString();
|
||||
}
|
||||
|
||||
[ConsoleMethod( "prefs.int", "Sets the value of an Integer PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
|
||||
public static void PlayerPrefsSetInt( string key, int value )
|
||||
{
|
||||
PlayerPrefs.SetInt( key, value );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "prefs.float", "Returns the value of a Float PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
|
||||
public static string PlayerPrefsGetFloat( string key )
|
||||
{
|
||||
if( !PlayerPrefs.HasKey( key ) ) return "Key Not Found";
|
||||
return PlayerPrefs.GetFloat( key ).ToString();
|
||||
}
|
||||
|
||||
[ConsoleMethod( "prefs.float", "Sets the value of a Float PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
|
||||
public static void PlayerPrefsSetFloat( string key, float value )
|
||||
{
|
||||
PlayerPrefs.SetFloat( key, value );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "prefs.string", "Returns the value of a String PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
|
||||
public static string PlayerPrefsGetString( string key )
|
||||
{
|
||||
if( !PlayerPrefs.HasKey( key ) ) return "Key Not Found";
|
||||
return PlayerPrefs.GetString( key );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "prefs.string", "Sets the value of a String PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
|
||||
public static void PlayerPrefsSetString( string key, string value )
|
||||
{
|
||||
PlayerPrefs.SetString( key, value );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "prefs.delete", "Deletes a PlayerPrefs field" ), UnityEngine.Scripting.Preserve]
|
||||
public static void PlayerPrefsDelete( string key )
|
||||
{
|
||||
PlayerPrefs.DeleteKey( key );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "prefs.clear", "Deletes all PlayerPrefs fields" ), UnityEngine.Scripting.Preserve]
|
||||
public static void PlayerPrefsClear()
|
||||
{
|
||||
PlayerPrefs.DeleteAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33fb3ee25c8764f4c905fa3ac7c4eb89
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace IngameDebugConsole.Commands
|
||||
{
|
||||
public class SceneCommands
|
||||
{
|
||||
[ConsoleMethod( "scene.load", "Loads a scene" ), UnityEngine.Scripting.Preserve]
|
||||
public static void LoadScene( string sceneName )
|
||||
{
|
||||
LoadSceneInternal( sceneName, false, LoadSceneMode.Single );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "scene.load", "Loads a scene" ), UnityEngine.Scripting.Preserve]
|
||||
public static void LoadScene( string sceneName, LoadSceneMode mode )
|
||||
{
|
||||
LoadSceneInternal( sceneName, false, mode );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "scene.loadasync", "Loads a scene asynchronously" ), UnityEngine.Scripting.Preserve]
|
||||
public static void LoadSceneAsync( string sceneName )
|
||||
{
|
||||
LoadSceneInternal( sceneName, true, LoadSceneMode.Single );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "scene.loadasync", "Loads a scene asynchronously" ), UnityEngine.Scripting.Preserve]
|
||||
public static void LoadSceneAsync( string sceneName, LoadSceneMode mode )
|
||||
{
|
||||
LoadSceneInternal( sceneName, true, mode );
|
||||
}
|
||||
|
||||
private static void LoadSceneInternal( string sceneName, bool isAsync, LoadSceneMode mode )
|
||||
{
|
||||
if( SceneManager.GetSceneByName( sceneName ).IsValid() )
|
||||
{
|
||||
Debug.Log( "Scene " + sceneName + " is already loaded" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( isAsync )
|
||||
SceneManager.LoadSceneAsync( sceneName, mode );
|
||||
else
|
||||
SceneManager.LoadScene( sceneName, mode );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "scene.unload", "Unloads a scene" ), UnityEngine.Scripting.Preserve]
|
||||
public static void UnloadScene( string sceneName )
|
||||
{
|
||||
SceneManager.UnloadSceneAsync( sceneName );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "scene.restart", "Restarts the active scene" ), UnityEngine.Scripting.Preserve]
|
||||
public static void RestartScene()
|
||||
{
|
||||
SceneManager.LoadScene( SceneManager.GetActiveScene().name, LoadSceneMode.Single );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45984eacd62d9a3489fd62689265a23c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace IngameDebugConsole.Commands
|
||||
{
|
||||
public class TimeCommands
|
||||
{
|
||||
[ConsoleMethod( "time.scale", "Sets the Time.timeScale value" ), UnityEngine.Scripting.Preserve]
|
||||
public static void SetTimeScale( float value )
|
||||
{
|
||||
Time.timeScale = Mathf.Max( value, 0f );
|
||||
}
|
||||
|
||||
[ConsoleMethod( "time.scale", "Returns the current Time.timeScale value" ), UnityEngine.Scripting.Preserve]
|
||||
public static float GetTimeScale()
|
||||
{
|
||||
return Time.timeScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb12a1f557fffa541909fcfe92d9c1bf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
[AttributeUsage( AttributeTargets.Method, Inherited = false, AllowMultiple = true )]
|
||||
public class ConsoleMethodAttribute : Attribute
|
||||
{
|
||||
private string m_command;
|
||||
private string m_description;
|
||||
private string[] m_parameterNames;
|
||||
|
||||
public string Command { get { return m_command; } }
|
||||
public string Description { get { return m_description; } }
|
||||
public string[] ParameterNames { get { return m_parameterNames; } }
|
||||
|
||||
public ConsoleMethodAttribute( string command, string description, params string[] parameterNames )
|
||||
{
|
||||
m_command = command;
|
||||
m_description = description;
|
||||
m_parameterNames = parameterNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 324bb39c0bff0f74fa42f83e91f07e3a
|
||||
timeCreated: 1520710946
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1505
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogConsole.cs
Normal file
1505
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogConsole.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d15693a03d0d33b4892c6365a2a97e19
|
||||
timeCreated: 1472036503
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
170
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogEntry.cs
Normal file
170
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogEntry.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
// Container for a simple debug entry
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class DebugLogEntry : System.IEquatable<DebugLogEntry>
|
||||
{
|
||||
private const int HASH_NOT_CALCULATED = -623218;
|
||||
|
||||
public string logString;
|
||||
public string stackTrace;
|
||||
|
||||
private string completeLog;
|
||||
|
||||
// Sprite to show with this entry
|
||||
public Sprite logTypeSpriteRepresentation;
|
||||
|
||||
// Collapsed count
|
||||
public int count;
|
||||
|
||||
private int hashValue;
|
||||
|
||||
public void Initialize( string logString, string stackTrace )
|
||||
{
|
||||
this.logString = logString;
|
||||
this.stackTrace = stackTrace;
|
||||
|
||||
completeLog = null;
|
||||
count = 1;
|
||||
hashValue = HASH_NOT_CALCULATED;
|
||||
}
|
||||
|
||||
// Check if two entries have the same origin
|
||||
public bool Equals( DebugLogEntry other )
|
||||
{
|
||||
return this.logString == other.logString && this.stackTrace == other.stackTrace;
|
||||
}
|
||||
|
||||
// Checks if logString or stackTrace contains the search term
|
||||
public bool MatchesSearchTerm( string searchTerm )
|
||||
{
|
||||
return ( logString != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( logString, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 ) ||
|
||||
( stackTrace != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( stackTrace, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 );
|
||||
}
|
||||
|
||||
// Return a string containing complete information about this debug entry
|
||||
public override string ToString()
|
||||
{
|
||||
if( completeLog == null )
|
||||
completeLog = string.Concat( logString, "\n", stackTrace );
|
||||
|
||||
return completeLog;
|
||||
}
|
||||
|
||||
// Credit: https://stackoverflow.com/a/19250516/2373034
|
||||
public override int GetHashCode()
|
||||
{
|
||||
if( hashValue == HASH_NOT_CALCULATED )
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
hashValue = 17;
|
||||
hashValue = hashValue * 23 + ( logString == null ? 0 : logString.GetHashCode() );
|
||||
hashValue = hashValue * 23 + ( stackTrace == null ? 0 : stackTrace.GetHashCode() );
|
||||
}
|
||||
}
|
||||
|
||||
return hashValue;
|
||||
}
|
||||
}
|
||||
|
||||
public struct QueuedDebugLogEntry
|
||||
{
|
||||
public readonly string logString;
|
||||
public readonly string stackTrace;
|
||||
public readonly LogType logType;
|
||||
|
||||
public QueuedDebugLogEntry( string logString, string stackTrace, LogType logType )
|
||||
{
|
||||
this.logString = logString;
|
||||
this.stackTrace = stackTrace;
|
||||
this.logType = logType;
|
||||
}
|
||||
|
||||
// Checks if logString or stackTrace contains the search term
|
||||
public bool MatchesSearchTerm( string searchTerm )
|
||||
{
|
||||
return ( logString != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( logString, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 ) ||
|
||||
( stackTrace != null && DebugLogConsole.caseInsensitiveComparer.IndexOf( stackTrace, searchTerm, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace ) >= 0 );
|
||||
}
|
||||
}
|
||||
|
||||
public struct DebugLogEntryTimestamp
|
||||
{
|
||||
public readonly System.DateTime dateTime;
|
||||
#if !IDG_OMIT_ELAPSED_TIME
|
||||
public readonly float elapsedSeconds;
|
||||
#endif
|
||||
#if !IDG_OMIT_FRAMECOUNT
|
||||
public readonly int frameCount;
|
||||
#endif
|
||||
|
||||
#if !IDG_OMIT_ELAPSED_TIME && !IDG_OMIT_FRAMECOUNT
|
||||
public DebugLogEntryTimestamp( System.DateTime dateTime, float elapsedSeconds, int frameCount )
|
||||
#elif !IDG_OMIT_ELAPSED_TIME
|
||||
public DebugLogEntryTimestamp( System.DateTime dateTime, float elapsedSeconds )
|
||||
#elif !IDG_OMIT_FRAMECOUNT
|
||||
public DebugLogEntryTimestamp( System.DateTime dateTime, int frameCount )
|
||||
#else
|
||||
public DebugLogEntryTimestamp( System.DateTime dateTime )
|
||||
#endif
|
||||
{
|
||||
this.dateTime = dateTime;
|
||||
#if !IDG_OMIT_ELAPSED_TIME
|
||||
this.elapsedSeconds = elapsedSeconds;
|
||||
#endif
|
||||
#if !IDG_OMIT_FRAMECOUNT
|
||||
this.frameCount = frameCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
public void AppendTime( StringBuilder sb )
|
||||
{
|
||||
// Add DateTime in format: [HH:mm:ss]
|
||||
sb.Append( "[" );
|
||||
|
||||
int hour = dateTime.Hour;
|
||||
if( hour >= 10 )
|
||||
sb.Append( hour );
|
||||
else
|
||||
sb.Append( "0" ).Append( hour );
|
||||
|
||||
sb.Append( ":" );
|
||||
|
||||
int minute = dateTime.Minute;
|
||||
if( minute >= 10 )
|
||||
sb.Append( minute );
|
||||
else
|
||||
sb.Append( "0" ).Append( minute );
|
||||
|
||||
sb.Append( ":" );
|
||||
|
||||
int second = dateTime.Second;
|
||||
if( second >= 10 )
|
||||
sb.Append( second );
|
||||
else
|
||||
sb.Append( "0" ).Append( second );
|
||||
|
||||
sb.Append( "]" );
|
||||
}
|
||||
|
||||
public void AppendFullTimestamp( StringBuilder sb )
|
||||
{
|
||||
AppendTime( sb );
|
||||
|
||||
#if !IDG_OMIT_ELAPSED_TIME && !IDG_OMIT_FRAMECOUNT
|
||||
// Append elapsed seconds and frame count in format: [1.0s at #Frame]
|
||||
sb.Append( "[" ).Append( elapsedSeconds.ToString( "F1" ) ).Append( "s at " ).Append( "#" ).Append( frameCount ).Append( "]" );
|
||||
#elif !IDG_OMIT_ELAPSED_TIME
|
||||
// Append elapsed seconds in format: [1.0s]
|
||||
sb.Append( "[" ).Append( elapsedSeconds.ToString( "F1" ) ).Append( "s]" );
|
||||
#elif !IDG_OMIT_FRAMECOUNT
|
||||
// Append frame count in format: [#Frame]
|
||||
sb.Append( "[#" ).Append( frameCount ).Append( "]" );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7b1a420c564be040bf73b8a377fc2c2
|
||||
timeCreated: 1466375168
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class DebugLogIndexList<T>
|
||||
{
|
||||
private T[] indices;
|
||||
private int size;
|
||||
|
||||
public int Count { get { return size; } }
|
||||
public T this[int index]
|
||||
{
|
||||
get { return indices[index]; }
|
||||
set { indices[index] = value; }
|
||||
}
|
||||
|
||||
public DebugLogIndexList()
|
||||
{
|
||||
indices = new T[64];
|
||||
size = 0;
|
||||
}
|
||||
|
||||
public void Add( T value )
|
||||
{
|
||||
if( size == indices.Length )
|
||||
System.Array.Resize( ref indices, size * 2 );
|
||||
|
||||
indices[size++] = value;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
size = 0;
|
||||
}
|
||||
|
||||
public int IndexOf( T value )
|
||||
{
|
||||
return System.Array.IndexOf( indices, value );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37c6c91e5bfac6f499698c03f593bcbb
|
||||
timeCreated: 1520627934
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
283
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogItem.cs
Normal file
283
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogItem.cs
Normal file
@@ -0,0 +1,283 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using System.Text;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using System.Text.RegularExpressions;
|
||||
#endif
|
||||
|
||||
// A UI element to show information about a debug entry
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class DebugLogItem : MonoBehaviour, IPointerClickHandler
|
||||
{
|
||||
#region Platform Specific Elements
|
||||
#if !UNITY_2018_1_OR_NEWER
|
||||
#if !UNITY_EDITOR && UNITY_ANDROID
|
||||
private static AndroidJavaClass m_ajc = null;
|
||||
private static AndroidJavaClass AJC
|
||||
{
|
||||
get
|
||||
{
|
||||
if( m_ajc == null )
|
||||
m_ajc = new AndroidJavaClass( "com.yasirkula.unity.DebugConsole" );
|
||||
|
||||
return m_ajc;
|
||||
}
|
||||
}
|
||||
|
||||
private static AndroidJavaObject m_context = null;
|
||||
private static AndroidJavaObject Context
|
||||
{
|
||||
get
|
||||
{
|
||||
if( m_context == null )
|
||||
{
|
||||
using( AndroidJavaObject unityClass = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" ) )
|
||||
{
|
||||
m_context = unityClass.GetStatic<AndroidJavaObject>( "currentActivity" );
|
||||
}
|
||||
}
|
||||
|
||||
return m_context;
|
||||
}
|
||||
}
|
||||
#elif !UNITY_EDITOR && UNITY_IOS
|
||||
[System.Runtime.InteropServices.DllImport( "__Internal" )]
|
||||
private static extern void _DebugConsole_CopyText( string text );
|
||||
#endif
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#pragma warning disable 0649
|
||||
// Cached components
|
||||
[SerializeField]
|
||||
private RectTransform transformComponent;
|
||||
public RectTransform Transform { get { return transformComponent; } }
|
||||
|
||||
[SerializeField]
|
||||
private Image imageComponent;
|
||||
public Image Image { get { return imageComponent; } }
|
||||
|
||||
[SerializeField]
|
||||
private CanvasGroup canvasGroupComponent;
|
||||
public CanvasGroup CanvasGroup { get { return canvasGroupComponent; } }
|
||||
|
||||
[SerializeField]
|
||||
private Text logText;
|
||||
[SerializeField]
|
||||
private Image logTypeImage;
|
||||
|
||||
// Objects related to the collapsed count of the debug entry
|
||||
[SerializeField]
|
||||
private GameObject logCountParent;
|
||||
[SerializeField]
|
||||
private Text logCountText;
|
||||
|
||||
[SerializeField]
|
||||
private RectTransform copyLogButton;
|
||||
#pragma warning restore 0649
|
||||
|
||||
// Debug entry to show with this log item
|
||||
private DebugLogEntry logEntry;
|
||||
public DebugLogEntry Entry { get { return logEntry; } }
|
||||
|
||||
private DebugLogEntryTimestamp? logEntryTimestamp;
|
||||
public DebugLogEntryTimestamp? Timestamp { get { return logEntryTimestamp; } }
|
||||
|
||||
// Index of the entry in the list of entries
|
||||
private int entryIndex;
|
||||
public int Index { get { return entryIndex; } }
|
||||
|
||||
private bool isExpanded;
|
||||
public bool Expanded { get { return isExpanded; } }
|
||||
|
||||
private Vector2 logTextOriginalPosition;
|
||||
private Vector2 logTextOriginalSize;
|
||||
private float copyLogButtonHeight;
|
||||
|
||||
private DebugLogRecycledListView listView;
|
||||
|
||||
public void Initialize( DebugLogRecycledListView listView )
|
||||
{
|
||||
this.listView = listView;
|
||||
|
||||
logTextOriginalPosition = logText.rectTransform.anchoredPosition;
|
||||
logTextOriginalSize = logText.rectTransform.sizeDelta;
|
||||
copyLogButtonHeight = copyLogButton.anchoredPosition.y + copyLogButton.sizeDelta.y + 2f; // 2f: space between text and button
|
||||
|
||||
#if !UNITY_EDITOR && UNITY_WEBGL
|
||||
copyLogButton.gameObject.AddComponent<DebugLogItemCopyWebGL>().Initialize( this );
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SetContent( DebugLogEntry logEntry, DebugLogEntryTimestamp? logEntryTimestamp, int entryIndex, bool isExpanded )
|
||||
{
|
||||
this.logEntry = logEntry;
|
||||
this.logEntryTimestamp = logEntryTimestamp;
|
||||
this.entryIndex = entryIndex;
|
||||
this.isExpanded = isExpanded;
|
||||
|
||||
Vector2 size = transformComponent.sizeDelta;
|
||||
if( isExpanded )
|
||||
{
|
||||
logText.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
size.y = listView.SelectedItemHeight;
|
||||
|
||||
if( !copyLogButton.gameObject.activeSelf )
|
||||
{
|
||||
copyLogButton.gameObject.SetActive( true );
|
||||
|
||||
logText.rectTransform.anchoredPosition = new Vector2( logTextOriginalPosition.x, logTextOriginalPosition.y + copyLogButtonHeight * 0.5f );
|
||||
logText.rectTransform.sizeDelta = logTextOriginalSize - new Vector2( 0f, copyLogButtonHeight );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logText.horizontalOverflow = HorizontalWrapMode.Overflow;
|
||||
size.y = listView.ItemHeight;
|
||||
|
||||
if( copyLogButton.gameObject.activeSelf )
|
||||
{
|
||||
copyLogButton.gameObject.SetActive( false );
|
||||
|
||||
logText.rectTransform.anchoredPosition = logTextOriginalPosition;
|
||||
logText.rectTransform.sizeDelta = logTextOriginalSize;
|
||||
}
|
||||
}
|
||||
|
||||
transformComponent.sizeDelta = size;
|
||||
|
||||
SetText( logEntry, logEntryTimestamp, isExpanded );
|
||||
logTypeImage.sprite = logEntry.logTypeSpriteRepresentation;
|
||||
}
|
||||
|
||||
// Show the collapsed count of the debug entry
|
||||
public void ShowCount()
|
||||
{
|
||||
logCountText.text = logEntry.count.ToString();
|
||||
|
||||
if( !logCountParent.activeSelf )
|
||||
logCountParent.SetActive( true );
|
||||
}
|
||||
|
||||
// Hide the collapsed count of the debug entry
|
||||
public void HideCount()
|
||||
{
|
||||
if( logCountParent.activeSelf )
|
||||
logCountParent.SetActive( false );
|
||||
}
|
||||
|
||||
// Update the debug entry's displayed timestamp
|
||||
public void UpdateTimestamp( DebugLogEntryTimestamp timestamp )
|
||||
{
|
||||
logEntryTimestamp = timestamp;
|
||||
|
||||
if( isExpanded || listView.manager.alwaysDisplayTimestamps )
|
||||
SetText( logEntry, timestamp, isExpanded );
|
||||
}
|
||||
|
||||
private void SetText( DebugLogEntry logEntry, DebugLogEntryTimestamp? logEntryTimestamp, bool isExpanded )
|
||||
{
|
||||
if( !logEntryTimestamp.HasValue || ( !isExpanded && !listView.manager.alwaysDisplayTimestamps ) )
|
||||
logText.text = isExpanded ? logEntry.ToString() : logEntry.logString;
|
||||
else
|
||||
{
|
||||
StringBuilder sb = listView.manager.sharedStringBuilder;
|
||||
sb.Length = 0;
|
||||
|
||||
if( isExpanded )
|
||||
{
|
||||
logEntryTimestamp.Value.AppendFullTimestamp( sb );
|
||||
sb.Append( ": " ).Append( logEntry.ToString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
logEntryTimestamp.Value.AppendTime( sb );
|
||||
sb.Append( " " ).Append( logEntry.logString );
|
||||
}
|
||||
|
||||
logText.text = sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// This log item is clicked, show the debug entry's stack trace
|
||||
public void OnPointerClick( PointerEventData eventData )
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if( eventData.button == PointerEventData.InputButton.Right )
|
||||
{
|
||||
Match regex = Regex.Match( logEntry.stackTrace, @"\(at .*\.cs:[0-9]+\)$", RegexOptions.Multiline );
|
||||
if( regex.Success )
|
||||
{
|
||||
string line = logEntry.stackTrace.Substring( regex.Index + 4, regex.Length - 5 );
|
||||
int lineSeparator = line.IndexOf( ':' );
|
||||
MonoScript script = AssetDatabase.LoadAssetAtPath<MonoScript>( line.Substring( 0, lineSeparator ) );
|
||||
if( script != null )
|
||||
AssetDatabase.OpenAsset( script, int.Parse( line.Substring( lineSeparator + 1 ) ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
listView.OnLogItemClicked( this );
|
||||
#else
|
||||
listView.OnLogItemClicked( this );
|
||||
#endif
|
||||
}
|
||||
|
||||
public void CopyLog()
|
||||
{
|
||||
#if UNITY_EDITOR || !UNITY_WEBGL
|
||||
string log = GetCopyContent();
|
||||
if( string.IsNullOrEmpty( log ) )
|
||||
return;
|
||||
|
||||
#if UNITY_EDITOR || UNITY_2018_1_OR_NEWER || ( !UNITY_ANDROID && !UNITY_IOS )
|
||||
GUIUtility.systemCopyBuffer = log;
|
||||
#elif UNITY_ANDROID
|
||||
AJC.CallStatic( "CopyText", Context, log );
|
||||
#elif UNITY_IOS
|
||||
_DebugConsole_CopyText( log );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
internal string GetCopyContent()
|
||||
{
|
||||
if( !logEntryTimestamp.HasValue )
|
||||
return logEntry.ToString();
|
||||
else
|
||||
{
|
||||
StringBuilder sb = listView.manager.sharedStringBuilder;
|
||||
sb.Length = 0;
|
||||
|
||||
logEntryTimestamp.Value.AppendFullTimestamp( sb );
|
||||
sb.Append( ": " ).Append( logEntry.ToString() );
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public float CalculateExpandedHeight( DebugLogEntry logEntry, DebugLogEntryTimestamp? logEntryTimestamp )
|
||||
{
|
||||
string text = logText.text;
|
||||
HorizontalWrapMode wrapMode = logText.horizontalOverflow;
|
||||
|
||||
SetText( logEntry, logEntryTimestamp, true );
|
||||
logText.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
|
||||
float result = logText.preferredHeight + copyLogButtonHeight;
|
||||
|
||||
logText.text = text;
|
||||
logText.horizontalOverflow = wrapMode;
|
||||
|
||||
return Mathf.Max( listView.ItemHeight, result );
|
||||
}
|
||||
|
||||
// Return a string containing complete information about the debug entry
|
||||
public override string ToString()
|
||||
{
|
||||
return logEntry.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2ea291be9de70a4abfec595203c96c1
|
||||
timeCreated: 1465919949
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
#if !UNITY_EDITOR && UNITY_WEBGL
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class DebugLogItemCopyWebGL : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
|
||||
{
|
||||
[DllImport( "__Internal" )]
|
||||
private static extern void IngameDebugConsoleStartCopy( string textToCopy );
|
||||
[DllImport( "__Internal" )]
|
||||
private static extern void IngameDebugConsoleCancelCopy();
|
||||
|
||||
private DebugLogItem logItem;
|
||||
|
||||
public void Initialize( DebugLogItem logItem )
|
||||
{
|
||||
this.logItem = logItem;
|
||||
}
|
||||
|
||||
public void OnPointerDown( PointerEventData eventData )
|
||||
{
|
||||
string log = logItem.GetCopyContent();
|
||||
if( !string.IsNullOrEmpty( log ) )
|
||||
IngameDebugConsoleStartCopy( log );
|
||||
}
|
||||
|
||||
public void OnPointerUp( PointerEventData eventData )
|
||||
{
|
||||
if( eventData.dragging )
|
||||
IngameDebugConsoleCancelCopy();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a7d9d894141e704d8160fb4632121ac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1758
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogManager.cs
Normal file
1758
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogManager.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a4f16ed905adcd4ab0d7c8c11f0d72c
|
||||
timeCreated: 1522092746
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -9869
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
277
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogPopup.cs
Normal file
277
Assets/Plugins/IngameDebugConsole/Scripts/DebugLogPopup.cs
Normal file
@@ -0,0 +1,277 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using System.Collections;
|
||||
#if UNITY_EDITOR && UNITY_2021_1_OR_NEWER
|
||||
using Screen = UnityEngine.Device.Screen; // To support Device Simulator on Unity 2021.1+
|
||||
#endif
|
||||
|
||||
// Manager class for the debug popup
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class DebugLogPopup : MonoBehaviour, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||
{
|
||||
private RectTransform popupTransform;
|
||||
|
||||
// Dimensions of the popup divided by 2
|
||||
private Vector2 halfSize;
|
||||
|
||||
// Background image that will change color to indicate an alert
|
||||
private Image backgroundImage;
|
||||
|
||||
// Canvas group to modify visibility of the popup
|
||||
private CanvasGroup canvasGroup;
|
||||
|
||||
#pragma warning disable 0649
|
||||
[SerializeField]
|
||||
private DebugLogManager debugManager;
|
||||
|
||||
[SerializeField]
|
||||
private Text newInfoCountText;
|
||||
[SerializeField]
|
||||
private Text newWarningCountText;
|
||||
[SerializeField]
|
||||
private Text newErrorCountText;
|
||||
|
||||
[SerializeField]
|
||||
private Color alertColorInfo;
|
||||
[SerializeField]
|
||||
private Color alertColorWarning;
|
||||
[SerializeField]
|
||||
private Color alertColorError;
|
||||
#pragma warning restore 0649
|
||||
|
||||
// Number of new debug entries since the log window has been closed
|
||||
private int newInfoCount = 0, newWarningCount = 0, newErrorCount = 0;
|
||||
|
||||
private Color normalColor;
|
||||
|
||||
private bool isPopupBeingDragged = false;
|
||||
private Vector2 normalizedPosition;
|
||||
|
||||
// Coroutines for simple code-based animations
|
||||
private IEnumerator moveToPosCoroutine = null;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
popupTransform = (RectTransform)transform;
|
||||
backgroundImage = GetComponent<Image>();
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
|
||||
normalColor = backgroundImage.color;
|
||||
|
||||
halfSize = popupTransform.sizeDelta * 0.5f;
|
||||
|
||||
Vector2 pos = popupTransform.anchoredPosition;
|
||||
if (pos.x != 0f || pos.y != 0f)
|
||||
normalizedPosition = pos.normalized; // Respect the initial popup position set in the prefab
|
||||
else
|
||||
normalizedPosition = new Vector2(0.5f, 0f); // Right edge by default
|
||||
}
|
||||
|
||||
public void NewLogsArrived(int newInfo, int newWarning, int newError)
|
||||
{
|
||||
if (newInfo > 0)
|
||||
{
|
||||
newInfoCount += newInfo;
|
||||
newInfoCountText.text = newInfoCount.ToString();
|
||||
}
|
||||
|
||||
if (newWarning > 0)
|
||||
{
|
||||
newWarningCount += newWarning;
|
||||
newWarningCountText.text = newWarningCount.ToString();
|
||||
}
|
||||
|
||||
if (newError > 0)
|
||||
{
|
||||
newErrorCount += newError;
|
||||
newErrorCountText.text = newErrorCount.ToString();
|
||||
}
|
||||
|
||||
if (newErrorCount > 0)
|
||||
backgroundImage.color = alertColorError;
|
||||
else if (newWarningCount > 0)
|
||||
backgroundImage.color = alertColorWarning;
|
||||
else
|
||||
backgroundImage.color = alertColorInfo;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
newInfoCount = 0;
|
||||
newWarningCount = 0;
|
||||
newErrorCount = 0;
|
||||
|
||||
newInfoCountText.text = "0";
|
||||
newWarningCountText.text = "0";
|
||||
newErrorCountText.text = "0";
|
||||
|
||||
backgroundImage.color = normalColor;
|
||||
}
|
||||
|
||||
// A simple smooth movement animation
|
||||
private IEnumerator MoveToPosAnimation(Vector2 targetPos)
|
||||
{
|
||||
float modifier = 0f;
|
||||
Vector2 initialPos = popupTransform.anchoredPosition;
|
||||
|
||||
while (modifier < 1f)
|
||||
{
|
||||
modifier += 4f * Time.unscaledDeltaTime;
|
||||
popupTransform.anchoredPosition = Vector2.Lerp(initialPos, targetPos, modifier);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Popup is clicked
|
||||
public void OnPointerClick(PointerEventData data)
|
||||
{
|
||||
// Hide the popup and show the log window
|
||||
if (!isPopupBeingDragged)
|
||||
debugManager.ShowLogWindow();
|
||||
}
|
||||
|
||||
// Hides the log window and shows the popup
|
||||
public void Show()
|
||||
{
|
||||
canvasGroup.blocksRaycasts = true;
|
||||
canvasGroup.alpha = 1f;
|
||||
|
||||
// Reset the counters
|
||||
Reset();
|
||||
|
||||
// Update position in case resolution was changed while the popup was hidden
|
||||
UpdatePosition(true);
|
||||
}
|
||||
|
||||
// Hide the popup
|
||||
public void Hide()
|
||||
{
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
canvasGroup.alpha = 0f;
|
||||
|
||||
isPopupBeingDragged = false;
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData data)
|
||||
{
|
||||
isPopupBeingDragged = true;
|
||||
|
||||
// If a smooth movement animation is in progress, cancel it
|
||||
if (moveToPosCoroutine != null)
|
||||
{
|
||||
StopCoroutine(moveToPosCoroutine);
|
||||
moveToPosCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Reposition the popup
|
||||
public void OnDrag(PointerEventData data)
|
||||
{
|
||||
Vector2 localPoint;
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(debugManager.canvasTR, data.position, data.pressEventCamera, out localPoint))
|
||||
popupTransform.anchoredPosition = localPoint;
|
||||
}
|
||||
|
||||
// Smoothly translate the popup to the nearest edge
|
||||
public void OnEndDrag(PointerEventData data)
|
||||
{
|
||||
isPopupBeingDragged = false;
|
||||
UpdatePosition(false);
|
||||
}
|
||||
|
||||
// There are 2 different spaces used in these calculations:
|
||||
// RectTransform space: raw anchoredPosition of the popup that's in range [-canvasSize/2, canvasSize/2]
|
||||
// Safe area space: Screen.safeArea space that's in range [safeAreaBottomLeft, safeAreaTopRight] where these corner positions
|
||||
// are all positive (calculated from bottom left corner of the screen instead of the center of the screen)
|
||||
public void UpdatePosition(bool immediately)
|
||||
{
|
||||
Vector2 canvasRawSize = debugManager.canvasTR.rect.size;
|
||||
|
||||
// Calculate safe area bounds
|
||||
float canvasWidth = canvasRawSize.x;
|
||||
float canvasHeight = canvasRawSize.y;
|
||||
|
||||
float canvasBottomLeftX = 0f;
|
||||
float canvasBottomLeftY = 0f;
|
||||
|
||||
if (debugManager.popupAvoidsScreenCutout)
|
||||
{
|
||||
#if UNITY_2017_2_OR_NEWER && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IOS)
|
||||
Rect safeArea = Screen.safeArea;
|
||||
|
||||
int screenWidth = Screen.width;
|
||||
int screenHeight = Screen.height;
|
||||
|
||||
canvasWidth *= safeArea.width / screenWidth;
|
||||
canvasHeight *= safeArea.height / screenHeight;
|
||||
|
||||
canvasBottomLeftX = canvasRawSize.x * (safeArea.x / screenWidth);
|
||||
canvasBottomLeftY = canvasRawSize.y * (safeArea.y / screenHeight);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Calculate safe area position of the popup
|
||||
// normalizedPosition allows us to glue the popup to a specific edge of the screen. It becomes useful when
|
||||
// the popup is at the right edge and we switch from portrait screen orientation to landscape screen orientation.
|
||||
// Without normalizedPosition, popup could jump to bottom or top edges instead of staying at the right edge
|
||||
Vector2 pos = canvasRawSize * 0.5f + (immediately ? new Vector2(normalizedPosition.x * canvasWidth, normalizedPosition.y * canvasHeight) : (popupTransform.anchoredPosition - new Vector2(canvasBottomLeftX, canvasBottomLeftY)));
|
||||
|
||||
// Find distances to all four edges of the safe area
|
||||
float distToLeft = pos.x;
|
||||
float distToRight = canvasWidth - distToLeft;
|
||||
|
||||
float distToBottom = pos.y;
|
||||
float distToTop = canvasHeight - distToBottom;
|
||||
|
||||
float horDistance = Mathf.Min(distToLeft, distToRight);
|
||||
float vertDistance = Mathf.Min(distToBottom, distToTop);
|
||||
|
||||
// Find the nearest edge's safe area coordinates
|
||||
if (horDistance < vertDistance)
|
||||
{
|
||||
if (distToLeft < distToRight)
|
||||
pos = new Vector2(halfSize.x, pos.y);
|
||||
else
|
||||
pos = new Vector2(canvasWidth - halfSize.x, pos.y);
|
||||
|
||||
pos.y = Mathf.Clamp(pos.y, halfSize.y, canvasHeight - halfSize.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (distToBottom < distToTop)
|
||||
pos = new Vector2(pos.x, halfSize.y);
|
||||
else
|
||||
pos = new Vector2(pos.x, canvasHeight - halfSize.y);
|
||||
|
||||
pos.x = Mathf.Clamp(pos.x, halfSize.x, canvasWidth - halfSize.x);
|
||||
}
|
||||
|
||||
pos -= canvasRawSize * 0.5f;
|
||||
|
||||
normalizedPosition.Set(pos.x / canvasWidth, pos.y / canvasHeight);
|
||||
|
||||
// Safe area's bottom left coordinates are added to pos only after normalizedPosition's value
|
||||
// is set because normalizedPosition is in range [-canvasWidth / 2, canvasWidth / 2]
|
||||
pos += new Vector2(canvasBottomLeftX, canvasBottomLeftY);
|
||||
|
||||
// If another smooth movement animation is in progress, cancel it
|
||||
if (moveToPosCoroutine != null)
|
||||
{
|
||||
StopCoroutine(moveToPosCoroutine);
|
||||
moveToPosCoroutine = null;
|
||||
}
|
||||
|
||||
if (immediately)
|
||||
popupTransform.anchoredPosition = pos;
|
||||
else
|
||||
{
|
||||
// Smoothly translate the popup to the specified position
|
||||
moveToPosCoroutine = MoveToPosAnimation(pos);
|
||||
StartCoroutine(moveToPosCoroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05cc4b1999716644c9308528e38e7081
|
||||
timeCreated: 1466533184
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,392 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
// Handles the log items in an optimized way such that existing log items are
|
||||
// recycled within the list instead of creating a new log item at each chance
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class DebugLogRecycledListView : MonoBehaviour
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
// Cached components
|
||||
[SerializeField]
|
||||
private RectTransform transformComponent;
|
||||
[SerializeField]
|
||||
private RectTransform viewportTransform;
|
||||
|
||||
[SerializeField]
|
||||
private Color logItemNormalColor1;
|
||||
[SerializeField]
|
||||
private Color logItemNormalColor2;
|
||||
[SerializeField]
|
||||
private Color logItemSelectedColor;
|
||||
#pragma warning restore 0649
|
||||
|
||||
internal DebugLogManager manager;
|
||||
private ScrollRect scrollView;
|
||||
|
||||
private float logItemHeight, _1OverLogItemHeight;
|
||||
private float viewportHeight;
|
||||
|
||||
// Unique debug entries
|
||||
private List<DebugLogEntry> collapsedLogEntries = null;
|
||||
|
||||
// Indices of debug entries to show in collapsedLogEntries
|
||||
private DebugLogIndexList<int> indicesOfEntriesToShow = null;
|
||||
private DebugLogIndexList<DebugLogEntryTimestamp> timestampsOfEntriesToShow = null;
|
||||
|
||||
private int indexOfSelectedLogEntry = int.MaxValue;
|
||||
private float positionOfSelectedLogEntry = float.MaxValue;
|
||||
private float heightOfSelectedLogEntry;
|
||||
private float deltaHeightOfSelectedLogEntry;
|
||||
|
||||
// Log items used to visualize the debug entries at specified indices
|
||||
private readonly Dictionary<int, DebugLogItem> logItemsAtIndices = new Dictionary<int, DebugLogItem>( 256 );
|
||||
|
||||
private bool isCollapseOn = false;
|
||||
|
||||
// Current indices of debug entries shown on screen
|
||||
private int currentTopIndex = -1, currentBottomIndex = -1;
|
||||
|
||||
public float ItemHeight { get { return logItemHeight; } }
|
||||
public float SelectedItemHeight { get { return heightOfSelectedLogEntry; } }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
scrollView = viewportTransform.GetComponentInParent<ScrollRect>();
|
||||
scrollView.onValueChanged.AddListener( ( pos ) => UpdateItemsInTheList( false ) );
|
||||
|
||||
viewportHeight = viewportTransform.rect.height;
|
||||
}
|
||||
|
||||
public void Initialize( DebugLogManager manager, List<DebugLogEntry> collapsedLogEntries, DebugLogIndexList<int> indicesOfEntriesToShow, DebugLogIndexList<DebugLogEntryTimestamp> timestampsOfEntriesToShow, float logItemHeight )
|
||||
{
|
||||
this.manager = manager;
|
||||
this.collapsedLogEntries = collapsedLogEntries;
|
||||
this.indicesOfEntriesToShow = indicesOfEntriesToShow;
|
||||
this.timestampsOfEntriesToShow = timestampsOfEntriesToShow;
|
||||
this.logItemHeight = logItemHeight;
|
||||
_1OverLogItemHeight = 1f / logItemHeight;
|
||||
}
|
||||
|
||||
public void SetCollapseMode( bool collapse )
|
||||
{
|
||||
isCollapseOn = collapse;
|
||||
}
|
||||
|
||||
// A log item is clicked, highlight it
|
||||
public void OnLogItemClicked( DebugLogItem item )
|
||||
{
|
||||
OnLogItemClickedInternal( item.Index, item );
|
||||
}
|
||||
|
||||
// Force expand the log item at specified index
|
||||
public void SelectAndFocusOnLogItemAtIndex( int itemIndex )
|
||||
{
|
||||
if( indexOfSelectedLogEntry != itemIndex ) // Make sure that we aren't deselecting the target log item
|
||||
OnLogItemClickedInternal( itemIndex );
|
||||
|
||||
float transformComponentCenterYAtTop = viewportHeight * 0.5f;
|
||||
float transformComponentCenterYAtBottom = transformComponent.sizeDelta.y - viewportHeight * 0.5f;
|
||||
float transformComponentTargetCenterY = itemIndex * logItemHeight + viewportHeight * 0.5f;
|
||||
if( transformComponentCenterYAtTop == transformComponentCenterYAtBottom )
|
||||
scrollView.verticalNormalizedPosition = 0.5f;
|
||||
else
|
||||
scrollView.verticalNormalizedPosition = Mathf.Clamp01( Mathf.InverseLerp( transformComponentCenterYAtBottom, transformComponentCenterYAtTop, transformComponentTargetCenterY ) );
|
||||
|
||||
manager.SetSnapToBottom( false );
|
||||
}
|
||||
|
||||
private void OnLogItemClickedInternal( int itemIndex, DebugLogItem referenceItem = null )
|
||||
{
|
||||
if( indexOfSelectedLogEntry != itemIndex )
|
||||
{
|
||||
DeselectSelectedLogItem();
|
||||
|
||||
if( !referenceItem )
|
||||
{
|
||||
if( currentTopIndex == -1 )
|
||||
UpdateItemsInTheList( false ); // Try to generate some DebugLogItems, we need one DebugLogItem to calculate the text height
|
||||
|
||||
referenceItem = logItemsAtIndices[currentTopIndex];
|
||||
}
|
||||
|
||||
indexOfSelectedLogEntry = itemIndex;
|
||||
positionOfSelectedLogEntry = itemIndex * logItemHeight;
|
||||
heightOfSelectedLogEntry = referenceItem.CalculateExpandedHeight( collapsedLogEntries[indicesOfEntriesToShow[itemIndex]], ( timestampsOfEntriesToShow != null ) ? timestampsOfEntriesToShow[itemIndex] : (DebugLogEntryTimestamp?) null );
|
||||
deltaHeightOfSelectedLogEntry = heightOfSelectedLogEntry - logItemHeight;
|
||||
|
||||
manager.SetSnapToBottom( false );
|
||||
}
|
||||
else
|
||||
DeselectSelectedLogItem();
|
||||
|
||||
if( indexOfSelectedLogEntry >= currentTopIndex && indexOfSelectedLogEntry <= currentBottomIndex )
|
||||
ColorLogItem( logItemsAtIndices[indexOfSelectedLogEntry], indexOfSelectedLogEntry );
|
||||
|
||||
CalculateContentHeight();
|
||||
|
||||
HardResetItems();
|
||||
UpdateItemsInTheList( true );
|
||||
|
||||
manager.ValidateScrollPosition();
|
||||
}
|
||||
|
||||
// Deselect the currently selected log item
|
||||
public void DeselectSelectedLogItem()
|
||||
{
|
||||
int indexOfPreviouslySelectedLogEntry = indexOfSelectedLogEntry;
|
||||
indexOfSelectedLogEntry = int.MaxValue;
|
||||
|
||||
positionOfSelectedLogEntry = float.MaxValue;
|
||||
heightOfSelectedLogEntry = deltaHeightOfSelectedLogEntry = 0f;
|
||||
|
||||
if( indexOfPreviouslySelectedLogEntry >= currentTopIndex && indexOfPreviouslySelectedLogEntry <= currentBottomIndex )
|
||||
ColorLogItem( logItemsAtIndices[indexOfPreviouslySelectedLogEntry], indexOfPreviouslySelectedLogEntry );
|
||||
}
|
||||
|
||||
// Number of debug entries may be changed, update the list
|
||||
public void OnLogEntriesUpdated( bool updateAllVisibleItemContents )
|
||||
{
|
||||
CalculateContentHeight();
|
||||
viewportHeight = viewportTransform.rect.height;
|
||||
|
||||
if( updateAllVisibleItemContents )
|
||||
HardResetItems();
|
||||
|
||||
UpdateItemsInTheList( updateAllVisibleItemContents );
|
||||
}
|
||||
|
||||
// A single collapsed log entry at specified index is updated, refresh its item if visible
|
||||
public void OnCollapsedLogEntryAtIndexUpdated( int index )
|
||||
{
|
||||
DebugLogItem logItem;
|
||||
if( logItemsAtIndices.TryGetValue( index, out logItem ) )
|
||||
{
|
||||
logItem.ShowCount();
|
||||
|
||||
if( timestampsOfEntriesToShow != null )
|
||||
logItem.UpdateTimestamp( timestampsOfEntriesToShow[index] );
|
||||
}
|
||||
}
|
||||
|
||||
// Log window's width has changed, update the expanded (currently selected) log's height
|
||||
public void OnViewportWidthChanged()
|
||||
{
|
||||
if( indexOfSelectedLogEntry >= indicesOfEntriesToShow.Count )
|
||||
return;
|
||||
|
||||
if( currentTopIndex == -1 )
|
||||
{
|
||||
UpdateItemsInTheList( false ); // Try to generate some DebugLogItems, we need one DebugLogItem to calculate the text height
|
||||
if( currentTopIndex == -1 ) // No DebugLogItems are generated, weird
|
||||
return;
|
||||
}
|
||||
|
||||
DebugLogItem referenceItem = logItemsAtIndices[currentTopIndex];
|
||||
|
||||
heightOfSelectedLogEntry = referenceItem.CalculateExpandedHeight( collapsedLogEntries[indicesOfEntriesToShow[indexOfSelectedLogEntry]], ( timestampsOfEntriesToShow != null ) ? timestampsOfEntriesToShow[indexOfSelectedLogEntry] : (DebugLogEntryTimestamp?) null );
|
||||
deltaHeightOfSelectedLogEntry = heightOfSelectedLogEntry - logItemHeight;
|
||||
|
||||
CalculateContentHeight();
|
||||
|
||||
HardResetItems();
|
||||
UpdateItemsInTheList( true );
|
||||
|
||||
manager.ValidateScrollPosition();
|
||||
}
|
||||
|
||||
// Log window's height has changed, update the list
|
||||
public void OnViewportHeightChanged()
|
||||
{
|
||||
viewportHeight = viewportTransform.rect.height;
|
||||
UpdateItemsInTheList( false );
|
||||
}
|
||||
|
||||
private void HardResetItems()
|
||||
{
|
||||
if( currentTopIndex != -1 )
|
||||
{
|
||||
DestroyLogItemsBetweenIndices( currentTopIndex, currentBottomIndex );
|
||||
currentTopIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateContentHeight()
|
||||
{
|
||||
float newHeight = Mathf.Max( 1f, indicesOfEntriesToShow.Count * logItemHeight + deltaHeightOfSelectedLogEntry );
|
||||
transformComponent.sizeDelta = new Vector2( 0f, newHeight );
|
||||
}
|
||||
|
||||
// Calculate the indices of log entries to show
|
||||
// and handle log items accordingly
|
||||
public void UpdateItemsInTheList( bool updateAllVisibleItemContents )
|
||||
{
|
||||
// If there is at least one log entry to show
|
||||
if( indicesOfEntriesToShow.Count > 0 )
|
||||
{
|
||||
float contentPosTop = transformComponent.anchoredPosition.y - 1f;
|
||||
float contentPosBottom = contentPosTop + viewportHeight + 2f;
|
||||
|
||||
if( positionOfSelectedLogEntry <= contentPosBottom )
|
||||
{
|
||||
if( positionOfSelectedLogEntry <= contentPosTop )
|
||||
{
|
||||
contentPosTop -= deltaHeightOfSelectedLogEntry;
|
||||
contentPosBottom -= deltaHeightOfSelectedLogEntry;
|
||||
|
||||
if( contentPosTop < positionOfSelectedLogEntry - 1f )
|
||||
contentPosTop = positionOfSelectedLogEntry - 1f;
|
||||
|
||||
if( contentPosBottom < contentPosTop + 2f )
|
||||
contentPosBottom = contentPosTop + 2f;
|
||||
}
|
||||
else
|
||||
{
|
||||
contentPosBottom -= deltaHeightOfSelectedLogEntry;
|
||||
if( contentPosBottom < positionOfSelectedLogEntry + 1f )
|
||||
contentPosBottom = positionOfSelectedLogEntry + 1f;
|
||||
}
|
||||
}
|
||||
|
||||
int newTopIndex = (int) ( contentPosTop * _1OverLogItemHeight );
|
||||
int newBottomIndex = (int) ( contentPosBottom * _1OverLogItemHeight );
|
||||
|
||||
if( newTopIndex < 0 )
|
||||
newTopIndex = 0;
|
||||
|
||||
if( newBottomIndex > indicesOfEntriesToShow.Count - 1 )
|
||||
newBottomIndex = indicesOfEntriesToShow.Count - 1;
|
||||
|
||||
if( currentTopIndex == -1 )
|
||||
{
|
||||
// There are no log items visible on screen,
|
||||
// just create the new log items
|
||||
updateAllVisibleItemContents = true;
|
||||
|
||||
currentTopIndex = newTopIndex;
|
||||
currentBottomIndex = newBottomIndex;
|
||||
|
||||
CreateLogItemsBetweenIndices( newTopIndex, newBottomIndex );
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are some log items visible on screen
|
||||
|
||||
if( newBottomIndex < currentTopIndex || newTopIndex > currentBottomIndex )
|
||||
{
|
||||
// If user scrolled a lot such that, none of the log items are now within
|
||||
// the bounds of the scroll view, pool all the previous log items and create
|
||||
// new log items for the new list of visible debug entries
|
||||
updateAllVisibleItemContents = true;
|
||||
|
||||
DestroyLogItemsBetweenIndices( currentTopIndex, currentBottomIndex );
|
||||
CreateLogItemsBetweenIndices( newTopIndex, newBottomIndex );
|
||||
}
|
||||
else
|
||||
{
|
||||
// User did not scroll a lot such that, there are still some log items within
|
||||
// the bounds of the scroll view. Don't destroy them but update their content,
|
||||
// if necessary
|
||||
if( newTopIndex > currentTopIndex )
|
||||
DestroyLogItemsBetweenIndices( currentTopIndex, newTopIndex - 1 );
|
||||
|
||||
if( newBottomIndex < currentBottomIndex )
|
||||
DestroyLogItemsBetweenIndices( newBottomIndex + 1, currentBottomIndex );
|
||||
|
||||
if( newTopIndex < currentTopIndex )
|
||||
{
|
||||
CreateLogItemsBetweenIndices( newTopIndex, currentTopIndex - 1 );
|
||||
|
||||
// If it is not necessary to update all the log items,
|
||||
// then just update the newly created log items. Otherwise,
|
||||
// wait for the major update
|
||||
if( !updateAllVisibleItemContents )
|
||||
UpdateLogItemContentsBetweenIndices( newTopIndex, currentTopIndex - 1 );
|
||||
}
|
||||
|
||||
if( newBottomIndex > currentBottomIndex )
|
||||
{
|
||||
CreateLogItemsBetweenIndices( currentBottomIndex + 1, newBottomIndex );
|
||||
|
||||
// If it is not necessary to update all the log items,
|
||||
// then just update the newly created log items. Otherwise,
|
||||
// wait for the major update
|
||||
if( !updateAllVisibleItemContents )
|
||||
UpdateLogItemContentsBetweenIndices( currentBottomIndex + 1, newBottomIndex );
|
||||
}
|
||||
}
|
||||
|
||||
currentTopIndex = newTopIndex;
|
||||
currentBottomIndex = newBottomIndex;
|
||||
}
|
||||
|
||||
if( updateAllVisibleItemContents )
|
||||
{
|
||||
// Update all the log items
|
||||
UpdateLogItemContentsBetweenIndices( currentTopIndex, currentBottomIndex );
|
||||
}
|
||||
}
|
||||
else
|
||||
HardResetItems();
|
||||
}
|
||||
|
||||
private void CreateLogItemsBetweenIndices( int topIndex, int bottomIndex )
|
||||
{
|
||||
for( int i = topIndex; i <= bottomIndex; i++ )
|
||||
CreateLogItemAtIndex( i );
|
||||
}
|
||||
|
||||
// Create (or unpool) a log item
|
||||
private void CreateLogItemAtIndex( int index )
|
||||
{
|
||||
DebugLogItem logItem = manager.PopLogItem();
|
||||
|
||||
// Reposition the log item
|
||||
Vector2 anchoredPosition = new Vector2( 1f, -index * logItemHeight );
|
||||
if( index > indexOfSelectedLogEntry )
|
||||
anchoredPosition.y -= deltaHeightOfSelectedLogEntry;
|
||||
|
||||
logItem.Transform.anchoredPosition = anchoredPosition;
|
||||
|
||||
// Color the log item
|
||||
ColorLogItem( logItem, index );
|
||||
|
||||
// To access this log item easily in the future, add it to the dictionary
|
||||
logItemsAtIndices[index] = logItem;
|
||||
}
|
||||
|
||||
private void DestroyLogItemsBetweenIndices( int topIndex, int bottomIndex )
|
||||
{
|
||||
for( int i = topIndex; i <= bottomIndex; i++ )
|
||||
manager.PoolLogItem( logItemsAtIndices[i] );
|
||||
}
|
||||
|
||||
private void UpdateLogItemContentsBetweenIndices( int topIndex, int bottomIndex )
|
||||
{
|
||||
DebugLogItem logItem;
|
||||
for( int i = topIndex; i <= bottomIndex; i++ )
|
||||
{
|
||||
logItem = logItemsAtIndices[i];
|
||||
logItem.SetContent( collapsedLogEntries[indicesOfEntriesToShow[i]], ( timestampsOfEntriesToShow != null ) ? timestampsOfEntriesToShow[i] : (DebugLogEntryTimestamp?) null, i, i == indexOfSelectedLogEntry );
|
||||
|
||||
if( isCollapseOn )
|
||||
logItem.ShowCount();
|
||||
else
|
||||
logItem.HideCount();
|
||||
}
|
||||
}
|
||||
|
||||
// Color a log item using its index
|
||||
private void ColorLogItem( DebugLogItem logItem, int index )
|
||||
{
|
||||
if( index == indexOfSelectedLogEntry )
|
||||
logItem.Image.color = logItemSelectedColor;
|
||||
else if( index % 2 == 0 )
|
||||
logItem.Image.color = logItemNormalColor1;
|
||||
else
|
||||
logItem.Image.color = logItemNormalColor2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce231987d32488f43b6fb798f7df43f6
|
||||
timeCreated: 1466373025
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
// Listens to drag event on the DebugLogManager's resize button
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class DebugLogResizeListener : MonoBehaviour, IBeginDragHandler, IDragHandler
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
[SerializeField]
|
||||
private DebugLogManager debugManager;
|
||||
#pragma warning restore 0649
|
||||
|
||||
// This interface must be implemented in order to receive drag events
|
||||
void IBeginDragHandler.OnBeginDrag( PointerEventData eventData )
|
||||
{
|
||||
}
|
||||
|
||||
void IDragHandler.OnDrag( PointerEventData eventData )
|
||||
{
|
||||
debugManager.Resize( eventData );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6565f2084f5aef44abe57c988745b9c3
|
||||
timeCreated: 1601221093
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
// Listens to scroll events on the scroll rect that debug items are stored
|
||||
// and decides whether snap to bottom should be true or not
|
||||
//
|
||||
// Procedure: if, after a user input (drag or scroll), scrollbar is at the bottom, then
|
||||
// snap to bottom shall be true, otherwise it shall be false
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
public class DebugsOnScrollListener : MonoBehaviour, IScrollHandler, IBeginDragHandler, IEndDragHandler
|
||||
{
|
||||
public ScrollRect debugsScrollRect;
|
||||
public DebugLogManager debugLogManager;
|
||||
|
||||
public void OnScroll( PointerEventData data )
|
||||
{
|
||||
if( IsScrollbarAtBottom() )
|
||||
debugLogManager.SetSnapToBottom( true );
|
||||
else
|
||||
debugLogManager.SetSnapToBottom( false );
|
||||
}
|
||||
|
||||
public void OnBeginDrag( PointerEventData data )
|
||||
{
|
||||
debugLogManager.SetSnapToBottom( false );
|
||||
}
|
||||
|
||||
public void OnEndDrag( PointerEventData data )
|
||||
{
|
||||
if( IsScrollbarAtBottom() )
|
||||
debugLogManager.SetSnapToBottom( true );
|
||||
else
|
||||
debugLogManager.SetSnapToBottom( false );
|
||||
}
|
||||
|
||||
public void OnScrollbarDragStart( BaseEventData data )
|
||||
{
|
||||
debugLogManager.SetSnapToBottom( false );
|
||||
}
|
||||
|
||||
public void OnScrollbarDragEnd( BaseEventData data )
|
||||
{
|
||||
if( IsScrollbarAtBottom() )
|
||||
debugLogManager.SetSnapToBottom( true );
|
||||
else
|
||||
debugLogManager.SetSnapToBottom( false );
|
||||
}
|
||||
|
||||
private bool IsScrollbarAtBottom()
|
||||
{
|
||||
float scrollbarYPos = debugsScrollRect.verticalNormalizedPosition;
|
||||
if( scrollbarYPos <= 1E-6f )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb564dcb180e586429c57456166a76b5
|
||||
timeCreated: 1466004663
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,75 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.SceneManagement;
|
||||
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
|
||||
using UnityEngine.InputSystem.UI;
|
||||
#endif
|
||||
|
||||
namespace IngameDebugConsole
|
||||
{
|
||||
// Avoid multiple EventSystems in the scene by activating the embedded EventSystem only if one doesn't already exist in the scene
|
||||
[DefaultExecutionOrder( 1000 )]
|
||||
public class EventSystemHandler : MonoBehaviour
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
[SerializeField]
|
||||
private GameObject embeddedEventSystem;
|
||||
#pragma warning restore 0649
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
|
||||
private void Awake()
|
||||
{
|
||||
StandaloneInputModule legacyInputModule = embeddedEventSystem.GetComponent<StandaloneInputModule>();
|
||||
if( legacyInputModule )
|
||||
{
|
||||
DestroyImmediate( legacyInputModule );
|
||||
embeddedEventSystem.AddComponent<InputSystemUIInputModule>();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
SceneManager.sceneUnloaded -= OnSceneUnloaded;
|
||||
SceneManager.sceneUnloaded += OnSceneUnloaded;
|
||||
|
||||
ActivateEventSystemIfNeeded();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
SceneManager.sceneUnloaded -= OnSceneUnloaded;
|
||||
|
||||
DeactivateEventSystem();
|
||||
}
|
||||
|
||||
private void OnSceneLoaded( Scene scene, LoadSceneMode mode )
|
||||
{
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
DeactivateEventSystem();
|
||||
#endif
|
||||
ActivateEventSystemIfNeeded();
|
||||
}
|
||||
|
||||
private void OnSceneUnloaded( Scene current )
|
||||
{
|
||||
// Deactivate the embedded EventSystem before changing scenes because the new scene might have its own EventSystem
|
||||
DeactivateEventSystem();
|
||||
}
|
||||
|
||||
private void ActivateEventSystemIfNeeded()
|
||||
{
|
||||
if( embeddedEventSystem && !EventSystem.current )
|
||||
embeddedEventSystem.SetActive( true );
|
||||
}
|
||||
|
||||
private void DeactivateEventSystem()
|
||||
{
|
||||
if( embeddedEventSystem )
|
||||
embeddedEventSystem.SetActive( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c3cc1b407f337e641ad32a2e91d5b478
|
||||
timeCreated: 1658741613
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Plugins/IngameDebugConsole/WebGL.meta
Normal file
9
Assets/Plugins/IngameDebugConsole/WebGL.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a091b43ce3618074d8cf2beb7e538a7d
|
||||
folderAsset: yes
|
||||
timeCreated: 1626377678
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,70 @@
|
||||
mergeInto( LibraryManager.library,
|
||||
{
|
||||
IngameDebugConsoleStartCopy: function( textToCopy )
|
||||
{
|
||||
var textToCopyJS = UTF8ToString( textToCopy );
|
||||
|
||||
// Delete if element exist
|
||||
var copyTextButton = document.getElementById( 'DebugConsoleCopyButtonGL' );
|
||||
if( !copyTextButton )
|
||||
{
|
||||
copyTextButton = document.createElement( 'button' );
|
||||
copyTextButton.setAttribute( 'id', 'DebugConsoleCopyButtonGL' );
|
||||
copyTextButton.setAttribute( 'style','display:none; visibility:hidden;' );
|
||||
}
|
||||
|
||||
copyTextButton.onclick = function( event )
|
||||
{
|
||||
// Credit: https://stackoverflow.com/a/30810322/2373034
|
||||
if( navigator.clipboard )
|
||||
{
|
||||
navigator.clipboard.writeText( textToCopyJS ).then( function() { }, function( err )
|
||||
{
|
||||
console.error( "Couldn't copy text to clipboard using clipboard.writeText: ", err );
|
||||
} );
|
||||
}
|
||||
else
|
||||
{
|
||||
var textArea = document.createElement( 'textarea' );
|
||||
textArea.value = textToCopyJS;
|
||||
|
||||
// Avoid scrolling to bottom
|
||||
textArea.style.top = "0";
|
||||
textArea.style.left = "0";
|
||||
textArea.style.position = "fixed";
|
||||
|
||||
document.body.appendChild( textArea );
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
|
||||
try
|
||||
{
|
||||
document.execCommand( 'copy' );
|
||||
}
|
||||
catch( err )
|
||||
{
|
||||
console.error( "Couldn't copy text to clipboard using document.execCommand", err );
|
||||
}
|
||||
|
||||
document.body.removeChild( textArea );
|
||||
}
|
||||
};
|
||||
|
||||
document.body.appendChild( copyTextButton );
|
||||
document.onmouseup = function()
|
||||
{
|
||||
document.onmouseup = null;
|
||||
copyTextButton.click();
|
||||
document.body.removeChild( copyTextButton );
|
||||
};
|
||||
},
|
||||
|
||||
IngameDebugConsoleCancelCopy: function()
|
||||
{
|
||||
var copyTextButton = document.getElementById( 'DebugConsoleCopyButtonGL' );
|
||||
if( copyTextButton )
|
||||
document.body.removeChild( copyTextButton );
|
||||
|
||||
document.onmouseup = null;
|
||||
}
|
||||
} );
|
||||
@@ -0,0 +1,39 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa23dd530e9f98c4cb0766404fc0e755
|
||||
timeCreated: 1626377683
|
||||
licenseType: Free
|
||||
PluginImporter:
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
data:
|
||||
first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
data:
|
||||
first:
|
||||
Facebook: WebGL
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
WebGL: WebGL
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Plugins/IngameDebugConsole/iOS.meta
Normal file
9
Assets/Plugins/IngameDebugConsole/iOS.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4552a2fd287aca645a670fa2b65e52a9
|
||||
folderAsset: yes
|
||||
timeCreated: 1586184974
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
extern "C" void _DebugConsole_CopyText( const char* text )
|
||||
{
|
||||
[UIPasteboard generalPasteboard].string = [NSString stringWithUTF8String:text];
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b53767ec4f910e4a9876cbe77d57968
|
||||
timeCreated: 1498727312
|
||||
licenseType: Pro
|
||||
PluginImporter:
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
platformData:
|
||||
data:
|
||||
first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
data:
|
||||
first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
data:
|
||||
first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,2 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e037cde050f786f48a35fc4e775dc4a4
|
||||
guid: e037cde050f786f48a35fc4e775dc4a4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
8
Assets/Plugins/WaterCausticsModules.meta
Normal file
8
Assets/Plugins/WaterCausticsModules.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd4ab3b30e03a184483ced099b43ec19
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 557c32d7360c26949947ac9dd8c308fc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b933d9ff2aad75c47a4970139d6a01e6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8217f1589415f28408ff7a0dfe9142df
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bdbc0567055e3424da2363638a6ffd14
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,144 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f88b6df342d5c4f4a969fb6eb4799d3e
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 1
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 2
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 0
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: iPhone
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 64
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Windows Store Apps
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 121 B |
@@ -0,0 +1,144 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27623e5a17b6fd44a9af57a733ee993a
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 0
|
||||
aniso: 2
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 0
|
||||
alphaIsTransparency: 0
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: iPhone
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 32
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 0
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Windows Store Apps
|
||||
maxTextureSize: 8192
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76d974e53c74fd642a7607b4a9bbf0a4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,128 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if WCE_URP
|
||||
using System.Collections.Generic;
|
||||
using MH.WaterCausticsModules.Effect;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
[ExecuteAlways]
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu ("")]
|
||||
internal class AtOnce : MonoBehaviour {
|
||||
private WaterCausticsEffect _summoner;
|
||||
private MeshRenderer _render;
|
||||
internal MeshRenderer render => _render;
|
||||
private void setRenderEnable (bool isOn) {
|
||||
if (_render && _render.enabled != isOn) _render.enabled = isOn;
|
||||
}
|
||||
|
||||
private bool _inited;
|
||||
private AtOnce init (WaterCausticsEffect summoner, Material mat) {
|
||||
_inited = true;
|
||||
_summoner = summoner;
|
||||
var mf = gameObject.AddComponent<MeshFilter> ();
|
||||
mf.sharedMesh = getMesh ();
|
||||
_render = gameObject.AddComponent<MeshRenderer> ();
|
||||
_render.sharedMaterial = mat;
|
||||
_render.shadowCastingMode = ShadowCastingMode.Off;
|
||||
_render.lightProbeUsage = LightProbeUsage.Off;
|
||||
_render.reflectionProbeUsage = ReflectionProbeUsage.Off;
|
||||
_render.allowOcclusionWhenDynamic = true;
|
||||
_render.receiveShadows = true;
|
||||
updateTransform ();
|
||||
// -- HideFlags --
|
||||
gameObject.hideFlags = HideFlags.HideAndDontSave | HideFlags.HideInInspector;
|
||||
// gameObject.hideFlags &= (~HideFlags.HideInHierarchy); // デバッグ用 Hierarchyで表示
|
||||
// ---------------
|
||||
return this;
|
||||
}
|
||||
|
||||
private void OnDisable () {
|
||||
setRenderEnable (false);
|
||||
}
|
||||
|
||||
private void OnDestroy () {
|
||||
destroy (ref __mesh);
|
||||
}
|
||||
|
||||
private void LateUpdate () {
|
||||
if (!_summoner || !_summoner.isActiveAndEnabled || _summoner.method != Method.AtOnce) {
|
||||
setRenderEnable (false);
|
||||
} else {
|
||||
setRenderEnable (true);
|
||||
updateTransform ();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTransform () {
|
||||
if (gameObject.layer != _summoner.gameObject.layer)
|
||||
gameObject.layer = _summoner.gameObject.layer;
|
||||
var sumTra = _summoner.transform;
|
||||
if (transform.parent != sumTra.parent)
|
||||
transform.SetParent (sumTra.parent, worldPositionStays : false);
|
||||
if (transform.localToWorldMatrix != sumTra.localToWorldMatrix) {
|
||||
transform.localPosition = sumTra.localPosition;
|
||||
transform.localRotation = sumTra.localRotation;
|
||||
transform.localScale = sumTra.localScale;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update () {
|
||||
bool isLeaked = (!_inited || !_summoner || _summoner.atOnce != this);
|
||||
if (isLeaked) destroy (gameObject);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------- Mesh
|
||||
private Mesh __mesh;
|
||||
private Mesh getMesh () {
|
||||
if (!__mesh) {
|
||||
Mesh m = new Mesh ();
|
||||
m.name = "WCEMeshForAtOnce";
|
||||
m.vertices = new Vector3 [] { new Vector3 (-.5f, -.5f, -.5f), new Vector3 (.5f, -.5f, -.5f), new Vector3 (-.5f, .5f, -.5f), new Vector3 (.5f, .5f, -.5f), new Vector3 (-.5f, -.5f, .5f), new Vector3 (.5f, -.5f, .5f), new Vector3 (-.5f, .5f, .5f), new Vector3 (.5f, .5f, .5f), /* */ Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero };
|
||||
m.triangles = new int [] { 2, 6, 7, 2, 7, 3, 0, 2, 3, 0, 3, 1, 1, 3, 7, 1, 7, 5, 0, 4, 6, 0, 6, 2, 4, 5, 7, 4, 7, 6, 0, 1, 5, 0, 5, 4, /* */ 15, 8, 9, 15, 9, 10, 15, 10, 11, 15, 11, 12, 15, 12, 13, 15, 13, 14 };
|
||||
m.bounds = new Bounds (Vector3.zero, Vector3.one);
|
||||
m.hideFlags = HideFlags.HideAndDontSave;
|
||||
m.UploadMeshData (markNoLongerReadable: true);
|
||||
__mesh = m;
|
||||
}
|
||||
return __mesh;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------- Static
|
||||
|
||||
static internal AtOnce Create (WaterCausticsEffect summoner, Material mat) {
|
||||
var name = "(WCE Renderer) (Deletable)";
|
||||
var go = new GameObject (name);
|
||||
go.SetActive (false); // ← Flags設定時にOnEnable,OnDisableが呼ばれる不具合の回避
|
||||
var a = go.AddComponent<AtOnce> ().init (summoner, mat);
|
||||
go.SetActive (true);
|
||||
return a;
|
||||
}
|
||||
|
||||
static internal void OnSummonerDestroyed (ref AtOnce a) {
|
||||
if (a == null) return;
|
||||
destroy (a.gameObject);
|
||||
a = null;
|
||||
}
|
||||
|
||||
static private void destroy<T> (ref T o) where T : Object {
|
||||
if (o == null) return;
|
||||
destroy (o);
|
||||
o = null;
|
||||
}
|
||||
|
||||
static private void destroy (Object o) {
|
||||
if (o == null) return;
|
||||
if (Application.isPlaying)
|
||||
Destroy (o);
|
||||
else
|
||||
DestroyImmediate (o);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------
|
||||
}
|
||||
}
|
||||
#endif // End of WCE_URP
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22b1121aa1f7879478a6b6b90e1a9738
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb81f73566a5654488dbc4e168ae6b26
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,97 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR && (!WCE_URP || WCE_DEVELOPMENT)
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#pragma warning disable 162
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
/*------------------------------------------------------------------------
|
||||
URP10.4以上のパッケージを持っていない場合にEffectモジュールを削除。
|
||||
initializeOnLoad と インポート時に削除を試す
|
||||
-------------------------------------------------------------------------*/
|
||||
public class CheckRenderPipeline : AssetPostprocessor {
|
||||
static private readonly string classFileName = $"{typeof(CheckRenderPipeline).Name}.cs";
|
||||
|
||||
#if WCE_DEVELOPMENT
|
||||
[MenuItem ("WCM/TestDialog/DeleteEffectModuleDialog")]
|
||||
static void dialogTest () => showDialogAndWarning ();
|
||||
static private readonly bool isDeveloping = true;
|
||||
#else
|
||||
static private readonly bool isDeveloping = false;
|
||||
#endif
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void initializeOnLoad () {
|
||||
EditorApplication.delayCall += delayCall;
|
||||
}
|
||||
private static void delayCall () {
|
||||
if (isDeveloping) return;
|
||||
if (findAsset<EffectModuleRef> (out var asset, out var path)) {
|
||||
if (asset.effectModule) {
|
||||
var folderPath = AssetDatabase.GetAssetPath (asset.effectModule);
|
||||
if (!string.IsNullOrEmpty (folderPath) && folderPath.EndsWith (Constant.EFFECT_FOLDER_NAME)) {
|
||||
deleteEffectFolder (folderPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string s_folderPath;
|
||||
static void OnPostprocessAllAssets (string [] imported, string [] deleted, string [] moved, string [] movedFrom) {
|
||||
if (isDeveloping) return;
|
||||
if (findAsset<EffectModuleRef> (out var asset, out var path) && asset.effectModule) {
|
||||
var folderPath = AssetDatabase.GetAssetPath (asset.effectModule);
|
||||
if (!string.IsNullOrEmpty (folderPath) && folderPath.EndsWith (Constant.EFFECT_FOLDER_NAME)) {
|
||||
if (imported.Any (a => a.StartsWith (folderPath))) {
|
||||
// Shaderファイルなどを先に削除 ※Shader Error回避
|
||||
deleteWithoutMat (folderPath);
|
||||
// フォルダの削除はDelayCallで行う ※MaterialPostprocessorでのNullエラー回避
|
||||
s_folderPath = folderPath;
|
||||
EditorApplication.delayCall += () => deleteEffectFolder (s_folderPath);
|
||||
} else {
|
||||
deleteEffectFolder (folderPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void deleteWithoutMat (string folderPath) {
|
||||
string [] guids = AssetDatabase.FindAssets ("", new [] { folderPath });
|
||||
string [] paths = guids.Select (guid => AssetDatabase.GUIDToAssetPath (guid)).Where (p => p.EndsWith (".shader") || p.EndsWith (".asset") || p.EndsWith (".lighting")).ToArray ();
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
AssetDatabase.DeleteAssets (paths, new List<string> ());
|
||||
#else
|
||||
foreach (var p in paths) AssetDatabase.DeleteAsset (p);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void deleteEffectFolder (string folderPath) {
|
||||
if (isDeveloping || string.IsNullOrEmpty (folderPath)) return;
|
||||
if (AssetDatabase.DeleteAsset (folderPath)) {
|
||||
AssetDatabase.Refresh ();
|
||||
showDialogAndWarning ();
|
||||
}
|
||||
}
|
||||
|
||||
static void showDialogAndWarning () {
|
||||
// ----- Dialog表示
|
||||
EditorUtility.DisplayDialog ("Effect module removed.", $"The Effect module of this asset was removed.\n\nBecause the UniversalRP package {Constant.REQUIRE_URP_VER} could not be detected in this project.\n\nSee the Manual for details.\n\n\n({Constant.ASSET_NAME})", "OK");
|
||||
}
|
||||
|
||||
static private bool findAsset<T> (out T asset, out string path) where T : Object {
|
||||
asset = null;
|
||||
path = null;
|
||||
var guids = AssetDatabase.FindAssets ($"t:{typeof (T).ToString()}", new [] { "Assets" }); // ※フォルダ名の最後にスラッシュがあると古いUnityでエラーになるので注意
|
||||
if (guids.Length == 0) return false;
|
||||
path = AssetDatabase.GUIDToAssetPath (guids [0]);
|
||||
asset = AssetDatabase.LoadAssetAtPath<T> (path);
|
||||
return asset != null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4373c16da8bab7841b9c9f883fd8ca5c
|
||||
labels:
|
||||
- WaterCausticsModules
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,67 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR && WCE_URP
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEditor.Rendering;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
/*------------------------------------------------------------------------
|
||||
Previewウィンドウでエフェクトを無効化
|
||||
-------------------------------------------------------------------------*/
|
||||
public class DisableInPreviewWindow : IPreprocessBuildWithReport, IPostprocessBuildWithReport {
|
||||
private static readonly string KEYWORD = "_WCE_DISABLED";
|
||||
public int callbackOrder => 1;
|
||||
public void OnPreprocessBuild (BuildReport report) {
|
||||
// ビルド前処理
|
||||
disableEvent ();
|
||||
}
|
||||
|
||||
public void OnPostprocessBuild (BuildReport report) {
|
||||
// ビルド後処理
|
||||
enableEvent ();
|
||||
}
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
static void OnInitialize () {
|
||||
// Editor起動直後、プレイ開始時
|
||||
enableEvent ();
|
||||
}
|
||||
|
||||
static private void enableEvent () {
|
||||
WaterCausticsEffectFeature.onCamRender -= onEnqueue;
|
||||
WaterCausticsEffectFeature.onCamRender += onEnqueue;
|
||||
}
|
||||
|
||||
static private void disableEvent () {
|
||||
Shader.DisableKeyword (KEYWORD);
|
||||
WaterCausticsEffectFeature.onCamRender -= onEnqueue;
|
||||
}
|
||||
|
||||
static private void onEnqueue (Camera cam) {
|
||||
if (cam.cameraType == CameraType.Preview)
|
||||
Shader.EnableKeyword (KEYWORD);
|
||||
else
|
||||
Shader.DisableKeyword (KEYWORD);
|
||||
}
|
||||
|
||||
public class ShaderPreprocessor : IPreprocessShaders {
|
||||
// シェーダバリアント削除
|
||||
public int callbackOrder => 1;
|
||||
public void OnProcessShader (Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data) {
|
||||
var deleteKeyword = new ShaderKeyword (DisableInPreviewWindow.KEYWORD);
|
||||
for (var i = data.Count - 1; i >= 0; --i)
|
||||
if (data [i].shaderKeywordSet.IsEnabled (deleteKeyword))
|
||||
data.RemoveAt (i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8326956518b565e44a9cb612c6b7f963
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 276d321c87e0f494fb5e61d87eb50ad6, type: 3}
|
||||
m_Name: EffectModuleRef
|
||||
m_EditorClassIdentifier:
|
||||
m_effectModule: {fileID: 102900000, guid: 557c32d7360c26949947ac9dd8c308fc, type: 3}
|
||||
m_customFunc: {fileID: 102900000, guid: 5c458e7b6a8f6024aba7bed0ab7b3320, type: 3}
|
||||
m_packageForASE: {fileID: 102900000, guid: cd1a5fad241143647aa5403add1f9fd8, type: 3}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e71d80f209a88447bb8a57499210fd2
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
#if WCE_DEVELOPMENT
|
||||
[CreateAssetMenu]
|
||||
#endif
|
||||
public class EffectModuleRef : ScriptableObject {
|
||||
// WaterCausticEffectフォルダ
|
||||
[SerializeField] private Object m_effectModule;
|
||||
internal Object effectModule => m_effectModule;
|
||||
|
||||
// ShaderFunctionsフォルダ
|
||||
[SerializeField] private Object m_customFunc;
|
||||
internal Object customFunc => m_customFunc;
|
||||
|
||||
// ForAmplifyShaderEditor.unitypackageファイル
|
||||
[SerializeField] private Object m_packageForASE;
|
||||
internal Object packageForASE => m_packageForASE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 276d321c87e0f494fb5e61d87eb50ad6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR && WCE_URP && AMPLIFY_SHADER_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#pragma warning disable 162
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
/*------------------------------------------------------------------------
|
||||
AmplifyShaderEditorがある環境でアセットがインポートされた際、
|
||||
AmplifyShaderEditor用のカスタムファンクションパッケージを自動インポート
|
||||
-------------------------------------------------------------------------*/
|
||||
public class ImportPackageForASE {
|
||||
#if WCE_DEVELOPMENT
|
||||
static private readonly bool isDeveloping = true;
|
||||
#else
|
||||
static private readonly bool isDeveloping = false;
|
||||
#endif
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
public static void registerCallback () {
|
||||
AssetDatabase.importPackageCompleted -= importCompleted;
|
||||
AssetDatabase.importPackageCompleted += importCompleted;
|
||||
}
|
||||
|
||||
static void importCompleted (string packageName) {
|
||||
if (isDeveloping) return;
|
||||
if (Constant.CheckPackageName (packageName) && findAsset<EffectModuleRef> (out var asset, out var path) && asset.packageForASE) {
|
||||
string packagePath = AssetDatabase.GetAssetPath (asset.packageForASE);
|
||||
if (packagePath != null && packagePath.EndsWith (Constant.ASE_PACKAGE_NAME)) {
|
||||
AssetDatabase.ImportPackage (packagePath, false);
|
||||
AssetDatabase.DeleteAsset (packagePath);
|
||||
AssetDatabase.Refresh ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static private bool findAsset<T> (out T asset, out string path) where T : Object {
|
||||
asset = null;
|
||||
path = null;
|
||||
var guids = AssetDatabase.FindAssets ($"t:{typeof (T).ToString()}", new [] { "Assets" });
|
||||
if (guids.Length == 0) return false;
|
||||
path = AssetDatabase.GUIDToAssetPath (guids [0]);
|
||||
asset = AssetDatabase.LoadAssetAtPath<T> (path);
|
||||
return asset != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abb96ab8cc4602440a3c0f2ddea9415e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR && WCE_URP
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Rendering;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
/*------------------------------------------------------------------------
|
||||
ビルド時シェーダバリアント削除
|
||||
-------------------------------------------------------------------------*/
|
||||
public class OptimizeShader : IPreprocessShaders {
|
||||
public int callbackOrder => 1;
|
||||
|
||||
private readonly ShaderKeyword [] delKeys = {
|
||||
new ShaderKeyword ("WCE_DEBUG_NORMAL"),
|
||||
new ShaderKeyword ("WCE_DEBUG_DEPTH"),
|
||||
new ShaderKeyword ("WCE_DEBUG_FACING"),
|
||||
new ShaderKeyword ("WCE_DEBUG_CAUSTICS"),
|
||||
new ShaderKeyword ("WCE_DEBUG_AREA"),
|
||||
#if !WCE_URP_12_0 // URP12より下の場合
|
||||
new ShaderKeyword ("_GBUFFER_NORMALS_OCT"),
|
||||
new ShaderKeyword ("_LIGHT_LAYERS"),
|
||||
new ShaderKeyword ("_LIGHT_COOKIES"),
|
||||
#endif
|
||||
#if !WCE_URP_14_0 // URP14より下の場合
|
||||
new ShaderKeyword ("_FORWARD_PLUS"),
|
||||
#endif
|
||||
};
|
||||
|
||||
private bool hasDelKey (ShaderKeywordSet set) {
|
||||
foreach (var key in delKeys)
|
||||
if (set.IsEnabled (key))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnProcessShader (Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data) {
|
||||
// シェーダ名チェック
|
||||
if (!shader.name.StartsWith (Constant.SHADER_NAME_HEADER)) return;
|
||||
// キーを持っているか確認 & 削除
|
||||
for (var i = data.Count - 1; i >= 0; --i) {
|
||||
if (hasDelKey (data [i].shaderKeywordSet))
|
||||
data.RemoveAt (i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cacb7892edc3def4f8111ae95a40c233
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR && WCE_URP
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
/*------------------------------------------------------------------------
|
||||
「missing SubGraph references」エラーを防ぐため、このスクリプトが移動した
|
||||
ことを検知した際にShaderFunctionsフォルダを再インポート。
|
||||
-------------------------------------------------------------------------*/
|
||||
public class ReimportFunctions : AssetPostprocessor {
|
||||
static private readonly string classFileName = $"{typeof (ReimportFunctions).Name}.cs";
|
||||
static void OnPostprocessAllAssets (string [] imported, string [] deleted, string [] moved, string [] movedFrom) {
|
||||
// ※移動時と名称変更時、フォルダは importedAssetsとmovedAssetsに入るので注意、アセットはmovedAssetsのみ
|
||||
if (moved.Any (a => a.EndsWith (classFileName)) && !imported.Any (a => a.EndsWith (classFileName))) {
|
||||
if (findAsset<EffectModuleRef> (out var asset, out var path) && asset.customFunc) {
|
||||
var folderPath = AssetDatabase.GetAssetPath (asset.customFunc);
|
||||
if (!string.IsNullOrEmpty (folderPath) && moved.Any (a => a == folderPath)) {
|
||||
AssetDatabase.ImportAsset (folderPath, ImportAssetOptions.ImportRecursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static private bool findAsset<T> (out T asset, out string path) where T : Object {
|
||||
asset = null;
|
||||
path = null;
|
||||
var guids = AssetDatabase.FindAssets ($"t:{typeof (T).ToString()}", new [] { "Assets" });
|
||||
if (guids.Length == 0) return false;
|
||||
path = AssetDatabase.GUIDToAssetPath (guids [0]);
|
||||
asset = AssetDatabase.LoadAssetAtPath<T> (path);
|
||||
return asset != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 262d8e92d9439494bbb7bb9d66dee10a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 71d38c23289312844bc6e88159ed75c7, type: 3}
|
||||
m_Name: WaterCausticsEffectData
|
||||
m_EditorClassIdentifier:
|
||||
m_autoManageFeature: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 062a4f28f6d145a4798a42cbe2bf6992
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR && WCE_URP
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
public class WaterCausticsEffectData : ScriptableObject {
|
||||
// ---------------------------------------------------------
|
||||
[SerializeField] internal bool m_autoManageFeature = true;
|
||||
internal bool AutoManageFeature => m_autoManageFeature;
|
||||
|
||||
// ---------------------------------------------------------
|
||||
static private WaterCausticsEffectData _s_ins;
|
||||
static internal WaterCausticsEffectData GetAsset () {
|
||||
if (_s_ins) return _s_ins;
|
||||
if (findAsset<WaterCausticsEffectData> (out var ins, out var path)) return _s_ins = ins;
|
||||
return _s_ins = createAsset<WaterCausticsEffectData> ();
|
||||
}
|
||||
|
||||
static private bool findAsset<T> (out T asset, out string path) where T : Object {
|
||||
asset = null;
|
||||
path = null;
|
||||
var guids = AssetDatabase.FindAssets ($"t:{typeof (T).ToString()}", new [] { "Assets" });
|
||||
if (guids.Length == 0) return false;
|
||||
path = AssetDatabase.GUIDToAssetPath (guids [0]);
|
||||
asset = AssetDatabase.LoadAssetAtPath<T> (path);
|
||||
return asset != null;
|
||||
}
|
||||
|
||||
static private T createAsset<T> () where T : ScriptableObject {
|
||||
T asset = ScriptableObject.CreateInstance<T> ();
|
||||
MonoScript mono = MonoScript.FromScriptableObject (asset);
|
||||
string scriptPath = AssetDatabase.GetAssetPath (mono);
|
||||
string folderPath = Path.GetDirectoryName (scriptPath).Replace ("\\", "/");
|
||||
string path = $"{folderPath}/{Path.GetFileNameWithoutExtension (scriptPath)}.asset";
|
||||
AssetDatabase.CreateAsset (asset, path);
|
||||
AssetDatabase.SaveAssets ();
|
||||
return asset;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71d38c23289312844bc6e88159ed75c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,935 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR && WCE_URP
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MH.WaterCausticsModules.Effect;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor (typeof (WaterCausticsEffect))]
|
||||
public class WaterCausticsEffectEditor : Editor {
|
||||
private SerializedProperty m_method;
|
||||
private SerializedProperty m_normalSrc;
|
||||
private SerializedProperty m_debugInfo;
|
||||
private SerializedProperty m_debugMode;
|
||||
private SerializedProperty m_useLayer;
|
||||
private SerializedProperty m_renderLayerMask;
|
||||
private SerializedProperty m_layerMask;
|
||||
private SerializedProperty m_clipOutside;
|
||||
private SerializedProperty m_texture;
|
||||
private SerializedProperty m_textureChannel;
|
||||
private SerializedProperty m_textureRotation;
|
||||
private SerializedProperty m_texRotSinCos;
|
||||
private SerializedProperty m_useRandomTiling;
|
||||
private SerializedProperty m_tilingSeed;
|
||||
private SerializedProperty m_tilingRotation;
|
||||
private SerializedProperty m_tilingHardness;
|
||||
private SerializedProperty m_intensity;
|
||||
private SerializedProperty m_mainLit;
|
||||
private SerializedProperty m_addLit;
|
||||
private SerializedProperty m_colorShift;
|
||||
private SerializedProperty m_colorShiftDir;
|
||||
private SerializedProperty m_scale;
|
||||
private SerializedProperty m_surfaceY;
|
||||
private SerializedProperty m_surfFadeStart;
|
||||
private SerializedProperty m_surfFadeEnd;
|
||||
private SerializedProperty m_useDepthFade;
|
||||
private SerializedProperty m_depthFadeStart;
|
||||
private SerializedProperty m_depthFadeEnd;
|
||||
private SerializedProperty m_useDistanceFade;
|
||||
private SerializedProperty m_distanceFadeStart;
|
||||
private SerializedProperty m_distanceFadeEnd;
|
||||
private SerializedProperty m_litSaturation;
|
||||
private SerializedProperty m_multiply;
|
||||
private SerializedProperty m_normalAttenRate;
|
||||
private SerializedProperty m_normalAtten;
|
||||
private SerializedProperty m_transparentBackside;
|
||||
private SerializedProperty m_backsideShadow;
|
||||
private SerializedProperty m_shadowIntensity;
|
||||
private SerializedProperty m_receiveShadows;
|
||||
private SerializedProperty m_useMainLit;
|
||||
private SerializedProperty m_useAddLit;
|
||||
private SerializedProperty m_useImageMask;
|
||||
private SerializedProperty m_imageMaskTexture;
|
||||
private SerializedProperty m_stencilRef;
|
||||
private SerializedProperty m_stencilReadMask;
|
||||
private SerializedProperty m_stencilWriteMask;
|
||||
private SerializedProperty m_stencilComp;
|
||||
private SerializedProperty m_stencilPass;
|
||||
private SerializedProperty m_stencilFail;
|
||||
private SerializedProperty m_stencilZFail;
|
||||
private SerializedProperty m_cullMode;
|
||||
private SerializedProperty m_zWriteMode;
|
||||
private SerializedProperty m_zTestMode;
|
||||
private SerializedProperty m_depthOffsetFactor;
|
||||
private SerializedProperty m_depthOffsetUnits;
|
||||
private SerializedProperty m_shader;
|
||||
private SerializedProperty m_noTexture;
|
||||
private SerializedProperty m_useCustomFunc;
|
||||
private SerializedProperty m_renderEvent;
|
||||
private SerializedProperty m_renderEventAdjust;
|
||||
|
||||
private void prepProperties () {
|
||||
if (m_method != null) return;
|
||||
m_method = serializedObject.FindProperty ("m_method");
|
||||
m_normalSrc = serializedObject.FindProperty ("m_normalSrc");
|
||||
m_debugInfo = serializedObject.FindProperty ("m_debugInfo");
|
||||
m_debugMode = serializedObject.FindProperty ("m_debugMode");
|
||||
m_useLayer = serializedObject.FindProperty ("m_useLayer");
|
||||
m_renderLayerMask = serializedObject.FindProperty ("m_renderLayerMask");
|
||||
m_layerMask = serializedObject.FindProperty ("m_layerMask");
|
||||
m_clipOutside = serializedObject.FindProperty ("m_clipOutside");
|
||||
m_texture = serializedObject.FindProperty ("m_texture");
|
||||
m_textureChannel = serializedObject.FindProperty ("m_textureChannel");
|
||||
m_textureRotation = serializedObject.FindProperty ("m_textureRotation");
|
||||
m_texRotSinCos = serializedObject.FindProperty ("m_texRotSinCos");
|
||||
m_useRandomTiling = serializedObject.FindProperty ("m_useRandomTiling");
|
||||
m_tilingSeed = serializedObject.FindProperty ("m_tilingSeed");
|
||||
m_tilingRotation = serializedObject.FindProperty ("m_tilingRotation");
|
||||
m_tilingHardness = serializedObject.FindProperty ("m_tilingHardness");
|
||||
m_intensity = serializedObject.FindProperty ("m_intensity");
|
||||
m_mainLit = serializedObject.FindProperty ("m_mainLit");
|
||||
m_addLit = serializedObject.FindProperty ("m_addLit");
|
||||
m_colorShift = serializedObject.FindProperty ("m_colorShift");
|
||||
m_colorShiftDir = serializedObject.FindProperty ("m_colorShiftDir");
|
||||
m_scale = serializedObject.FindProperty ("m_scale");
|
||||
m_surfaceY = serializedObject.FindProperty ("m_surfaceY");
|
||||
m_surfFadeStart = serializedObject.FindProperty ("m_surfFadeStart");
|
||||
m_surfFadeEnd = serializedObject.FindProperty ("m_surfFadeEnd");
|
||||
m_useDepthFade = serializedObject.FindProperty ("m_useDepthFade");
|
||||
m_depthFadeStart = serializedObject.FindProperty ("m_depthFadeStart");
|
||||
m_depthFadeEnd = serializedObject.FindProperty ("m_depthFadeEnd");
|
||||
m_useDistanceFade = serializedObject.FindProperty ("m_useDistanceFade");
|
||||
m_distanceFadeStart = serializedObject.FindProperty ("m_distanceFadeStart");
|
||||
m_distanceFadeEnd = serializedObject.FindProperty ("m_distanceFadeEnd");
|
||||
m_litSaturation = serializedObject.FindProperty ("m_litSaturation");
|
||||
m_multiply = serializedObject.FindProperty ("m_multiply");
|
||||
m_normalAttenRate = serializedObject.FindProperty ("m_normalAttenRate");
|
||||
m_normalAtten = serializedObject.FindProperty ("m_normalAtten");
|
||||
m_transparentBackside = serializedObject.FindProperty ("m_transparentBackside");
|
||||
m_backsideShadow = serializedObject.FindProperty ("m_backsideShadow");
|
||||
m_shadowIntensity = serializedObject.FindProperty ("m_shadowIntensity");
|
||||
m_receiveShadows = serializedObject.FindProperty ("m_receiveShadows");
|
||||
m_useMainLit = serializedObject.FindProperty ("m_useMainLit");
|
||||
m_useAddLit = serializedObject.FindProperty ("m_useAddLit");
|
||||
m_useImageMask = serializedObject.FindProperty ("m_useImageMask");
|
||||
m_imageMaskTexture = serializedObject.FindProperty ("m_imageMaskTexture");
|
||||
m_stencilRef = serializedObject.FindProperty ("m_stencilRef");
|
||||
m_stencilReadMask = serializedObject.FindProperty ("m_stencilReadMask");
|
||||
m_stencilWriteMask = serializedObject.FindProperty ("m_stencilWriteMask");
|
||||
m_stencilComp = serializedObject.FindProperty ("m_stencilComp");
|
||||
m_stencilPass = serializedObject.FindProperty ("m_stencilPass");
|
||||
m_stencilFail = serializedObject.FindProperty ("m_stencilFail");
|
||||
m_stencilZFail = serializedObject.FindProperty ("m_stencilZFail");
|
||||
m_cullMode = serializedObject.FindProperty ("m_cullMode");
|
||||
m_zWriteMode = serializedObject.FindProperty ("m_zWriteMode");
|
||||
m_zTestMode = serializedObject.FindProperty ("m_zTestMode");
|
||||
m_depthOffsetFactor = serializedObject.FindProperty ("m_depthOffsetFactor");
|
||||
m_depthOffsetUnits = serializedObject.FindProperty ("m_depthOffsetUnits");
|
||||
m_shader = serializedObject.FindProperty ("m_shader");
|
||||
m_noTexture = serializedObject.FindProperty ("m_noTexture");
|
||||
m_useCustomFunc = serializedObject.FindProperty ("m_useCustomFunc");
|
||||
m_renderEvent = serializedObject.FindProperty ("m_renderEvent");
|
||||
m_renderEventAdjust = serializedObject.FindProperty ("m_renderEventAdjust");
|
||||
}
|
||||
|
||||
private SerializedObject _wceData;
|
||||
private SerializedProperty m_autoManageFeature;
|
||||
private SerializedObject prepWceData () {
|
||||
if (_wceData == null)
|
||||
_wceData = new SerializedObject (WaterCausticsEffectData.GetAsset ());
|
||||
if (m_autoManageFeature == null) {
|
||||
m_autoManageFeature = _wceData.FindProperty ("m_autoManageFeature");
|
||||
}
|
||||
_wceData.Update ();
|
||||
return _wceData;
|
||||
}
|
||||
|
||||
static readonly GUIContent [] _cullingEnumStr = {
|
||||
new GUIContent ("Both"),
|
||||
new GUIContent ("Back"),
|
||||
new GUIContent ("Front"),
|
||||
};
|
||||
|
||||
static readonly string descGenFromDepth = "[Generate from Depth] \nGenerate from _CameraDepthTexture generated by the system. This method is not good for smooth surfaces, but it does produce the correct normals.";
|
||||
static readonly string descCamNormalTex = "[Camera Normals Tex] \nSampling _CameraNormalsTexture generated by the system. This is high quality, but may produce strange results with materials that do not support normal output.";
|
||||
|
||||
static readonly GUIContent [] _normalSrcStr = {
|
||||
new GUIContent ("Generate from Depth (LQ)", $"{descGenFromDepth}\n\n{descCamNormalTex}"),
|
||||
new GUIContent ("Camera Normals Tex (HQ)", $"{descGenFromDepth}\n\n{descCamNormalTex}"),
|
||||
};
|
||||
|
||||
static readonly string [] _renderingLayerMaskNamesSpare = { "Layer1", "Layer2", "Layer3", "Layer4", "Layer5", "Layer6", "Layer7", "Layer8", "Layer9", "Layer10", "Layer11", "Layer12", "Layer13", "Layer14", "Layer15", "Layer16", "Layer17", "Layer18", "Layer19", "Layer20", "Layer21", "Layer22", "Layer23", "Layer24", "Layer25", "Layer26", "Layer27", "Layer28", "Layer29", "Layer30", "Layer31", "Layer32", };
|
||||
|
||||
private List<ScriptableRendererData> _rendererDataList;
|
||||
private bool _hasGetRenderData;
|
||||
|
||||
protected virtual void OnEnable () {
|
||||
foreach (var tar in targets.OfType<WaterCausticsEffect> ())
|
||||
tar.VersionCheck ();
|
||||
}
|
||||
|
||||
UniversalRenderPipelineAsset urpAsset => GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
|
||||
public override void OnInspectorGUI () {
|
||||
if (urpAsset) {
|
||||
var wceData = prepWceData ();
|
||||
prepProperties ();
|
||||
serializedObject.Update ();
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
drawProperties ();
|
||||
serializedObject.ApplyModifiedProperties ();
|
||||
wceData.ApplyModifiedProperties ();
|
||||
if (check.changed) {
|
||||
foreach (var tar in targets.OfType<WaterCausticsEffect> ())
|
||||
tar.OnInspectorChanged ();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// -- URP設定が完了していない場合
|
||||
onInspectorGUI_NotSettingYet ();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------
|
||||
readonly Color colorPinkBar = new Color (1f, 0.3f, 0.6f, 0.3f);
|
||||
readonly Color colorPinkContent = new Color (1f, 0.3f, 0.6f, 1f);
|
||||
readonly Color colorGreenContent = new Color (0.4f, 1f, 0.7f, 1f);
|
||||
private float lineH = EditorGUIUtility.singleLineHeight + 2;
|
||||
readonly float SPACE_SUB_TOP_5 = 5f;
|
||||
readonly float SPACE_SUB_BTM_12 = 12f;
|
||||
readonly float SPACE_MAIN_TOP_7 = 7f;
|
||||
readonly float SPACE_MAIN_BTM_5 = 5f;
|
||||
private Color _defaultGUIColor;
|
||||
|
||||
private void setLabelAreaWidth (float labelWidthMin, float valWidthMin) {
|
||||
if (EditorGUIUtility.labelWidth < labelWidthMin)
|
||||
EditorGUIUtility.labelWidth = labelWidthMin;
|
||||
if (EditorGUIUtility.currentViewWidth - EditorGUIUtility.labelWidth < valWidthMin)
|
||||
EditorGUIUtility.labelWidth = EditorGUIUtility.currentViewWidth - valWidthMin;
|
||||
}
|
||||
|
||||
private void drawProperties () {
|
||||
_defaultGUIColor = GUI.color;
|
||||
storeIndentWidth ();
|
||||
EditorGUIUtility.labelWidth += 6;
|
||||
EditorGUI.indentLevel++;
|
||||
setLabelAreaWidth (labelWidthMin: 140f, valWidthMin: 170f);
|
||||
bool isEditingMultiObj = serializedObject.isEditingMultipleObjects;
|
||||
bool isMethodEach = (m_method.enumValueIndex == (int) Method.EachMesh && !m_method.hasMultipleDifferentValues);
|
||||
bool isMethodOnce = (m_method.enumValueIndex == (int) Method.AtOnce && !m_method.hasMultipleDifferentValues);
|
||||
// ---------------------------------------------------------------------------------- System
|
||||
|
||||
// ------ RendererFeature
|
||||
if (!_hasGetRenderData) {
|
||||
_hasGetRenderData = true;
|
||||
WaterCausticsEffectFeatureEditor.GetAllRendererData (out _rendererDataList);
|
||||
if (WaterCausticsEffectData.GetAsset ().AutoManageFeature)
|
||||
WaterCausticsEffectFeatureEditor.AddFeatureToAllRenderers (_rendererDataList, useUndo : false);
|
||||
}
|
||||
bool someRenderNotHasFeature = !WaterCausticsEffectFeatureEditor.CheckAllHasActiveFeature (_rendererDataList);
|
||||
bool currentRenderNotHasFeature = someRenderNotHasFeature && !WaterCausticsEffectFeature.effective;
|
||||
// ----------------------
|
||||
|
||||
if (expandMainGroup (m_method, true, "System", isPink : currentRenderNotHasFeature)) {
|
||||
EditorGUILayout.Space (SPACE_MAIN_TOP_7);
|
||||
|
||||
// ------ RendererFeature
|
||||
if (someRenderNotHasFeature) {
|
||||
EditorGUI.indentLevel -= 1;
|
||||
// labelWarning("To apply this effect, a Renderer Feature needs to be added to a Renderer.", 11);
|
||||
using (new ColorScope (currentRenderNotHasFeature ? colorPinkContent : _defaultGUIColor)) {
|
||||
string str = "To apply this effect, a Renderer Feature needs to be added to a Renderer.";
|
||||
if (currentRenderNotHasFeature)
|
||||
EditorGUILayout.HelpBox ($"The Renderer Feature has not been added or activated in the current Renderer.\n{str}", MessageType.Warning);
|
||||
else
|
||||
EditorGUILayout.HelpBox ($"The Renderer Feature has not been added or activated in some Renderers.\n{str}", MessageType.Warning);
|
||||
EditorGUILayout.Space (2);
|
||||
Rect rect = GUILayoutUtility.GetRect (0, 0);
|
||||
rect.height = lineH;
|
||||
rect.width *= 0.5f;
|
||||
if (GUI.Button (rect, new GUIContent ("Select Renderer", "Search and select RendererData assets."), EditorStyles.miniButton)) {
|
||||
// -- 選択ボタン
|
||||
if (WaterCausticsEffectFeatureEditor.GetAllRendererData (out var list)) {
|
||||
// -- 成功
|
||||
WaterCausticsEffectFeatureEditor.SelectAndPing (list);
|
||||
if (list.Count >= 2) {
|
||||
var pathStr = WaterCausticsEffectFeatureEditor.AssetsToPathStr (list);
|
||||
EditorApplication.delayCall += () => EditorApplication.delayCall += () =>
|
||||
EditorUtility.DisplayDialog ("Multiple found.", $"Multiple RendererData assets found.\n\n{pathStr}", "OK");
|
||||
}
|
||||
} else {
|
||||
// -- 見つからない
|
||||
EditorUtility.DisplayDialog ("Not found.", $"Not found.", "OK");
|
||||
}
|
||||
}
|
||||
rect.x += rect.width;
|
||||
if (GUI.Button (rect, new GUIContent ("Fix It", "Add a Renderer Feature to Renderers."), EditorStyles.miniButton)) {
|
||||
// -- 追加ボタン
|
||||
if (WaterCausticsEffectFeatureEditor.AddFeatureToAllRenderers (useUndo: true)) {
|
||||
// -- 成功
|
||||
} else {
|
||||
// -- 失敗
|
||||
bool showURL = EditorUtility.DisplayDialog ("Failed", "Processing failed. Please add the Renderer Feature to Renderers manually.", "Open URP Manual", "Cancel");
|
||||
if (showURL) Application.OpenURL (Constant.URL_HOW_TO_ADD_FEATURE);
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Space (lineH);
|
||||
using (new ColorScope (_defaultGUIColor)) {
|
||||
EditorGUILayout.Space (1);
|
||||
if (labelLink (new GUIContent ("How to add Renderer Feature to Renderer", Constant.URL_HOW_TO_ADD_FEATURE), 10))
|
||||
Application.OpenURL (Constant.URL_HOW_TO_ADD_FEATURE);
|
||||
EditorGUILayout.Space (4);
|
||||
}
|
||||
EditorGUI.indentLevel += 1;
|
||||
EditorGUILayout.Space (15);
|
||||
}
|
||||
}
|
||||
// ----------------------
|
||||
|
||||
EditorGUILayout.PropertyField (m_method, new GUIContent ("Effect Method", "[At Once]\nDraws the effect at once using the camera's depth and normal texture. It can also be applied to objects with materials that are deformed by shaders. \n\n[Each Mesh]\nDraws effects to each mesh. Masking with layers and the surface to be drawn can be specified. However, it cannot be applied to objects with materials that deform with shaders. For such objects, embed custom function in the shader or use the At Once method."));
|
||||
if (isMethodOnce) {
|
||||
using (new IndentScope (-2f, 0f)) {
|
||||
popup (m_normalSrc, _normalSrcStr, "Normal Data", $"How to get normal vector in world space.\n\n{descGenFromDepth}\n\n{descCamNormalTex}");
|
||||
}
|
||||
}
|
||||
drawBoolAndValue (m_debugInfo, m_debugMode, true, new GUIContent ("Debug Info", "Display data for debugging. This is only valid on the editor.\n\n" +
|
||||
$"[{DebugMode.Normal}]\nDisplays world-space normal data.\n\n" +
|
||||
$"[{DebugMode.Depth}]\nDisplays the depth data.\n\n" +
|
||||
$"[{DebugMode.Facing}]\nDisplays the plane facing the camera as bright.\n\n" +
|
||||
$"[{DebugMode.Caustics}]\nDisplays only caustics effects.\n\n" +
|
||||
$"[{DebugMode.LightArea}]\nDisplays the affected area by each light.\n\n" +
|
||||
$"If some objects are not rendering correctly on At Once method with Camera Normals Tex, the object's material is outputting the wrong normals. Check the normals on this screen and modify the material (shader) of the object."));
|
||||
|
||||
EditorGUILayout.Space (SPACE_SUB_BTM_12);
|
||||
// ---------------------------------------------------------------------------------- Influence Scope
|
||||
if (expandSubGroup (m_useImageMask, true, "Influence Scope")) {
|
||||
EditorGUILayout.Space (SPACE_SUB_TOP_5);
|
||||
selectGameObjectLayer (new GUIContent ("Layer", "The layer in which this effect exists."));
|
||||
if (isMethodEach) {
|
||||
EditorGUILayout.PropertyField (m_layerMask, new GUIContent ("Layer Mask", "Specify the layer on which the effect will be drawn. Objects on unchecked layers will be ignored."));
|
||||
}
|
||||
if (isMethodEach) {
|
||||
EditorGUILayout.PropertyField (m_clipOutside, new GUIContent ("Clip Outside", "Draw effects only inside the volume."));
|
||||
}
|
||||
drawBoolAndValue (m_useImageMask, m_imageMaskTexture, hide : true, new GUIContent ("Image Mask", "Masking with an image."));
|
||||
|
||||
if (isMethodEach) {
|
||||
popup (m_cullMode, _cullingEnumStr, "Render Face", "Which face to draw.");
|
||||
}
|
||||
|
||||
// EditorGUILayout.Space (2);
|
||||
// if (isExpand (m_renderEventAdjust, false, new GUIContent ("Advanced", "Advanced Settings"))) {
|
||||
// using (new IndentScope (0f, 0f)) {
|
||||
EditorGUILayout.PropertyField (m_useCustomFunc, new GUIContent ("Custom Function", "Supports Custom Function for shader. \nTransmits the settings to the WaterCausticsEmissionSync function embedded in the shader. \nTurning this On will copy the settings to a global shader variable. \n\nIf there are multiple effects with this setting On in a scene, the last active effect will be used."));
|
||||
|
||||
{
|
||||
// 描画タイミング設定
|
||||
bool isExpanded = isExpand (m_renderEvent, true, new GUIContent (""));
|
||||
EditorGUILayout.Space (-EditorGUIUtility.singleLineHeight - 2f);
|
||||
string baseTimingName = splitCamelCase (((RenderPassEvent) m_renderEvent.intValue).ToString ());
|
||||
int sysOpqTiming = (int) WaterCausticsEffect.SYS_OPAQUE_TEX_EVENT;
|
||||
string sysOpqName = WaterCausticsEffect.SYS_OPAQUE_TEX_EVENT.ToString ();
|
||||
string sysOpqDesc = $"{sysOpqName}({sysOpqTiming})";
|
||||
string sysOpqDescPlusOne = $"{sysOpqName}+1 ({sysOpqTiming+1})";
|
||||
string defaultTiming = WaterCausticsEffect.RENDER_EVENT.ToString ();
|
||||
int defaultTimingAdj = WaterCausticsEffect.RENDER_EVENT_ADJ;
|
||||
int baseTiming = m_renderEvent.intValue;
|
||||
int adjTiming = m_renderEventAdjust.intValue;
|
||||
int adjusted = baseTiming + adjTiming;
|
||||
bool isHasDifVal = m_renderEvent.hasMultipleDifferentValues || m_renderEventAdjust.hasMultipleDifferentValues;
|
||||
EditorGUILayout.LabelField (new GUIContent ("Draw Timing", $"Specifies the timing of drawing.\n\nTo display this effect on _CameraOpaqueTexture, it must be drawn before {sysOpqDesc}."), new GUIContent (isHasDifVal ? "-" : $"{baseTimingName} {(adjTiming < 0 ? "-" : "+")}{Mathf.Abs(adjTiming)} ({Mathf.Clamp(adjusted, 0, 1000)})"));
|
||||
if (isExpanded) {
|
||||
using (new IndentScope (-2f, 4f)) {
|
||||
EditorGUILayout.PropertyField (m_renderEvent, new GUIContent ($"Render Event", $"Controls when the render executes. \n[Default: {defaultTiming}]"));
|
||||
EditorGUILayout.PropertyField (m_renderEventAdjust, new GUIContent ("Adjustment", $"Controls when the render executes. This number is added to the Draw Timing above. \n[Default: {defaultTimingAdj}]"));
|
||||
bool isEarly = (adjusted <= sysOpqTiming);
|
||||
string warning = isEarly ? $"To use a value between 0 and 1 in the Multiply Color setting, set it after {sysOpqDescPlusOne}." :
|
||||
$"To display this effect on _CameraOpaqueTexture, it must be drawn before {sysOpqDesc}.";
|
||||
EditorGUILayout.HelpBox (new GUIContent (warning, ""), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isMethodOnce) {
|
||||
var names = urpAsset.renderingLayerMaskNames;
|
||||
if (names == null) names = _renderingLayerMaskNamesSpare;
|
||||
bitMask (m_renderLayerMask, names, "Render Mask", "Rendering Layer Mask of this effect. It works as same as RenderingLayerMask of MeshRenderer.");
|
||||
}
|
||||
if (isMethodEach) {
|
||||
if (isExpand (m_zTestMode, false, new GUIContent ("Depth Buffer", "Adjust Depth Testing and Depth Offset."))) {
|
||||
using (new IndentScope (0, 2)) {
|
||||
EditorGUILayout.PropertyField (m_zWriteMode, new GUIContent ("ZWrite", "Whether to write depth values to the depth buffer."));
|
||||
EditorGUILayout.PropertyField (m_zTestMode, new GUIContent ("ZTest", "Comparison method with already existing depth values."));
|
||||
EditorGUILayout.PropertyField (m_depthOffsetFactor, new GUIContent ("Offset Factor", "Offset Factor"));
|
||||
EditorGUILayout.PropertyField (m_depthOffsetUnits, new GUIContent ("Offset Units", "Offset Units"));
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Space (2);
|
||||
}
|
||||
if (isExpand (m_stencilRef, false, new GUIContent ("Stencil Buffer", "The Stencil Buffer can be used to limit the objects to be drawn or used for subsequent effects."))) {
|
||||
using (new IndentScope (0, 2)) {
|
||||
EditorGUILayout.PropertyField (m_stencilRef, new GUIContent ("Ref", "Stencil Reference Value"));
|
||||
EditorGUILayout.PropertyField (m_stencilReadMask, new GUIContent ("ReadMask", "Stencil Read Mask"));
|
||||
EditorGUILayout.PropertyField (m_stencilWriteMask, new GUIContent ("WriteMask", "Stencil Write Mask"));
|
||||
EditorGUILayout.PropertyField (m_stencilComp, new GUIContent ("Comp", "Stencil Compare Operation"));
|
||||
EditorGUILayout.PropertyField (m_stencilPass, new GUIContent ("Pass", "Stencil Pass Operation"));
|
||||
EditorGUILayout.PropertyField (m_stencilFail, new GUIContent ("Fail", "Stencil Fail Operation"));
|
||||
EditorGUILayout.PropertyField (m_stencilZFail, new GUIContent ("ZFail", "Stencil Z Fail Operation"));
|
||||
}
|
||||
}
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
EditorGUILayout.Space (SPACE_SUB_BTM_12);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space (SPACE_MAIN_BTM_5);
|
||||
// ---------------------------------------------------------------------------------- Effect Group
|
||||
bool useTextureWarning = (m_texture.objectReferenceValue == null && isGameObjectOnScene () && !isEditingMultiObj);
|
||||
if (expandMainGroup (m_texture, true, "Caustics Effect", isPink : useTextureWarning && m_texture.isExpanded)) {
|
||||
EditorGUILayout.Space (SPACE_MAIN_TOP_7);
|
||||
|
||||
if (expandSubGroup (m_textureRotation, true, "Texture", isPink : useTextureWarning)) {
|
||||
EditorGUILayout.Space (SPACE_SUB_TOP_5);
|
||||
|
||||
using (new ColorScope (useTextureWarning?colorPinkContent : GUI.color)) {
|
||||
EditorGUILayout.PropertyField (m_texture, new GUIContent ("Caustics Texture", $"Set the RenderTexture specified as the output destination in the {typeof(WaterCausticsTexGenerator).Name}."));
|
||||
if (!m_texture.hasMultipleDifferentValues) {
|
||||
if (useTextureWarning) {
|
||||
EditorGUILayout.Space (1);
|
||||
EditorGUILayout.BeginHorizontal ();
|
||||
GUILayout.FlexibleSpace ();
|
||||
if (GUILayout.Button ("Search from this Scene", EditorStyles.miniButton, GUILayout.Width (150))) {
|
||||
var gen = FindObjectsOfType<WaterCausticsTexGenerator> ().FirstOrDefault (g => g.renderTexture != null);
|
||||
if (gen != null)
|
||||
m_texture.objectReferenceValue = gen.renderTexture;
|
||||
else
|
||||
EditorUtility.DisplayDialog ("Not Found", $"There is no {typeof(WaterCausticsTexGenerator).Name} with active and having RenderTexture in this scene.", "OK");
|
||||
}
|
||||
EditorGUILayout.EndHorizontal ();
|
||||
EditorGUILayout.Space (3);
|
||||
} else {
|
||||
var tex = m_texture.objectReferenceValue as Texture;
|
||||
if (tex != null) {
|
||||
EditorGUILayout.HelpBox ($"{tex.width}x{tex.height} / {tex.graphicsFormat}", MessageType.None);
|
||||
EditorGUILayout.Space (3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.PropertyField (m_textureChannel, new GUIContent ("Channel", "Channels to be used. Set to R if using R-channel only textures."));
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
using (new IndentScope (0f, 0f, 1)) {
|
||||
EditorGUILayout.PropertyField (m_textureRotation, new GUIContent ("Rotation", "Rotate the texture."));
|
||||
drawDirMark (m_textureRotation, true);
|
||||
}
|
||||
if (check.changed) {
|
||||
float rad = m_textureRotation.floatValue * Mathf.Deg2Rad;
|
||||
m_texRotSinCos.vector2Value = new Vector2 (Mathf.Sin (rad), Mathf.Cos (rad));
|
||||
}
|
||||
}
|
||||
EditorGUILayout.PropertyField (m_useRandomTiling, new GUIContent ("Random Tiling", "Use randomized hexagonal tiling. This reduces unnatural repetitions that appear on distant planes."));
|
||||
if (m_useRandomTiling.boolValue) {
|
||||
using (new IndentScope (-2f, 0f)) {
|
||||
EditorGUILayout.PropertyField (m_tilingSeed, new GUIContent ("Seed", "Random seed value."));
|
||||
EditorGUILayout.PropertyField (m_tilingHardness, new GUIContent ("Hardness", "Edge hardness."));
|
||||
EditorGUILayout.PropertyField (m_tilingRotation, new GUIContent ("Rotation", "Rotate tiles randomly."));
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Space (SPACE_SUB_BTM_12);
|
||||
}
|
||||
|
||||
if (expandSubGroup (m_scale, true, "Dimensions")) {
|
||||
EditorGUILayout.Space (SPACE_SUB_TOP_5);
|
||||
|
||||
EditorGUILayout.PropertyField (m_scale, new GUIContent ("Scale", "Texture size at the height of the water surface."));
|
||||
EditorGUILayout.PropertyField (m_surfaceY, new GUIContent ("Water Surface Y", "Height of the water surface. Y-axis. The projected position of the light is calculated with respect to this plane."));
|
||||
|
||||
EditorGUILayout.Space (4);
|
||||
drawStartEndProp (m_surfFadeStart, m_surfFadeEnd, new GUIContent ("Surface Fade", "Attenuates light as it approaches the surface of the water."));
|
||||
EditorGUILayout.PropertyField (m_useDepthFade, new GUIContent ("Depth Fade", "Attenuates light as depth increases."));
|
||||
if (m_useDepthFade.boolValue) {
|
||||
using (new IndentScope (-2f, 0f))
|
||||
drawStartEndProp (m_depthFadeStart, m_depthFadeEnd, new GUIContent ("Range", "Attenuates light as depth increases."));
|
||||
}
|
||||
EditorGUILayout.PropertyField (m_useDistanceFade, new GUIContent ("Distance Fade", "Attenuates light as distance increases."));
|
||||
if (m_useDistanceFade.boolValue) {
|
||||
using (new IndentScope (-2f, 0f))
|
||||
drawStartEndProp (m_distanceFadeStart, m_distanceFadeEnd, new GUIContent ("Range", "Attenuates light as distance increases."));
|
||||
}
|
||||
|
||||
EditorGUILayout.Space (SPACE_SUB_BTM_12);
|
||||
}
|
||||
if (expandSubGroup (m_intensity, true, "Effect")) {
|
||||
EditorGUILayout.Space (SPACE_SUB_TOP_5);
|
||||
|
||||
EditorGUILayout.PropertyField (m_intensity, new GUIContent ("Intensity", "Intensity of effect."));
|
||||
using (new IndentScope (-1f, 1f)) {
|
||||
drawBoolAndValue (m_useMainLit, m_mainLit, hide : true, new GUIContent ("Main Light", "Adjust the intensity of the main light. If the checkbox is Off, the main light calculation is skipped."));
|
||||
drawBoolAndValue (m_useAddLit, m_addLit, hide : true, new GUIContent ("Additional Lights", "Adjust the intensity of the additional lights. If the check box is Off, the calculation of additional lights is skipped."));
|
||||
}
|
||||
EditorGUILayout.Space (2);
|
||||
|
||||
drawBoolAndValue (m_receiveShadows, m_shadowIntensity, hide : true, new GUIContent ("Shadow", "Strength of shadow. If the checkbox is unchecked, the shadow calculation is skipped. \n\nFor the At Once method, \"Transparent Receive Shadows\" in the URP settings must also be set to On."));
|
||||
EditorGUILayout.Space (2);
|
||||
EditorGUILayout.PropertyField (m_colorShift, new GUIContent ("Color Shift", "Amount of RGB channel shift."));
|
||||
if (m_colorShift.floatValue > 0f) {
|
||||
using (new IndentScope (-2f, 0f, 2)) {
|
||||
EditorGUILayout.PropertyField (m_colorShiftDir, new GUIContent ("Direction", "Direction of shift for RGB channels."));
|
||||
drawDirMark (m_colorShiftDir, true);
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Space (2);
|
||||
|
||||
EditorGUILayout.PropertyField (m_litSaturation, new GUIContent ("Light Color", "Color intensity of the light."));
|
||||
EditorGUILayout.Space (2);
|
||||
EditorGUILayout.PropertyField (m_multiply, new GUIContent ("Multiply Color", "Multiply by the screen color and then add. \nIf this value is 1 or 0, it is processed faster because it uses the shader's Blend function. Otherwise, _CameraOpaqueTexture is sampled and multiplied. If the Draw Timing setting is before _CameraOpaqueTexture is drawn, it is processed as 1."));
|
||||
if (!isEditingMultiObj && (m_multiply.floatValue > 0f && m_multiply.floatValue < 1f) &&
|
||||
((m_renderEvent.intValue + m_renderEventAdjust.intValue) <= (int) WaterCausticsEffect.SYS_OPAQUE_TEX_EVENT)
|
||||
) {
|
||||
// 描画タイミングが早すぎる場合警告
|
||||
using (new IndentScope (0f, 0f)) {
|
||||
EditorGUILayout.HelpBox (new GUIContent ("Only 0 or 1 is valid because the Draw Timing is too early.", "Draw Timing in Influence Scope settings is too early and _CameraOpaqueTexture does not exist, so it cannot be drawn with a setting between 0 and 1. Therefore, it is drawn as 1."), true);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space (3);
|
||||
EditorGUILayout.PropertyField (m_normalAtten, new GUIContent ("Normal Attenuation", "Attenuation due to the angle between the normal and the light ray. \n[Default: 1]")); {
|
||||
using (new IndentScope (-2f, 2f)) {
|
||||
using (new DisableScope (m_normalAtten.floatValue > 0f)) {
|
||||
EditorGUILayout.PropertyField (m_normalAttenRate, new GUIContent ("Rate", "Rate of normal attenuation. How quickly does the light fade. \n[Default: 1.5]"));
|
||||
EditorGUILayout.PropertyField (m_transparentBackside, new GUIContent ("Transparent", "The intensity of light transmitted to the backside. \n[Default: 0]"));
|
||||
}
|
||||
using (new DisableScope (m_receiveShadows.boolValue && (m_normalAtten.floatValue < 1f || m_transparentBackside.floatValue > 0f))) {
|
||||
EditorGUILayout.PropertyField (m_backsideShadow, new GUIContent ("Backside Shadow", "The intensity of shadow on the backside. \n[Default: 0]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Space (SPACE_SUB_BTM_12);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space (SPACE_MAIN_BTM_5);
|
||||
// ---------------------------------------------------------------------------------- Advanced Settings
|
||||
if (expandMainGroup (m_backsideShadow, false, "Advanced Settings")) {
|
||||
EditorGUILayout.Space (SPACE_MAIN_TOP_7);
|
||||
|
||||
if (expandSubGroup (m_normalAttenRate, false, "Renderer Feature")) {
|
||||
EditorGUILayout.Space (SPACE_SUB_TOP_5);
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
EditorGUILayout.PropertyField (m_autoManageFeature, new GUIContent ("Auto-Management", "Automatically manages Renderer Feature. It automatically adds the Renderer Feature for this effect to all Renderer Data in the project.\n\nIf this is turned off, it is required to manually add the Renderer Feature to the Renderer Data."));
|
||||
if (check.changed && m_autoManageFeature.boolValue == true) {
|
||||
WaterCausticsEffectFeatureEditor.AddFeatureToAllRenderers (useUndo: false);
|
||||
}
|
||||
if (!m_autoManageFeature.boolValue) {
|
||||
EditorGUILayout.Space (1);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.HelpBox ("To apply this effect, a Renderer Feature needs to be added to a Renderer.", MessageType.None);
|
||||
EditorGUILayout.Space (1);
|
||||
if (labelLink (new GUIContent ("How to add Renderer Feature to Renderer", Constant.URL_HOW_TO_ADD_FEATURE), 10, 2))
|
||||
Application.OpenURL (Constant.URL_HOW_TO_ADD_FEATURE);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
EditorGUILayout.Space (SPACE_SUB_BTM_12);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EditorGUILayout.Space (SPACE_SUB_BTM_12);
|
||||
EditorGUILayout.Space (SPACE_MAIN_BTM_5);
|
||||
EditorGUILayout.Space (SPACE_MAIN_BTM_5);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------- Parts
|
||||
private string splitCamelCase (string str) {
|
||||
return Regex.Replace (
|
||||
Regex.Replace (str, @"(\P{Ll})(\P{Ll}\p{Ll})", "$1 $2"), @"(\p{Ll})(\P{Ll})", "$1 $2");
|
||||
}
|
||||
|
||||
private float _indentWidth;
|
||||
private void storeIndentWidth () {
|
||||
if (_indentWidth != 0f) return;
|
||||
var x0 = EditorGUI.IndentedRect (Rect.zero).x;
|
||||
EditorGUI.indentLevel++;
|
||||
_indentWidth = EditorGUI.IndentedRect (Rect.zero).x - x0;
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
private void drawBoolAndValue (SerializedProperty propBool, SerializedProperty propValue, bool hide, GUIContent label) {
|
||||
EditorGUILayout.PropertyField (propBool, label);
|
||||
var rect = GUILayoutUtility.GetLastRect ();
|
||||
var labelW = EditorGUIUtility.labelWidth;
|
||||
if (!hide || propBool.boolValue) {
|
||||
using (new DisableScope (propBool.boolValue)) {
|
||||
EditorGUIUtility.labelWidth += 25;
|
||||
EditorGUI.PropertyField (rect, propValue, new GUIContent (" "));
|
||||
}
|
||||
}
|
||||
EditorGUIUtility.labelWidth = labelW;
|
||||
}
|
||||
|
||||
private void selectGameObjectLayer (GUIContent label) {
|
||||
var gameObjects = targets.Select (t => (t as WaterCausticsEffect).gameObject).ToArray ();
|
||||
var layers = gameObjects.Select (go => go.layer).Distinct ().ToArray ();
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
EditorGUI.showMixedValue = (layers.Length != 1);
|
||||
int newVal = EditorGUILayout.LayerField (label, layers [0]);
|
||||
EditorGUI.showMixedValue = false;
|
||||
if (check.changed) {
|
||||
Undo.RecordObjects (gameObjects, "Changed Layer");
|
||||
foreach (var go in gameObjects) {
|
||||
go.layer = newVal;
|
||||
EditorUtility.SetDirty (go);
|
||||
}
|
||||
if (layers.Length >= 2 && gameObjects.Length == Selection.objects.Length) {
|
||||
// 上部のレイヤー表示Multiple(-)を更新するため選択中の場合は再選択
|
||||
bool isSelected = true;
|
||||
foreach (var o in gameObjects) {
|
||||
if (!Selection.objects.Contains (o)) {
|
||||
isSelected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isSelected) {
|
||||
Selection.activeGameObject = null;
|
||||
EditorApplication.delayCall += () => { Selection.objects = gameObjects; };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void selectLayer (SerializedProperty prop, GUIContent label) {
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
|
||||
var newVal = EditorGUILayout.LayerField (label, prop.intValue);
|
||||
EditorGUI.showMixedValue = false;
|
||||
if (check.changed)
|
||||
prop.intValue = newVal;
|
||||
}
|
||||
}
|
||||
|
||||
private void drawStartEndProp (SerializedProperty propStt, SerializedProperty propEnd, GUIContent label) {
|
||||
EditorGUILayout.LabelField (label);
|
||||
var rect = GUILayoutUtility.GetLastRect ();
|
||||
rect.x += EditorGUIUtility.labelWidth;
|
||||
rect.width -= EditorGUIUtility.labelWidth;
|
||||
drawStartEndPropInRect (rect, propStt, propEnd);
|
||||
}
|
||||
|
||||
|
||||
private void drawStartEndPropInRect (Rect rect, SerializedProperty propStt, SerializedProperty propEnd) {
|
||||
bool isWide = (rect.width > 140);
|
||||
float span = isWide ? 5f : 3f;
|
||||
var rect2 = rect;
|
||||
var rect3 = rect;
|
||||
rect2.width = rect3.width = (rect.width - span) * 0.5f;
|
||||
rect3.x += rect2.width + span;
|
||||
var storeIndent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
var labelW = EditorGUIUtility.labelWidth;
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
EditorGUI.showMixedValue = propStt.hasMultipleDifferentValues;
|
||||
EditorGUIUtility.labelWidth = isWide? 32 : 10;
|
||||
float newStt = EditorGUI.FloatField (rect2, isWide ? "Start" : "S", propStt.floatValue);
|
||||
if (check.changed)
|
||||
propStt.floatValue = Mathf.Clamp (newStt, 0, propEnd.floatValue);
|
||||
}
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
EditorGUI.showMixedValue = propEnd.hasMultipleDifferentValues;
|
||||
EditorGUIUtility.labelWidth = isWide ? 26 : 10;
|
||||
float newEnd = EditorGUI.FloatField (rect3, isWide ? "End" : "E", propEnd.floatValue);
|
||||
if (check.changed)
|
||||
propEnd.floatValue = Mathf.Max (newEnd, propStt.floatValue);
|
||||
}
|
||||
EditorGUI.showMixedValue = false;
|
||||
EditorGUIUtility.labelWidth = labelW;
|
||||
EditorGUI.indentLevel = storeIndent;
|
||||
}
|
||||
|
||||
static private Color colorMulAlpha (Color c, float mulAlpha) => new Color (c.r, c.g, c.b, c.a * mulAlpha);
|
||||
|
||||
private void drawDirMark (SerializedProperty prop, bool isActive = true) {
|
||||
EditorGUI.indentLevel--;
|
||||
var rect = EditorGUI.IndentedRect (GUILayoutUtility.GetLastRect ());
|
||||
drawDirMark (rect, prop, isActive);
|
||||
EditorGUI.indentLevel++;
|
||||
}
|
||||
private void drawDirMark (Rect rect, SerializedProperty prop, bool isActive = true) {
|
||||
rect.width = EditorGUIUtility.labelWidth;
|
||||
Vector2 origin = new Vector2 (CIRCLE_R + 1, rect.height * 0.5f);
|
||||
float dir = prop.floatValue;
|
||||
Handles.color = colorMulAlpha (EditorStyles.label.normal.textColor, isActive ? 0.8f : 0.4f);
|
||||
var tmpMatrix = Handles.matrix;
|
||||
GUI.BeginClip (rect, origin, Vector2.zero, false);
|
||||
Handles.matrix = tmpMatrix * Matrix4x4.Scale (Vector3.one * CIRCLE_R);
|
||||
Handles.DrawAAPolyLine (Texture2D.whiteTexture, 1, circlePts);
|
||||
if (!prop.hasMultipleDifferentValues) {
|
||||
Handles.matrix = tmpMatrix * Matrix4x4.Rotate (Quaternion.Euler (0f, 0f, dir)) * Matrix4x4.Scale (Vector3.one * (CIRCLE_R - 0.5f));
|
||||
Handles.DrawAAConvexPolygon (arrowAry);
|
||||
}
|
||||
Handles.matrix = tmpMatrix;
|
||||
GUI.EndClip ();
|
||||
}
|
||||
|
||||
static private Vector2 dirToVec (float dir) => new Vector2 (Mathf.Sin (dir * Mathf.Deg2Rad), -Mathf.Cos (dir * Mathf.Deg2Rad));
|
||||
const float CIRCLE_R = 5f;
|
||||
static readonly private Vector3 [] arrowAry = {
|
||||
dirToVec (0),
|
||||
dirToVec (150f),
|
||||
dirToVec (170f),
|
||||
dirToVec (-170f),
|
||||
dirToVec (-150f),
|
||||
};
|
||||
static readonly private Vector3 [] circlePts = {
|
||||
new Vector3 (-1f, 0f),
|
||||
new Vector3 (-0.87f, -0.5f),
|
||||
new Vector3 (-0.5f, -0.87f),
|
||||
new Vector3 (0f, -1f),
|
||||
new Vector3 (0.5f, -0.87f),
|
||||
new Vector3 (0.87f, -0.5f),
|
||||
new Vector3 (1f, 0f),
|
||||
new Vector3 (0.87f, 0.5f),
|
||||
new Vector3 (0.5f, 0.87f),
|
||||
new Vector3 (0f, 1f),
|
||||
new Vector3 (-0.5f, 0.87f),
|
||||
new Vector3 (-0.87f, 0.5f),
|
||||
new Vector3 (-1f, 0f),
|
||||
};
|
||||
|
||||
bool isGameObjectOnScene () {
|
||||
return (target as Component).gameObject.scene.IsValid ();
|
||||
}
|
||||
|
||||
private void drawRectMain (bool isPink = false) {
|
||||
Color color = isPink ? colorPinkBar : new Color (0f, 0f, 0f, 0.2f);
|
||||
Rect rect = GUILayoutUtility.GetRect (0, 0);
|
||||
rect.height = lineH;
|
||||
rect.x -= _indentWidth + 4;
|
||||
rect.width += _indentWidth + 8;
|
||||
EditorGUI.DrawRect (rect, color);
|
||||
}
|
||||
|
||||
private bool expandMainGroup (SerializedProperty prop, bool defOpen, string label, bool isPink = false) {
|
||||
EditorGUI.indentLevel--;
|
||||
drawRectMain (isPink);
|
||||
bool expand = isExpand (prop, true, new GUIContent (label));
|
||||
EditorGUI.indentLevel++;
|
||||
return expand;
|
||||
}
|
||||
|
||||
private bool expandSubGroup (SerializedProperty prop, bool defOpen, string label, bool isPink = false) {
|
||||
Color color = isPink ? colorPinkBar : colorMulAlpha (EditorStyles.label.normal.textColor, 0.1f);
|
||||
GUILayout.Label (" ");
|
||||
Rect rect = GUILayoutUtility.GetLastRect ();
|
||||
rect.y += 1f;
|
||||
rect.x += 3f;
|
||||
rect.width -= 3f;
|
||||
Rect rect2 = rect;
|
||||
rect2.x -= 14f;
|
||||
rect2.width += 15f;
|
||||
EditorGUI.DrawRect (rect2, color);
|
||||
GUI.Label (rect, label);
|
||||
if (prop == null) {
|
||||
return true;
|
||||
} else {
|
||||
rect.x -= 14;
|
||||
prop.isExpanded = EditorGUI.Foldout (rect, prop.isExpanded != defOpen, " ") != defOpen;
|
||||
return prop.isExpanded != defOpen;
|
||||
}
|
||||
}
|
||||
|
||||
private void popup (SerializedProperty prop, GUIContent [] enumStr, string text, string tooltip) {
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
|
||||
var newVal = EditorGUILayout.Popup (new GUIContent (text, tooltip), prop.enumValueIndex, enumStr);
|
||||
EditorGUI.showMixedValue = false;
|
||||
if (check.changed)
|
||||
prop.enumValueIndex = newVal;
|
||||
}
|
||||
}
|
||||
|
||||
private void popup (SerializedProperty prop, string [] enumStr, string text, string tooltip) {
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
|
||||
var newVal = EditorGUILayout.Popup (new GUIContent (text, tooltip), prop.enumValueIndex, enumStr);
|
||||
EditorGUI.showMixedValue = false;
|
||||
if (check.changed)
|
||||
prop.enumValueIndex = newVal;
|
||||
}
|
||||
}
|
||||
|
||||
private void bitMask (SerializedProperty prop, string [] options, string text, string tooltip) {
|
||||
using (var check = new EditorGUI.ChangeCheckScope ()) {
|
||||
EditorGUI.showMixedValue = prop.hasMultipleDifferentValues;
|
||||
int newVal = EditorGUILayout.MaskField (new GUIContent (text, tooltip), prop.intValue, options);
|
||||
EditorGUI.showMixedValue = false;
|
||||
if (check.changed) {
|
||||
uint uintVal = unchecked ((uint) newVal);
|
||||
prop.longValue = uintVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool isExpand (SerializedProperty prop, bool isDefaultOpen, GUIContent label) {
|
||||
prop.isExpanded = EditorGUILayout.Foldout (prop.isExpanded != isDefaultOpen, label) != isDefaultOpen;
|
||||
return prop.isExpanded != isDefaultOpen;
|
||||
}
|
||||
|
||||
private bool isExpandMarkOnly (SerializedProperty prop, bool isDefaultOpen, float adjustX = 0f, float adjustY = 0f) {
|
||||
var rect = GUILayoutUtility.GetLastRect ();
|
||||
prop.isExpanded = EditorGUI.Foldout (rect, prop.isExpanded != isDefaultOpen, " ") != isDefaultOpen;
|
||||
return prop.isExpanded != isDefaultOpen;
|
||||
}
|
||||
|
||||
private void drawLine () {
|
||||
Rect r = GUILayoutUtility.GetRect (0, 0);
|
||||
Color col = colorMulAlpha (EditorStyles.label.normal.textColor, 0.09f);
|
||||
EditorGUI.DrawRect (new Rect (r.x + 14f, r.y, r.width - 14f, 1f), col);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------- Scope
|
||||
private class AdjustLabelSpaceWidthScope : GUI.Scope {
|
||||
private readonly float _store;
|
||||
internal AdjustLabelSpaceWidthScope (float adjust) {
|
||||
_store = EditorGUIUtility.labelWidth;
|
||||
EditorGUIUtility.labelWidth += adjust;
|
||||
}
|
||||
protected override void CloseScope () {
|
||||
EditorGUIUtility.labelWidth = _store;
|
||||
}
|
||||
}
|
||||
|
||||
private class LabelAndIndentScope : GUI.Scope {
|
||||
private float _spaceBtm;
|
||||
internal LabelAndIndentScope (GUIContent label, float spaceTop = 0f, float spaceMid = 2f, float spaceBtm = 0f) {
|
||||
_spaceBtm = spaceBtm;
|
||||
EditorGUILayout.Space (spaceTop);
|
||||
EditorGUILayout.LabelField (label);
|
||||
EditorGUILayout.Space (spaceMid);
|
||||
EditorGUI.indentLevel++;
|
||||
}
|
||||
protected override void CloseScope () {
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.Space (_spaceBtm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class IndentScope : GUI.Scope {
|
||||
private float _spaceBtm;
|
||||
private int _indent;
|
||||
internal IndentScope (float spaceTop = 3f, float spaceBtm = 10f, int indent = 1) {
|
||||
_spaceBtm = spaceBtm;
|
||||
_indent = indent;
|
||||
EditorGUILayout.Space (spaceTop);
|
||||
EditorGUI.indentLevel += indent;
|
||||
}
|
||||
protected override void CloseScope () {
|
||||
EditorGUI.indentLevel -= _indent;
|
||||
EditorGUILayout.Space (_spaceBtm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class DisableScope : GUI.Scope {
|
||||
private readonly bool _tmp;
|
||||
internal DisableScope (bool isActive = false) {
|
||||
_tmp = isActive;
|
||||
if (!_tmp) EditorGUI.BeginDisabledGroup (true);
|
||||
}
|
||||
protected override void CloseScope () {
|
||||
if (!_tmp) EditorGUI.EndDisabledGroup ();
|
||||
}
|
||||
}
|
||||
|
||||
private class ColorScope : GUI.Scope {
|
||||
private readonly Color _tmp;
|
||||
internal ColorScope (Color color) {
|
||||
_tmp = GUI.color;
|
||||
GUI.color = color;
|
||||
}
|
||||
protected override void CloseScope () {
|
||||
GUI.color = _tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------- URPパッケージは在るけれど 設定が完了していない場合
|
||||
private bool isDark => EditorGUIUtility.isProSkin;
|
||||
private GUIStyle _textStyle, _linkUrlStyle, _warningStyle;
|
||||
|
||||
private void prepStyle () {
|
||||
if (_textStyle == null) {
|
||||
_textStyle = new GUIStyle (EditorStyles.label);
|
||||
_textStyle.wordWrap = true;
|
||||
_textStyle.fontSize = 14;
|
||||
|
||||
_linkUrlStyle = new GUIStyle (_textStyle);
|
||||
_linkUrlStyle.wordWrap = false;
|
||||
_linkUrlStyle.normal.textColor = isDark ? new Color (0f, 0.8f, 1f, 1f) : new Color (0f, 0.4f, 0.8f, 1f);
|
||||
_linkUrlStyle.hover.textColor = _linkUrlStyle.normal.textColor + Color.white * (isDark ? 0.3f : 0.2f);
|
||||
_linkUrlStyle.stretchWidth = false;
|
||||
|
||||
_warningStyle = new GUIStyle (_textStyle);
|
||||
_warningStyle.normal.textColor = isDark ? Color.white : new Color (0.8f, 0.1f, 0f, 1f);
|
||||
_warningStyle.normal.background = Texture2D.whiteTexture;
|
||||
}
|
||||
}
|
||||
|
||||
private void onInspectorGUI_NotSettingYet () {
|
||||
prepStyle ();
|
||||
storeIndentWidth ();
|
||||
EditorGUILayout.Space (50);
|
||||
labelWarning ($"UniversalRP setup is not completed.");
|
||||
EditorGUILayout.Space (10);
|
||||
GUILayout.Label ($"Please refer to the Unity manual page to setup, or create a new project with the URP 3D template.", _textStyle);
|
||||
EditorGUILayout.Space (10);
|
||||
var urlA = "https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@12.0/manual/InstallURPIntoAProject.html";
|
||||
if (labelLink (new GUIContent ("Unity URP Setup Manual", urlA)))
|
||||
Application.OpenURL (urlA);
|
||||
EditorGUILayout.Space (5);
|
||||
var urlB = Constant.URL_MANUAL;
|
||||
if (labelLink (new GUIContent ("Asset Manual", urlB)))
|
||||
Application.OpenURL (urlB);
|
||||
EditorGUILayout.Space (50);
|
||||
}
|
||||
|
||||
void labelWarning (string text, int fontSize = 18) {
|
||||
prepStyle ();
|
||||
_warningStyle.fontSize = fontSize;
|
||||
Color tmp = GUI.backgroundColor;
|
||||
GUI.backgroundColor = isDark ? new Color (1f, 0.3f, 0.6f, 0.4f) : new Color (1f, 0.3f, 0.6f, 0.5f);
|
||||
GUILayout.Label (text, _warningStyle);
|
||||
GUI.backgroundColor = tmp;
|
||||
}
|
||||
|
||||
private bool labelLink (GUIContent label, int fontSize = 14, int indent = 0, params GUILayoutOption [] options) {
|
||||
prepStyle ();
|
||||
_linkUrlStyle.fontSize = fontSize;
|
||||
var rect = GUILayoutUtility.GetRect (label, _linkUrlStyle, options);
|
||||
rect.x += indent * _indentWidth;
|
||||
Handles.BeginGUI ();
|
||||
Handles.color = _linkUrlStyle.normal.textColor;
|
||||
Handles.DrawLine (new Vector3 (rect.xMin, rect.yMax), new Vector3 (rect.xMax, rect.yMax));
|
||||
Handles.color = Color.white;
|
||||
Handles.EndGUI ();
|
||||
EditorGUIUtility.AddCursorRect (rect, MouseCursor.Link);
|
||||
return GUI.Button (rect, label, _linkUrlStyle);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // End of WCE_URP
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5998e4477e64d9b47a7297a804fff2ab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,207 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR && WCE_URP
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
[CustomEditor (typeof (WaterCausticsEffectFeature), true)]
|
||||
public class WaterCausticsEffectFeatureEditor : Editor {
|
||||
private GUIStyle _style;
|
||||
private void init () {
|
||||
_style = new GUIStyle (EditorStyles.label);
|
||||
_style.wordWrap = true;
|
||||
_style.fontSize -= 1;
|
||||
}
|
||||
public override void OnInspectorGUI () {
|
||||
if (_style == null) init ();
|
||||
EditorGUILayout.Space (10);
|
||||
string str = "This Renderer Function is required to apply WaterCausticsEffect.";
|
||||
GUILayout.Label (str, _style);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
// static internal bool AddToCurrentRendererData (bool useUndo) {
|
||||
// if (GetCurrentRendererData (out var dt))
|
||||
// return AddFeatureToRenderer (dt, useUndo);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// static internal bool GetCurrentRendererData (out ScriptableRendererData dt) {
|
||||
// dt = null;
|
||||
// try {
|
||||
// var urpAsset = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
|
||||
// var propertyInfo = typeof (UniversalRenderPipelineAsset).GetProperty ("scriptableRendererData", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
||||
// if (propertyInfo == null) return false;
|
||||
// dt = propertyInfo.GetValue (urpAsset) as ScriptableRendererData;
|
||||
// return dt != null;
|
||||
// } catch { }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
|
||||
public class ModificationProcessor : UnityEditor.AssetModificationProcessor {
|
||||
// WaterCausticsEffectFeatureスクリプトが削除されるとき、登録済みのRendererFeatureを削除
|
||||
// ※フォルダ削除時、中身のパスは渡されないので注意
|
||||
private static AssetDeleteResult OnWillDeleteAsset (string deletePath, RemoveAssetOptions options) {
|
||||
bool isDirectory = File.GetAttributes (deletePath).HasFlag (FileAttributes.Directory);
|
||||
string scriptPath = getScriptPath<WaterCausticsEffectFeature> ();
|
||||
if ((isDirectory && scriptPath.StartsWith (deletePath)) || deletePath == scriptPath) {
|
||||
// RendererFeatureを削除
|
||||
DeleteAllFeatures ();
|
||||
}
|
||||
return AssetDeleteResult.DidNotDelete;
|
||||
}
|
||||
}
|
||||
|
||||
static private string getScriptPath<T> () where T : ScriptableObject {
|
||||
T asset = ScriptableObject.CreateInstance<T> ();
|
||||
MonoScript mono = MonoScript.FromScriptableObject (asset);
|
||||
string path = AssetDatabase.GetAssetPath (mono);
|
||||
if (Application.isPlaying) Destroy (asset);
|
||||
else DestroyImmediate (asset);
|
||||
return path;
|
||||
}
|
||||
|
||||
#if WCE_DEVELOPMENT
|
||||
[MenuItem ("WCM/RendererFeatureTest/DeleteAllFeatures")]
|
||||
#endif
|
||||
static internal void DeleteAllFeatures () {
|
||||
if (GetAllRendererData (out var list))
|
||||
foreach (var dt in list)
|
||||
DeleteFeature (dt);
|
||||
}
|
||||
|
||||
static internal void DeleteFeature (ScriptableRendererData dt) {
|
||||
if (!dt) return;
|
||||
try {
|
||||
// ※ TODO URPのバージョンが上がるたび処理方法に変更がないか要確認
|
||||
if (dt.rendererFeatures.Any (a => a is WaterCausticsEffectFeature)) {
|
||||
if (!EditorUtility.IsPersistent (dt)) return;
|
||||
var feature = dt.rendererFeatures.FirstOrDefault (a => a is WaterCausticsEffectFeature);
|
||||
AssetDatabase.RemoveObjectFromAsset (feature);
|
||||
dt.rendererFeatures.Remove (feature);
|
||||
dt.SetDirty ();
|
||||
EditorUtility.SetDirty (dt);
|
||||
saveAssetSafe (dt);
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
|
||||
static private void saveAssetSafe (Object o) {
|
||||
// ※AssetDatabase.SaveAssetIfDirty は Unity 2021.1.17、2020.3.16で追加されたので分岐
|
||||
#if !UNITY_2020_3_OR_NEWER || UNITY_2020_3_0 || UNITY_2020_3_1 || UNITY_2020_3_2 || UNITY_2020_3_3 || UNITY_2020_3_4 || UNITY_2020_3_5 || UNITY_2020_3_6 || UNITY_2020_3_7 || UNITY_2020_3_8 || UNITY_2020_3_9 || UNITY_2020_3_10 || UNITY_2020_3_11 || UNITY_2020_3_12 || UNITY_2020_3_13 || UNITY_2020_3_14 || UNITY_2020_3_15 || UNITY_2021_1
|
||||
AssetDatabase.SaveAssets ();
|
||||
#else
|
||||
AssetDatabase.SaveAssetIfDirty (o);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static internal bool AddFeatureToRenderer (ScriptableRendererData dt, bool useUndo) {
|
||||
if (!dt) return false;
|
||||
try {
|
||||
if (dt.rendererFeatures.Any (a => a is WaterCausticsEffectFeature)) {
|
||||
// -- すでにある場合 アクティブ化
|
||||
var feature = dt.rendererFeatures.FirstOrDefault (a => a is WaterCausticsEffectFeature) as WaterCausticsEffectFeature;
|
||||
//if (!feature.isActive) {
|
||||
//if (useUndo) Undo.RegisterCompleteObjectUndo (feature, "Feature Set Active");
|
||||
//feature.SetActive (true);
|
||||
//EditorUtility.SetDirty (feature);
|
||||
//saveAssetSafe (dt);
|
||||
//}
|
||||
WaterCausticsEffectFeature.OnAddedByScript ();
|
||||
return true;
|
||||
} else {
|
||||
// -- まだ無い場合
|
||||
// ※ TODO URPのバージョンが上がるたび処理方法に変更がないか要確認 10.9, 12.1, 14.0 OK
|
||||
if (!EditorUtility.IsPersistent (dt)) return false;
|
||||
var validateMethod = dt.GetType ().GetMethod ("ValidateRendererFeatures", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
if (validateMethod == null) return false;
|
||||
var feature = ScriptableRendererFeature.CreateInstance<WaterCausticsEffectFeature> ();
|
||||
feature.name = typeof (WaterCausticsEffect).Name;
|
||||
if (useUndo) {
|
||||
Undo.RegisterCreatedObjectUndo (feature, "Add Renderer Feature");
|
||||
Undo.RegisterCompleteObjectUndo (dt, "Add Renderer Feature");
|
||||
}
|
||||
AssetDatabase.AddObjectToAsset (feature, dt);
|
||||
dt.rendererFeatures.Add (feature);
|
||||
validateMethod.Invoke (dt, null);
|
||||
dt.SetDirty ();
|
||||
EditorUtility.SetDirty (dt);
|
||||
saveAssetSafe (dt);
|
||||
WaterCausticsEffectFeature.OnAddedByScript ();
|
||||
return true;
|
||||
}
|
||||
} catch { }
|
||||
return false;
|
||||
}
|
||||
|
||||
static internal bool CheckAllHasActiveFeature (List<ScriptableRendererData> list) {
|
||||
return list != null && !list.Any (a => checkHasActiveFeature (a) == false);
|
||||
}
|
||||
|
||||
static internal bool checkHasActiveFeature (ScriptableRendererData dt) {
|
||||
return dt != null && dt.rendererFeatures.Any (a => a is WaterCausticsEffectFeature && a.isActive);
|
||||
}
|
||||
|
||||
static internal bool AddFeatureToAllRenderers (out List<ScriptableRendererData> list, bool useUndo) {
|
||||
if (GetAllRendererData (out list))
|
||||
return AddFeatureToAllRenderers (list, useUndo);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WCE_DEVELOPMENT
|
||||
[MenuItem ("WCM/RendererFeatureTest/AddFeatureToAllRenderers")]
|
||||
#endif
|
||||
static internal bool AddFeatureToAllRenderers () {
|
||||
return AddFeatureToAllRenderers (useUndo: true);
|
||||
|
||||
}
|
||||
static internal bool AddFeatureToAllRenderers (bool useUndo) {
|
||||
if (GetAllRendererData (out var list))
|
||||
return AddFeatureToAllRenderers (list, useUndo);
|
||||
return false;
|
||||
}
|
||||
|
||||
static internal bool AddFeatureToAllRenderers (List<ScriptableRendererData> list, bool useUndo) {
|
||||
if (list == null) return false;
|
||||
bool result = true;
|
||||
foreach (var dt in list)
|
||||
result &= AddFeatureToRenderer (dt, useUndo);
|
||||
return result;
|
||||
}
|
||||
|
||||
static internal bool GetAllRendererData (out List<ScriptableRendererData> list) {
|
||||
list = new List<ScriptableRendererData> ();
|
||||
var guids = AssetDatabase.FindAssets ($"t:{typeof(ScriptableRendererData).ToString()}", new [] { "Assets" });
|
||||
if (guids.Length == 0) return false;
|
||||
foreach (var guid in guids) {
|
||||
var dt = AssetDatabase.LoadAssetAtPath<ScriptableRendererData> (AssetDatabase.GUIDToAssetPath (guid));
|
||||
list.Add (dt);
|
||||
}
|
||||
return list.Count != 0;
|
||||
}
|
||||
|
||||
static internal void SelectAndPing (List<ScriptableRendererData> list) {
|
||||
Selection.objects = list.ToArray ();
|
||||
foreach (var dt in list) EditorGUIUtility.PingObject (dt);
|
||||
}
|
||||
|
||||
static internal string AssetsToPathStr (List<ScriptableRendererData> list) {
|
||||
var str = "";
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
str += $"{i+1}: {AssetDatabase.GetAssetPath (list [i])}\n";
|
||||
return str;
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8b3f56e6e68f2d4fbdf5ad470a2fa4d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if UNITY_EDITOR && WCE_URP
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
public class WaterCausticsEffectMenuItem {
|
||||
[MenuItem ("GameObject/WaterCausticsModules/TexGen and Effect (with RenderTexture Asset)", false, 0)]
|
||||
static public void CreateTexGenAndEffectPair () {
|
||||
var texGen = WaterCausticsTexGeneratorMenuItem.CreateTexGeneratorWithRT ();
|
||||
var effect = createEffectGO ();
|
||||
effect.texture = texGen.renderTexture;
|
||||
}
|
||||
|
||||
[MenuItem ("GameObject/WaterCausticsModules/Effect", false, 3)]
|
||||
static public void CreateEffectGO () {
|
||||
GameObject selectedGO = Selection.activeGameObject;
|
||||
var effect = createEffectGO ();
|
||||
var texGen = selectedGO?.GetComponent<WaterCausticsTexGenerator> ();
|
||||
if (texGen == null)
|
||||
texGen = Object.FindObjectOfType<WaterCausticsTexGenerator> ();
|
||||
if (texGen != null)
|
||||
effect.texture = texGen.renderTexture;
|
||||
}
|
||||
|
||||
static private WaterCausticsEffect createEffectGO () {
|
||||
var go = new GameObject ("WaterCausticsEffect");
|
||||
Undo.RegisterCreatedObjectUndo (go, "Create WaterCausticsEffect");
|
||||
var tra = go.transform;
|
||||
if (Selection.activeGameObject != null) {
|
||||
var baseTra = Selection.activeGameObject.transform;
|
||||
tra.parent = baseTra.parent;
|
||||
tra.SetSiblingIndex (baseTra.GetSiblingIndex () + 1);
|
||||
}
|
||||
tra.localPosition = Vector3.zero;
|
||||
tra.localRotation = Quaternion.identity;
|
||||
tra.localScale = Vector3.one * 3f;
|
||||
Selection.activeObject = go;
|
||||
Selection.activeObject = null;
|
||||
Selection.activeObject = go;
|
||||
return go.AddComponent<WaterCausticsEffect> ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cde63416afd7d524cb16551f6e60fa41
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e975b56feadc05a4a9da076c953ae619
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_imageMaskTexture: {fileID: 2800000, guid: f88b6df342d5c4f4a969fb6eb4799d3e, type: 3}
|
||||
- m_texture: {instanceID: 0}
|
||||
- m_shader: {fileID: 4800000, guid: 348afebc23c3c6e4c8f05f2ea8f758fc, type: 3}
|
||||
- m_noTexture: {fileID: 2800000, guid: 27623e5a17b6fd44a9af57a733ee993a, type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,49 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
#if WCE_URP
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace MH.WaterCausticsModules {
|
||||
/*------------------------------------------------------------------------
|
||||
This RendererFeature is used to stably apply WaterCausticsEffect to cameras
|
||||
created by other effects.
|
||||
For example, a mirror or water reflection effect may use a temporary camera
|
||||
that is not placed in the scene, and the effect cannot be applied stably.
|
||||
In that case, register this RendererFeature to the RendererData Asset.
|
||||
The effect will be applied stably to all cameras.
|
||||
|
||||
このRendererFeatureは、他のエフェクトで作成されたカメラへWaterCausticsEffect
|
||||
を安定的に適用するために使用します。
|
||||
鏡や水面の反射エフェクトなどではシーンに配置されない一時的なカメラを使用する
|
||||
場合があり、安定してエフェクトを適用出来ません。その場合はこの RendererFeature
|
||||
を RendererData Asset に登録して下さい。安定してエフェクトが適用されるように
|
||||
なります。
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
[DisallowMultipleRendererFeature ("WaterCausticsEffect (Renderer Feature)")]
|
||||
#elif WCE_URP_10_8
|
||||
[DisallowMultipleRendererFeature]
|
||||
#endif
|
||||
[HelpURL (Constant.URL_MANUAL)]
|
||||
public class WaterCausticsEffectFeature : ScriptableRendererFeature {
|
||||
static private WaterCausticsEffectFeature s_ins;
|
||||
static public event Action<Camera> onCamRender;
|
||||
static public event Action<ScriptableRenderer, Camera> onEnqueue;
|
||||
static private int s_lastFrame;
|
||||
static internal bool effective => (s_ins != null && s_ins.isActive && s_lastFrame >= Time.renderedFrameCount - 1);
|
||||
static internal void OnAddedByScript () => s_lastFrame = Time.renderedFrameCount;
|
||||
public override void Create () { }
|
||||
public override void AddRenderPasses (ScriptableRenderer renderer, ref RenderingData rendData) {
|
||||
s_ins = this;
|
||||
s_lastFrame = Time.renderedFrameCount;
|
||||
var cam = rendData.cameraData.camera;
|
||||
onCamRender?.Invoke (cam);
|
||||
onEnqueue?.Invoke (renderer, cam);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63239fdff9bcf7545bae0204cba6eb96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5408d0311478d0c4984c6debe06c8308
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,522 @@
|
||||
// WaterCausticsModules
|
||||
// Copyright (c) 2021 Masataka Hakozaki
|
||||
|
||||
Shader "Hidden/WaterCausticsModules/Effect" {
|
||||
Properties {
|
||||
// --- Scope
|
||||
_WCE_ClipOutside ("Clip Outside Volume", Int) = 1
|
||||
_WCE_UseImageMask ("Use Image Mask", Int) = 0
|
||||
[NoScaleOffset]_WCE_ImageMaskTex ("Texture", 2D) = "white" { }
|
||||
[Enum(UnityEngine.Rendering.CullMode)] _CullMode ("Cull Mode", Int) = 2
|
||||
// --- Texture
|
||||
[NoScaleOffset]_WCE_CausticsTex ("Caustics Texture", 2D) = "black" { }
|
||||
_WCE_TexChannels ("Channel", Vector) = (0, 1, 2, 0)
|
||||
_WCE_TexRotateSinCos ("Rotation Sin and Cos", Vector) = (0, 1, 0, 0)
|
||||
_WCE_TilingSeed ("Tiling Seed", Int) = -1
|
||||
_WCE_TilingRot ("Tiling Rot", Float) = 0.02
|
||||
_WCE_TilingHard ("Tiling Hard", Float) = 0.85
|
||||
// --- Dimension
|
||||
_WCE_Density ("Density", Float) = 0.2
|
||||
_WCE_SurfaceY ("Water Surface Y", Float) = 2
|
||||
_WCE_SurfFadeCoef ("Surface Fade Coef", Float) = 2
|
||||
_WCE_SurfFadeStart ("Surface Fade Start", Float) = 0
|
||||
_WCE_DepthFadeStart ("Depth Fade Start", Float) = 0
|
||||
_WCE_DepthFadeCoef ("Depth Fade Coef", Float) = 0.01
|
||||
_WCE_DistanceFadeStart ("Distance Fade Start", Float) = 0
|
||||
_WCE_DistanceFadeCoef ("Distance Fade Coef", Float) = 0.01
|
||||
// --- Effect
|
||||
_WCE_IntensityMainLit ("Main Light Intensity", Range(0, 50)) = 1
|
||||
_WCE_IntensityAddLit ("Additional Lights Intensity", Range(0, 50)) = 1
|
||||
[ToggleOff(_RECEIVE_SHADOWS_OFF)] _RECEIVE_SHADOWS_OFF ("Receive Shadow", Float) = 1
|
||||
_WCE_ShadowIntensity ("Shadow Intensity", Range(0, 1)) = 1
|
||||
_WCE_ColorShift ("ColorShift", Vector) = (0.004, -0.001, 0, 0)
|
||||
_WCE_LitSaturation ("Light Saturation", Range(0, 2)) = 0.2
|
||||
_WCE_MultiplyByTex ("Multiply Color", Range(0, 1)) = 1
|
||||
// --- Normal Atten
|
||||
_WCE_NormalAtten ("Normal Atten Intensity", Range(0, 1)) = 1
|
||||
_WCE_NormalAttenRate ("Normal Atten Rate", Range(1, 8)) = 2
|
||||
_WCE_TransparentBack ("Transparent Backside", Range(0, 1)) = 0
|
||||
_WCE_BacksideShadow ("Backside Shadow", Range(0, 1)) = 0
|
||||
// --- Depth Buffer
|
||||
_ZWrite ("ZWrite", Int) = 0
|
||||
[Enum(UnityEngine.Rendering.CompareFunction)] _ZTest ("ZTest", Int) = 4
|
||||
_OffsetFactor ("Offset Factor", float) = 0
|
||||
_OffsetUnits ("Offset Units", float) = 0
|
||||
// --- Stencil Buffer
|
||||
_StencilRef ("Ref [0-255]", Range(0, 255)) = 0
|
||||
_StencilReadMask ("Read Mask [0-255]", Range(0, 255)) = 255
|
||||
_StencilWriteMask ("Write Mask [0-255]", Range(0, 255)) = 255
|
||||
[Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp ("Comp", Int) = 8
|
||||
[Enum(UnityEngine.Rendering.StencilOp)] _StencilPass ("Pass", Int) = 0
|
||||
[Enum(UnityEngine.Rendering.StencilOp)] _StencilFail ("ZFail", Int) = 0
|
||||
[Enum(UnityEngine.Rendering.StencilOp)] _StencilZFail ("ZFail", Int) = 0
|
||||
// --- Blend
|
||||
[Enum(UnityEngine.Rendering.BlendMode)] _BlendSrcFactor ("SrcFactor", Int) = 1
|
||||
[Enum(UnityEngine.Rendering.BlendMode)] _BlendDstFactor ("DstFactor", Int) = 1
|
||||
// ※ Properties は SRPBatcher に必須
|
||||
|
||||
}
|
||||
|
||||
SubShader {
|
||||
LOD 0
|
||||
Tags { "RenderPipeline" = "UniversalPipeline" "RenderType" = "Transparent" "Queue" = "Transparent" "DisableBatching" = "True" "IgnoreProjector" = "True" }
|
||||
|
||||
Pass {
|
||||
Name "WCE_EffectPass"
|
||||
Tags { "LightMode" = "WCE_EffectPass" }
|
||||
|
||||
Blend [_BlendSrcFactor] [_BlendDstFactor]
|
||||
ZWrite [_ZWrite]
|
||||
ZTest [_ZTest]
|
||||
Offset [_OffsetFactor], [_OffsetUnits]
|
||||
Cull [_CullMode]
|
||||
Stencil {
|
||||
Ref [_StencilRef]
|
||||
ReadMask [_StencilReadMask]
|
||||
WriteMask [_StencilWriteMask]
|
||||
Comp [_StencilComp]
|
||||
Pass [_StencilPass]
|
||||
Fail [_StencilFail]
|
||||
ZFail [_StencilZFail]
|
||||
}
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma exclude_renderers d3d11_9x
|
||||
#pragma target 3.5
|
||||
|
||||
#define WCE_EFFECT_SHADER
|
||||
#define REQUIRE_OPAQUE_TEXTURE
|
||||
|
||||
#pragma multi_compile_local _ _WCE_ONE_PASS_NORMAL _WCE_ONE_PASS_DEPTH
|
||||
#pragma multi_compile_local_fragment _ WCE_DEBUG_NORMAL WCE_DEBUG_DEPTH WCE_DEBUG_FACING WCE_DEBUG_CAUSTICS WCE_DEBUG_AREA
|
||||
#if defined(_WCE_ONE_PASS_NORMAL) || defined(_WCE_ONE_PASS_DEPTH)
|
||||
#define REQUIRE_DEPTH_TEXTURE
|
||||
#if defined(_WCE_ONE_PASS_NORMAL)
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareNormalsTexture.hlsl"
|
||||
#endif
|
||||
#else
|
||||
#define WCE_EACH_MESH
|
||||
#endif
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl"
|
||||
#if VERSION_GREATER_EQUAL(11, 0)
|
||||
#pragma multi_compile_fragment _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
|
||||
#else
|
||||
#pragma multi_compile_fragment _ _MAIN_LIGHT_SHADOWS
|
||||
#pragma multi_compile_fragment _ _MAIN_LIGHT_SHADOWS_CASCADE
|
||||
#endif
|
||||
#pragma multi_compile_fragment _ _SHADOWS_SOFT
|
||||
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHTS
|
||||
|
||||
// ---- ※ URP14のDeferredで影が現れない問題応急処置
|
||||
// ※ TODO URP14のバージョンが上がったら修正されたか要確認
|
||||
#if UNITY_VERSION >= 202220 // Unity2022.2.0 URP14.0 以上
|
||||
#if !defined(_RECEIVE_SHADOWS_OFF)
|
||||
#define _ADDITIONAL_LIGHT_SHADOWS
|
||||
#endif
|
||||
#else
|
||||
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
|
||||
#endif
|
||||
// ----
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
|
||||
|
||||
// ---- 使用しない
|
||||
// #pragma multi_compile_fragment _ LIGHTMAP_ON
|
||||
// #pragma multi_compile_fragment _ LIGHTMAP_SHADOW_MIXING
|
||||
// #pragma multi_compile_fragment _ SHADOWS_SHADOWMASK
|
||||
// #pragma multi_compile_fragment _ _MIXED_LIGHTING_SUBTRACTIVE
|
||||
// ----
|
||||
|
||||
#if UNITY_VERSION >= 202120 // Unity2021.2.0 URP12.0 以上
|
||||
#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT
|
||||
#pragma multi_compile_fragment _ _LIGHT_LAYERS
|
||||
#pragma multi_compile_fragment _ _LIGHT_COOKIES
|
||||
#endif
|
||||
#if UNITY_VERSION >= 202220 // Unity2022.2.0 URP14.0 以上
|
||||
#pragma multi_compile_fragment _ _FORWARD_PLUS
|
||||
#endif
|
||||
|
||||
#pragma multi_compile_fog
|
||||
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
|
||||
#define _USE_FOG
|
||||
#endif
|
||||
|
||||
#include "WaterCausticsEffectCommon.hlsl"
|
||||
#pragma multi_compile_local_fragment _ _RECEIVE_SHADOWS_OFF
|
||||
|
||||
struct appdata {
|
||||
float4 vertex : POSITION;
|
||||
#if defined(WCE_EACH_MESH)
|
||||
float3 normal : NORMAL;
|
||||
#else
|
||||
uint vID : SV_VertexID;
|
||||
#endif
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct v2f {
|
||||
float4 posClip : SV_POSITION;
|
||||
float4 posScrn : TEXCOORD0;
|
||||
#if defined(WCE_EACH_MESH)
|
||||
float3 posWld : TEXCOORD1;
|
||||
float3 posEffect : TEXCOORD2;
|
||||
float3 normalWS : TEXCOORD3;
|
||||
#if defined(_USE_FOG)
|
||||
float viewDepth : TEXCOORD4;
|
||||
#endif
|
||||
#endif
|
||||
UNITY_VERTEX_OUTPUT_STEREO
|
||||
};
|
||||
|
||||
CBUFFER_START(UnityPerMaterial)
|
||||
float _WCE_Density;
|
||||
int3 _WCE_TexChannels;
|
||||
float2 _WCE_TexRotateSinCos;
|
||||
int _WCE_TilingSeed;
|
||||
float _WCE_TilingRot;
|
||||
float _WCE_TilingHard;
|
||||
float _WCE_SurfaceY;
|
||||
float _WCE_SurfFadeStart;
|
||||
float _WCE_SurfFadeCoef;
|
||||
float _WCE_DepthFadeStart;
|
||||
float _WCE_DepthFadeCoef;
|
||||
float _WCE_DistanceFadeStart;
|
||||
float _WCE_DistanceFadeCoef;
|
||||
half _WCE_IntensityMainLit;
|
||||
half _WCE_IntensityAddLit;
|
||||
float2 _WCE_ColorShift;
|
||||
half _WCE_LitSaturation;
|
||||
half _WCE_MultiplyByTex;
|
||||
half _WCE_NormalAtten;
|
||||
half _WCE_NormalAttenRate;
|
||||
half _WCE_TransparentBack;
|
||||
half _WCE_BacksideShadow;
|
||||
half _WCE_ShadowIntensity;
|
||||
int _WCE_ClipOutside;
|
||||
int _WCE_UseImageMask;
|
||||
CBUFFER_END
|
||||
|
||||
#if defined(WCE_EACH_MESH)
|
||||
CBUFFER_START(FrequentlyUpdateVariables)
|
||||
float4x4 _WCE_WorldToObjMatrix;
|
||||
CBUFFER_END
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------ Fill Clipped Hole
|
||||
bool WCE_intersectPlaneAndLine(float3 ptA, float3 ptB, float3 planeP, float3 planeN, bool isAllowEndOnPlane, out float3 PT) {
|
||||
float dotPA = dot(ptA - planeP, planeN);
|
||||
float dotPB = dot(ptB - planeP, planeN);
|
||||
bool isCross = (sign(dotPA) != sign(dotPB));
|
||||
bool isPtOnPlane = (dotPA == 0 || dotPB == 0);
|
||||
[branch] if (isCross && (isAllowEndOnPlane || !isPtOnPlane)) {
|
||||
float3 AB = ptB - ptA;
|
||||
float dif = abs(dotPA) + abs(dotPB);
|
||||
float rate = abs(dotPA) / dif;
|
||||
PT = ptA + AB * rate;
|
||||
return true;
|
||||
} else {
|
||||
PT = float3(0, 0, 0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float3 WCE_camDirWS() {
|
||||
return -UNITY_MATRIX_V[2].xyz;
|
||||
}
|
||||
|
||||
float3 WCE_viewDirWS(float3 posWS) {
|
||||
return (unity_OrthoParams.w == 0) ? normalize(posWS - _WorldSpaceCameraPos) : WCE_camDirWS();
|
||||
}
|
||||
float3 WCE_viewDirRawWS(float3 posWS) {
|
||||
return (unity_OrthoParams.w == 0) ? posWS - _WorldSpaceCameraPos : WCE_camDirWS();
|
||||
}
|
||||
|
||||
float4 WCE_fillClippedHole(uint vID) {
|
||||
const float3 pts[8] = {
|
||||
float3(-0.5, -0.5, -0.5), float3(0.5, -0.5, -0.5), float3(-0.5, 0.5, -0.5), float3(0.5, 0.5, -0.5),
|
||||
float3(-0.5, -0.5, 0.5), float3(0.5, -0.5, 0.5), float3(-0.5, 0.5, 0.5), float3(0.5, 0.5, 0.5),
|
||||
};
|
||||
const uint2 idxs [12] = {
|
||||
uint2(0, 4), uint2(1, 5), uint2(2, 6), uint2(3, 7), uint2(0, 2), uint2(1, 3), uint2(4, 6), uint2(5, 7), uint2(0, 1), uint2(4, 5), uint2(2, 3), uint2(6, 7),
|
||||
};
|
||||
// ObliqueMatrix対応のためClipSpaceの端点からNearClipPlaneを得る
|
||||
float near = UNITY_NEAR_CLIP_VALUE; // ← D3D11/Metal/Vulkan/Switch:1, GLCore/GLES:-1
|
||||
float3 p0 = ComputeWorldSpacePosition(float4(0, 0, near, 1), UNITY_MATRIX_I_VP);
|
||||
float3 p1 = ComputeWorldSpacePosition(float4(1, 0, near, 1), UNITY_MATRIX_I_VP);
|
||||
float3 p2 = ComputeWorldSpacePosition(float4(0, 1, near, 1), UNITY_MATRIX_I_VP);
|
||||
float3 planeN_WS = cross(p1 - p0, p2 - p0);
|
||||
planeN_WS *= sign(dot(planeN_WS, -WCE_camDirWS()));
|
||||
|
||||
float3 planeN = TransformWorldToObjectNormal(planeN_WS, true);
|
||||
float3 planeP = TransformWorldToObject(p0);
|
||||
float3 rightV = TransformWorldToObjectDir(p1 - p0, true);
|
||||
|
||||
uint cnt = 0u;
|
||||
float3 center = float3(0, 0, 0);
|
||||
float4 intersectPts[6];
|
||||
[unroll(12)] for (uint i = 0u; i < 12u; i++) {
|
||||
float3 ptA = pts [idxs [i].x];
|
||||
float3 ptB = pts [idxs [i].y];
|
||||
float3 PT;
|
||||
bool isIntersect = WCE_intersectPlaneAndLine(ptA, ptB, planeP, planeN, (i < 4), PT);
|
||||
[branch] if (isIntersect) {
|
||||
intersectPts [cnt].xyz = PT;
|
||||
center += PT;
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
center /= cnt;
|
||||
|
||||
float3 outputPt = center;
|
||||
[branch] if (cnt >= 3u && vID <= cnt) {
|
||||
[unroll(6)] for (uint k = 0u; k < cnt; k++) {
|
||||
// 時計回りにwを設定 -2~+2
|
||||
float3 v = normalize(intersectPts [k].xyz - center);
|
||||
intersectPts [k].w = - (dot(v, rightV) - 1.0) * sign(dot(cross(v, rightV), planeN));
|
||||
}
|
||||
// ソート
|
||||
[unroll(5)] for (uint m = 0u; m < cnt - 1u; m++) {
|
||||
[unroll(5)] for (uint o = m + 1u; o < cnt; o++) {
|
||||
[branch] if (intersectPts[m].w < intersectPts[o].w) {
|
||||
float4 swap = intersectPts[m];
|
||||
intersectPts[m] = intersectPts[o];
|
||||
intersectPts[o] = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
outputPt = intersectPts[vID % cnt].xyz;
|
||||
}
|
||||
float4 posClip = TransformObjectToHClip(outputPt);
|
||||
posClip.z = UNITY_NEAR_CLIP_VALUE * posClip.w;
|
||||
return posClip;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------ Vertex Shader
|
||||
v2f vert(appdata v) {
|
||||
v2f o = (v2f)0;
|
||||
UNITY_SETUP_INSTANCE_ID(v);
|
||||
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
||||
#if defined(WCE_EACH_MESH)
|
||||
// [Each Mesh]
|
||||
float4 posClip = TransformObjectToHClip(v.vertex.xyz);
|
||||
float3 posWld = TransformObjectToWorld(v.vertex.xyz);
|
||||
float4 posScrn = ComputeScreenPos(posClip);
|
||||
o.posClip = posClip;
|
||||
o.posWld = posWld;
|
||||
o.posScrn = posScrn;
|
||||
o.posEffect = mul(_WCE_WorldToObjMatrix, float4(posWld, 1)).xyz;
|
||||
o.normalWS = TransformObjectToWorldNormal(v.normal, true);
|
||||
#if defined(_USE_FOG)
|
||||
o.viewDepth = -TransformWorldToView(posWld).z;
|
||||
#endif
|
||||
#else
|
||||
// [At Once]
|
||||
float4 posClip;
|
||||
[branch]if (v.vID < 8u) {
|
||||
posClip = TransformObjectToHClip(v.vertex.xyz);
|
||||
} else {
|
||||
posClip = WCE_fillClippedHole(v.vID - 8u);
|
||||
}
|
||||
float4 posScrn = ComputeScreenPos(posClip);
|
||||
o.posClip = posClip;
|
||||
o.posScrn = posScrn;
|
||||
#endif
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------ Reconstruct World Pos and Normal
|
||||
float WCE_fixReversedZ(float Depth) {
|
||||
#if UNITY_REVERSED_Z
|
||||
return 1 - Depth;
|
||||
#else
|
||||
return Depth;
|
||||
#endif
|
||||
}
|
||||
|
||||
float3 WCE_reconstructPosWS(float2 screenUV, float rawDepth) {
|
||||
#if !UNITY_REVERSED_Z
|
||||
rawDepth = lerp(UNITY_NEAR_CLIP_VALUE, 1, rawDepth);
|
||||
#endif
|
||||
return ComputeWorldSpacePosition(screenUV, rawDepth, UNITY_MATRIX_I_VP);
|
||||
}
|
||||
|
||||
bool WCE_checkOutside(float3 posES) {
|
||||
return (abs(posES.x) > 0.5 || abs(posES.y) > 0.5 || abs(posES.z) > 0.5);
|
||||
}
|
||||
|
||||
#if !defined(WCE_EACH_MESH)
|
||||
#define RECONSTRUCT_NORMAL_HQ 1
|
||||
half3 WCE_reconstructNormalWS(float2 screenUV, float3 posWS, float rdC) {
|
||||
#if (!RECONSTRUCT_NORMAL_HQ)
|
||||
return normalize(cross(ddy(posWS), ddx(posWS)));
|
||||
#else
|
||||
float2 offsetU = float2(_ScreenParams.z - 1, 0);
|
||||
float2 offsetV = float2(0, _ScreenParams.w - 1);
|
||||
float2 uvN = screenUV + offsetV;
|
||||
float2 uvS = screenUV - offsetV;
|
||||
float2 uvE = screenUV + offsetU;
|
||||
float2 uvW = screenUV - offsetU;
|
||||
float rdN = SampleSceneDepth(uvN);
|
||||
float rdS = SampleSceneDepth(uvS);
|
||||
float rdE = SampleSceneDepth(uvE);
|
||||
float rdW = SampleSceneDepth(uvW);
|
||||
float3 vV = abs(rdN - rdC) < abs(rdS - rdC) ? WCE_reconstructPosWS(uvN, rdN) - posWS : posWS - WCE_reconstructPosWS(uvS, rdS);
|
||||
float3 vU = abs(rdE - rdC) < abs(rdW - rdC) ? WCE_reconstructPosWS(uvE, rdE) - posWS : posWS - WCE_reconstructPosWS(uvW, rdW);
|
||||
return normalize(cross(vV, vU));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
half3 WCE_getNormal(v2f IN, float2 screenUV, float3 posWS, float rawDepth) {
|
||||
#if defined(WCE_EACH_MESH)
|
||||
float3 normal = IN.normalWS; // VFACEセマンティクスでの向きの取得はメッシュのデータに不具合があると正しくないことがあるので廃止
|
||||
normal *= -sign(dot(normal, WCE_viewDirRawWS(posWS)));
|
||||
return normal;
|
||||
#elif defined(_WCE_ONE_PASS_NORMAL)
|
||||
float3 normal = SampleSceneNormals(screenUV);
|
||||
#if VERSION_LOWER(10, 9) || (VERSION_GREATER_EQUAL(11, 0) && VERSION_LOWER(12, 0))
|
||||
// ViewSpaceで保存されているURPのバージョン対応
|
||||
normal.z *= -1;
|
||||
normal = mul((float3x3)UNITY_MATRIX_I_V, normal).xyz;
|
||||
normal = normalize(normal);
|
||||
#endif
|
||||
// normal *= -sign(dot(normal, WCE_viewDirWS(posWS))+0.07 );
|
||||
normal *= -sign(dot(normal, WCE_viewDirRawWS(posWS)));
|
||||
return normal;
|
||||
#else
|
||||
return WCE_reconstructNormalWS(screenUV, posWS, rawDepth);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------ Fog (Oblique Projection Supported)
|
||||
#if defined(_USE_FOG)
|
||||
float WCE_computeFogFactorZ0ToFar(float z) {
|
||||
#if defined(FOG_LINEAR)
|
||||
return saturate(z * unity_FogParams.z + unity_FogParams.w);
|
||||
#elif defined(FOG_EXP) || defined(FOG_EXP2)
|
||||
return unity_FogParams.x * z;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
float WCE_calcFog(float viewDepth) {
|
||||
float nearToFarZ = max(viewDepth - _ProjectionParams.y, 0);
|
||||
return ComputeFogIntensity(WCE_computeFogFactorZ0ToFar(nearToFarZ));
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
#if defined(WCE_EACH_MESH)
|
||||
// [Each Mesh]
|
||||
#define WCE_clipOutside (_WCE_ClipOutside == 1)
|
||||
#else
|
||||
// [At Once]
|
||||
#define WCE_clipOutside true
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------ Fragment
|
||||
#define CLR_COL half4(0, 0, 0, 0)
|
||||
|
||||
TEXTURE2D(_WCE_CausticsTex);
|
||||
TEXTURE2D(_WCE_ImageMaskTex);
|
||||
SAMPLER(sampler_WCE_CausticsTex);
|
||||
SAMPLER(sampler_WCE_ImageMaskTex);
|
||||
|
||||
half4 frag(v2f IN) : SV_Target {
|
||||
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
|
||||
|
||||
// ---------- WorldPos
|
||||
float2 screenUV = IN.posScrn.xy / IN.posScrn.w;
|
||||
#if defined(WCE_EACH_MESH)
|
||||
// [Each Mesh]
|
||||
float3 posWS = IN.posWld;
|
||||
float3 posES = IN.posEffect;
|
||||
float rawDepth = 0.5;
|
||||
#else
|
||||
// [At Once]
|
||||
float rawDepth = SampleSceneDepth(screenUV);
|
||||
float3 posWS = WCE_reconstructPosWS(screenUV, rawDepth);
|
||||
float3 posES = TransformWorldToObject(posWS);
|
||||
#endif
|
||||
|
||||
// ---------- Debug Info
|
||||
#if defined(WCE_DEBUG_NORMAL) || defined(WCE_DEBUG_DEPTH) || defined(WCE_DEBUG_FACING) || defined(WCE_DEBUG_CAUSTICS) || defined(WCE_DEBUG_AREA)
|
||||
if ((WCE_clipOutside && WCE_checkOutside(posES)) || rawDepth == UNITY_RAW_FAR_CLIP_VALUE) discard;
|
||||
#endif
|
||||
#if defined(WCE_DEBUG_NORMAL)
|
||||
return half4(pow(saturate(WCE_getNormal(IN, screenUV, posWS, rawDepth) * 0.5 + 0.5), 4) * 0.9, 1);
|
||||
#elif defined(WCE_DEBUG_DEPTH)
|
||||
float debugDepth = -TransformWorldToView(posWS).z * _ProjectionParams.w;
|
||||
return half4(pow(abs(debugDepth), 0.7).xxx, 1);
|
||||
#elif defined(WCE_DEBUG_FACING)
|
||||
float3 n = WCE_getNormal(IN, screenUV, posWS, rawDepth);
|
||||
float b = dot(-n, WCE_viewDirWS(posWS));
|
||||
return half4((saturate(pow(abs(b), 2) * 0.5)).xxx, 1);
|
||||
#elif defined(WCE_DEBUG_CAUSTICS)
|
||||
_WCE_MultiplyByTex = 0;
|
||||
#elif defined(WCE_DEBUG_AREA)
|
||||
_WCE_MultiplyByTex = 0;
|
||||
#endif
|
||||
|
||||
// ---------- Clip Outside
|
||||
[branch] if ((WCE_clipOutside && WCE_checkOutside(posES)) || rawDepth == UNITY_RAW_FAR_CLIP_VALUE) return CLR_COL;
|
||||
|
||||
// ---------- Atten Start
|
||||
float atten = 1; // halfだとVRシングルパスで不安定?
|
||||
const float ATTEN_TH = 0.001;
|
||||
|
||||
// ---------- Fog
|
||||
#if defined(_USE_FOG)
|
||||
#if defined(WCE_EACH_MESH)
|
||||
float viewDepth = IN.viewDepth;
|
||||
#else
|
||||
float viewDepth = -TransformWorldToView(posWS).z;
|
||||
#endif
|
||||
atten *= WCE_calcFog(viewDepth);
|
||||
#endif
|
||||
|
||||
// ---------- Distance Fade
|
||||
float3 viewDir = posWS - _WorldSpaceCameraPos; // ←ifに入れるとVR SinglePassでエラー
|
||||
[branch] if (atten > ATTEN_TH && _WCE_DistanceFadeCoef > 0.0001f) {
|
||||
atten *= smoothstep(0, 1, 1 - (length(viewDir) - _WCE_DistanceFadeStart) * _WCE_DistanceFadeCoef);
|
||||
}
|
||||
|
||||
// ---------- Image Mask
|
||||
[branch] if (atten > ATTEN_TH && _WCE_UseImageMask != 0) {
|
||||
atten *= _WCE_ImageMaskTex.Sample(sampler_WCE_ImageMaskTex, posES.xz + 0.5).r;
|
||||
}
|
||||
|
||||
// ---------- Atten End
|
||||
[branch] if (atten <= ATTEN_TH) return CLR_COL;
|
||||
_WCE_IntensityMainLit *= atten;
|
||||
_WCE_IntensityAddLit *= atten;
|
||||
|
||||
// ---------- Normal
|
||||
half3 normalWS = WCE_getNormal(IN, screenUV, posWS, rawDepth);
|
||||
|
||||
// ---------- Caustics
|
||||
half3 c = WCE_EffectCore(posWS, normalWS, screenUV, _WCE_CausticsTex, sampler_WCE_CausticsTex, _WCE_TexRotateSinCos, _WCE_TexChannels, _WCE_TilingSeed, _WCE_TilingRot, _WCE_TilingHard, _WCE_Density, _WCE_SurfaceY, _WCE_SurfFadeStart, _WCE_SurfFadeCoef, _WCE_DepthFadeStart, _WCE_DepthFadeCoef, _WCE_IntensityMainLit, _WCE_IntensityAddLit, _WCE_ShadowIntensity, _WCE_ColorShift, _WCE_LitSaturation, _WCE_NormalAtten, _WCE_NormalAttenRate, _WCE_TransparentBack, _WCE_BacksideShadow);
|
||||
|
||||
// ---------- Multiply Opaque Tex
|
||||
[branch] if (_WCE_MultiplyByTex > 0) {
|
||||
c *= 1 - (1 - SHADERGRAPH_SAMPLE_SCENE_COLOR(screenUV)) * _WCE_MultiplyByTex;
|
||||
}
|
||||
return half4(c, 1);
|
||||
}
|
||||
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
|
||||
Fallback "Hidden/InternalErrorShader"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user