Boat Attack使用了Universal RP的许多新图形功能,可以用于探索 Universal RP 的使用方式和技巧。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

361 行
17 KiB

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
namespace WaterSystem.Data
{
[CustomEditor(typeof(WaterSurfaceData))]
public class WaterSurfaceDataEditor : Editor
{
[SerializeField]
ReorderableList waveList;
private void OnValidate()
{
var init = serializedObject.FindProperty("_init");
if(init?.boolValue == false)
Setup();
var standardHeight = EditorGUIUtility.singleLineHeight;
var standardLine = standardHeight + EditorGUIUtility.standardVerticalSpacing;
//Reorderable list stuff////////////////////////////////////////////////
waveList = new ReorderableList(serializedObject, serializedObject.FindProperty("_waves"), true, true, true, true);
//Single entry GUI
waveList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
var element = waveList.serializedProperty.GetArrayElementAtIndex(index);
rect.y += 2;
// Swell height
var preWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = rect.width * 0.2f;
Rect ampRect = new Rect(rect.x, rect.y + standardLine, rect.width * 0.5f, standardHeight);
var waveAmp = element.FindPropertyRelative("amplitude");
waveAmp.floatValue = EditorGUI.Slider(ampRect, "Swell Height", waveAmp.floatValue, 0.1f, 30f);
// Wavelength
Rect lengthRect = new Rect(rect.x + ampRect.width, rect.y + standardLine, rect.width * 0.5f, standardHeight);
var waveLen = element.FindPropertyRelative("wavelength");
waveLen.floatValue = EditorGUI.Slider(lengthRect, "Wavelength", waveLen.floatValue, 1.0f, 200f);
EditorGUIUtility.labelWidth = preWidth;
// Directional controls
Rect dirToggleRect = new Rect(rect.x, rect.y + 2 + standardLine * 2, rect.width * 0.5f, standardHeight);
Rect omniToggleRect = new Rect(rect.x + rect.width * 0.5f, dirToggleRect.y, rect.width * 0.5f, standardHeight);
Rect containerRect = new Rect(rect.x, dirToggleRect.y + 1, rect.width, standardLine * 3.2f);
// Direction/origin
var waveType = element.FindPropertyRelative("onmiDir");
var wTypeBool = (int)waveType.floatValue == 1 ? true : false;
GUI.Box(containerRect, "", EditorStyles.helpBox );
wTypeBool = !GUI.Toggle(dirToggleRect, !wTypeBool, "Directional", EditorStyles.miniButtonLeft);
wTypeBool = GUI.Toggle(omniToggleRect, wTypeBool, "Omni-directional", EditorStyles.miniButtonRight);
waveType.floatValue = wTypeBool ? 1 : 0;
Rect dirRect = new Rect(rect.x + 4, dirToggleRect.y + standardLine, rect.width - 8, standardHeight);
Rect buttonRect = new Rect(rect.x + 4, dirRect.y + standardLine + 2, rect.width - 8, standardHeight);
// Directional
if(!wTypeBool)
{
var waveDir = element.FindPropertyRelative("direction");
waveDir.floatValue = EditorGUI.Slider(dirRect, "Facing Direction", waveDir.floatValue, -180.0f, 180.0f);
if(GUI.Button(buttonRect, "Align with Scene Camera"))
waveDir.floatValue = CameraRelativeDirection();
}
else
{// Omni-Directional
EditorGUIUtility.wideMode = true;
//var perWidth = EditorGUIUtility.labelWidth;
//EditorGUIUtility.labelWidth = 20f;
var waveOrig = element.FindPropertyRelative("origin");
waveOrig.vector2Value = EditorGUI.Vector2Field(dirRect, "Point of Origin", waveOrig.vector2Value);
if(GUI.Button(buttonRect, "Project Origin from Scene Camera"))
waveOrig.vector2Value = CameraRelativeOrigin(waveOrig.vector2Value);
//EditorGUIUtility.labelWidth = perWidth;
}
};
// Check can remove to make sure at least one wave remains
waveList.onCanRemoveCallback = (ReorderableList l) =>
{
return l.count > 1;
};
// Check on remove to give a warning incase removing by accident
waveList.onRemoveCallback = (ReorderableList l) =>
{
if (EditorUtility.DisplayDialog("Warning!", "Are you sure you want to delete the wave?", "Yes", "No"))
{
ReorderableList.defaultBehaviours.DoRemoveButton(l);
}
};
// When adding, check if under 10, if so add a new random wave
waveList.onAddCallback = (ReorderableList l) =>
{
var index = l.serializedProperty.arraySize;
if (index < 10)
{
l.serializedProperty.arraySize++;
l.index = index;
var element = l.serializedProperty.GetArrayElementAtIndex(index);
element.FindPropertyRelative("amplitude").floatValue = Random.Range(0.25f, 1.5f);
element.FindPropertyRelative("direction").floatValue = Random.Range(-180f, 180f);
element.FindPropertyRelative("wavelength").floatValue = Random.Range(2f, 8f);
}
else
{
EditorUtility.DisplayDialog("Warning!", "You have reached the limit of 10 waves for this Water.", "Close");
}
};
//Draw header
waveList.drawHeaderCallback = (Rect rect) =>
{
EditorGUI.LabelField(rect, "Wave List");
};
//Do height of list entry
waveList.elementHeightCallback = (index) =>
{
var elementHeight = standardLine * 6f;
return elementHeight;
};
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.LabelField("Visual Settings", EditorStyles.boldLabel);
EditorGUI.indentLevel += 1;
// Max visibility - slider 3-300
var maxDepth = serializedObject.FindProperty("_waterMaxVisibility");
EditorGUILayout.Slider(maxDepth, 3, 300, new GUIContent("Maximum Visibility", maxDepthTT));
// Colouring settings
DoSmallHeader("Coloring Controls");
// Absorbstion Ramp
var absorpRamp = serializedObject.FindProperty("_absorptionRamp");
EditorGUILayout.PropertyField(absorpRamp, new GUIContent("Absorption Color", absorpRampTT), true, null);
// Scatter Ramp
var scatterRamp = serializedObject.FindProperty("_scatterRamp");
EditorGUILayout.PropertyField(scatterRamp, new GUIContent("Scattering Color", scatterRampTT), true, null);
// Foam Ramps
DoSmallHeader("Surface Foam");
var foamSettings = serializedObject.FindProperty("_foamSettings");
var foamType = foamSettings.FindPropertyRelative("foamType");
foamType.intValue = GUILayout.Toolbar(foamType.intValue, foamTypeOptions);
EditorGUILayout.Space();
switch (foamType.intValue)
{
case 0: //// Auto ////
{
EditorGUILayout.HelpBox("Automatic will distribute the foam suitable for an average swell", MessageType.Info);
}
break;
case 1: //// Simple ////
{
EditorGUILayout.BeginHorizontal();
DoInlineLabel("Foam Profile", foamCurveTT, 50f);
var basicFoam = foamSettings.FindPropertyRelative("basicFoam");
basicFoam.animationCurveValue = EditorGUILayout.CurveField(basicFoam.animationCurveValue, Color.white, new Rect(Vector2.zero, Vector2.one));
EditorGUILayout.EndHorizontal();
}
break;
case 2: //// Simple ////
{
EditorGUILayout.BeginHorizontal();
DoInlineLabel("Foam Profiles", foam3curvesTT, 50f);
var liteFoam = foamSettings.FindPropertyRelative("liteFoam");
liteFoam.animationCurveValue = EditorGUILayout.CurveField(liteFoam.animationCurveValue, new Color(0.5f, 0.75f, 1f, 1f), new Rect(Vector2.zero, Vector2.one));
var mediumFoam = foamSettings.FindPropertyRelative("mediumFoam");
mediumFoam.animationCurveValue = EditorGUILayout.CurveField(mediumFoam.animationCurveValue, new Color(0f, 0.5f, 1f, 1f), new Rect(Vector2.zero, Vector2.one));
var denseFoam = foamSettings.FindPropertyRelative("denseFoam");
denseFoam.animationCurveValue = EditorGUILayout.CurveField(denseFoam.animationCurveValue, Color.blue, new Rect(Vector2.zero, Vector2.one));
EditorGUILayout.EndHorizontal();
}
break;
}
EditorGUI.indentLevel -= 1;
EditorGUILayout.LabelField("Wave Settings", EditorStyles.boldLabel);
EditorGUI.indentLevel += 1;
// Wave type - Automatic / Customized
//wavesType = EditorGUILayout.Popup("System Type", wavesType, wavesTypeOptions);
// Toolbar labels here
var customWaves = serializedObject.FindProperty("_customWaves");
var intVal = customWaves.boolValue ? 1 : 0;
intVal = GUILayout.Toolbar(intVal, wavesTypeOptions);
customWaves.boolValue = intVal == 1 ? true : false;
EditorGUILayout.Space();
switch(customWaves.boolValue ? 1 : 0)
{
case 0: //// Automatic ////
{
var basicSettings = serializedObject.FindProperty("_basicWaveSettings");
// Wave count (display warning of on mobile platform and over 6) dropdown 1 > 10
var autoCount = basicSettings.FindPropertyRelative("numWaves");
EditorGUILayout.IntSlider(autoCount, 1, 10, new GUIContent("Wave Count", waveCountTT), null);
// Average Wave height - slider 0.05 - 30
var avgHeight = basicSettings.FindPropertyRelative("amplitude");
EditorGUILayout.Slider(avgHeight, 0.1f, 30.0f, new GUIContent("Avg Swell Height", avgHeightTT), null);
// Average Wavelength - slider 1 - 200
var avgWavelength = basicSettings.FindPropertyRelative("wavelength");
EditorGUILayout.Slider(avgWavelength, 1.0f, 200.0f, new GUIContent("Avg Wavelength", avgWavelengthTT), null);
// Wind direction - slider -180-180
EditorGUILayout.BeginHorizontal();
var windDir = basicSettings.FindPropertyRelative("direction");
EditorGUILayout.Slider(windDir, -180.0f, 180.0f, new GUIContent("Wind Direction", windDirTT), null);
if(GUILayout.Button(new GUIContent("Align to scene camera", alignButtonTT)))
windDir.floatValue = CameraRelativeDirection();
EditorGUILayout.EndHorizontal();
// [override] - random otherwise(on creation/override check)
// Random seed - int input
EditorGUILayout.BeginHorizontal();
var randSeed = serializedObject.FindProperty("randomSeed");
randSeed.intValue = EditorGUILayout.IntField(new GUIContent("Random Seed", randSeedTT), randSeed.intValue);
if (GUILayout.Button("Randomize Waves"))
{
randSeed.intValue = System.DateTime.Now.Millisecond * 100 - System.DateTime.Now.Millisecond;
}
EditorGUILayout.EndHorizontal();
}
break;
case 1: //// Customized ////
{
EditorGUI.indentLevel -= 1;
// Re-orderable list with wave details
waveList.DoLayoutList();
/// Type - Directional / Omi-directional
//// Amplitude - slider 0.05 - 30
//// Wavelength - slider 1 - 200
////// Direction(facing) - slider -180-180 && face scene camera direction(if scene view)
// OR
////// Origin(point of origin) - Vector input && origin at camera aim
}
break;
}
EditorUtility.SetDirty(this);
serializedObject.ApplyModifiedProperties();
}
void DoSmallHeader(string header)
{
EditorGUI.indentLevel -= 1;
EditorGUILayout.LabelField(header, EditorStyles.miniBoldLabel);
EditorGUI.indentLevel += 1;
}
void DoInlineLabel(string label, string tooltip, float width)
{
var preWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = width;
EditorGUILayout.LabelField(new GUIContent(label, tooltip));
EditorGUIUtility.labelWidth = preWidth;
}
void Setup()
{
WaterSurfaceData wsd = (WaterSurfaceData)target;
wsd._init = true;
wsd._absorptionRamp = DefaultAbsorptionGrad();
wsd._scatterRamp = DefaultScatterGrad();
EditorUtility.SetDirty(wsd);
}
Gradient DefaultAbsorptionGrad() // Preset for absorption
{
Gradient g = new Gradient();
GradientColorKey[] gck = new GradientColorKey[5];
GradientAlphaKey[] gak = new GradientAlphaKey[1];
gak[0].alpha = 1;
gak[0].time = 0;
gck[0].color = Color.white;
gck[0].time = 0f;
gck[1].color = new Color(0.22f, 0.87f, 0.87f);
gck[1].time = 0.082f;
gck[2].color = new Color(0f, 0.47f, 0.49f);
gck[2].time = 0.318f;
gck[3].color = new Color(0f, 0.275f, 0.44f);
gck[3].time = 0.665f;
gck[4].color = Color.black;
gck[4].time = 1f;
g.SetKeys(gck, gak);
return g;
}
Gradient DefaultScatterGrad() // Preset for scattering
{
Gradient g = new Gradient();
GradientColorKey[] gck = new GradientColorKey[4];
GradientAlphaKey[] gak = new GradientAlphaKey[1];
gak[0].alpha = 1;
gak[0].time = 0;
gck[0].color = Color.black;
gck[0].time = 0f;
gck[1].color = new Color(0.08f, 0.41f, 0.34f);
gck[1].time = 0.15f;
gck[2].color = new Color(0.13f, 0.55f, 0.45f);
gck[2].time = 0.42f;
gck[3].color = new Color(0.21f, 0.62f, 0.6f);
gck[3].time = 1f;
g.SetKeys(gck, gak);
return g;
}
float CameraRelativeDirection()
{
float degrees = 0;
Vector3 camFwd = UnityEditor.SceneView.lastActiveSceneView.camera.transform.forward;
camFwd.y = 0f;
camFwd.Normalize();
float dot = Vector3.Dot(-Vector3.forward, camFwd);
degrees = Mathf.LerpUnclamped(90.0f, 180.0f, dot);
if(camFwd.x < 0)
degrees *= -1f;
return Mathf.RoundToInt(degrees * 1000) / 1000;
}
Vector2 CameraRelativeOrigin(Vector2 original)
{
Camera sceneCam = UnityEditor.SceneView.lastActiveSceneView.camera;
float angle = 90f - Vector3.Angle(sceneCam.transform.forward, Vector3.down);
if (angle > 0.1f)
{
Vector3 intersect = Vector2.zero;
float hypot = (sceneCam.transform.position.y) * (1 / Mathf.Sin(Mathf.Deg2Rad * angle));
Vector3 fwd = sceneCam.transform.forward * hypot;
intersect = fwd + sceneCam.transform.position;
return new Vector2(intersect.x, intersect.z);
}
else
{
return original;
}
}
static string[] wavesTypeOptions = new string[] { "Automatic", "Customized" };
static string[] foamTypeOptions = new string[3] { "Automatic", "Simple Curve", "Density Curves" };
////TOOLTIPS////
private string maxDepthTT = "This controls the max depth of the waters transparency/visiblility, the absorption and scattering gradients map to this depth. Units:Meters";
private string absorpRampTT = "This gradient controls the color of the water as it gets deeper, darkening the surfaces under the water as they get deeper.";
private string scatterRampTT = "This gradient controls the 'scattering' of the water from shallow to deep, lighting the water as there becomes more of it.";
private string waveCountTT = "Number of waves the automatic setup creates, if aiming for mobile set to 6 or less";
private string avgHeightTT = "The average height of the waves. Units:Meters";
private string avgWavelengthTT = "The average wavelength of the waves. Units:Meters";
private string windDirTT = "The general wind direction, this is in degrees from Z+";
private string alignButtonTT = "This aligns the wave direction to the current scene view camera facing direction";
private string foamCurveTT = "This curve control the foam propagation. X is wave height and Y is foam opacity";
private string foam3curvesTT = "These three curves control the Lite, Medium and Dense foam propagation. X is wave height and Y is foam opacity";
private string randSeedTT = "This seed controls the automatic wave generation";
}
}