540 lines
26 KiB
C#
540 lines
26 KiB
C#
|
using UnityEngine;
|
||
|
using UnityEngine.TerrainTools;
|
||
|
using UnityEditor.ShortcutManagement;
|
||
|
using UnityEngine.Experimental.Rendering;
|
||
|
|
||
|
namespace UnityEditor.TerrainTools
|
||
|
{
|
||
|
//[FilePathAttribute("Library/TerrainTools/Stamp", FilePathAttribute.Location.ProjectFolder)]
|
||
|
internal class StampTool : TerrainPaintTool<StampTool>
|
||
|
{
|
||
|
#if UNITY_2019_1_OR_NEWER
|
||
|
[Shortcut("Terrain/Select Stamp Tool", typeof(TerrainToolShortcutContext))]
|
||
|
static void SelectShortcut(ShortcutArguments args)
|
||
|
{
|
||
|
TerrainToolShortcutContext context = (TerrainToolShortcutContext)args.context;
|
||
|
context.SelectPaintTool<StampTool>();
|
||
|
TerrainToolsAnalytics.OnShortcutKeyRelease("Select Stamp Tool");
|
||
|
}
|
||
|
|
||
|
[ClutchShortcut("Terrain/Adjust Mesh Stamp Transform", typeof(TerrainToolShortcutContext), KeyCode.C)]
|
||
|
static void StrengthBrushShortcut(ShortcutArguments args)
|
||
|
{
|
||
|
if (args.stage == ShortcutStage.Begin && s_StampToolProperties.mode == StampToolMode.Mesh)
|
||
|
{
|
||
|
s_EditTransform = true;
|
||
|
}
|
||
|
else if (args.stage == ShortcutStage.End && s_StampToolProperties.mode == StampToolMode.Mesh)
|
||
|
{
|
||
|
s_EditTransform = false;
|
||
|
TerrainToolsAnalytics.OnShortcutKeyRelease("Adjust Mesh Stamp Transform");
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static class Styles
|
||
|
{
|
||
|
public static readonly GUIContent controls = EditorGUIUtility.TrTextContent("Stamp Tool Controls");
|
||
|
public static readonly GUIContent description = EditorGUIUtility.TrTextContent("Left click to stamp the brush onto the terrain.\n\nHold control and mousewheel to adjust height.");
|
||
|
public static readonly GUIContent height = EditorGUIUtility.TrTextContent("Stamp Height", "You can set the Stamp Height manually or you can hold control and mouse wheel on the terrain to adjust it.");
|
||
|
public static readonly GUIContent blendAmount = EditorGUIUtility.TrTextContent("Blend Amount", "Blends between replacing and offsetting the existing heights under the stamp.");
|
||
|
public static readonly GUIContent stampToolBehavior = EditorGUIUtility.TrTextContent("Behavior", "Stamping behavior.");
|
||
|
public static readonly GUIContent minBehavior = EditorGUIUtility.TrTextContent("Min", "Stamp where the terrain's height is greater than the input height.");
|
||
|
public static readonly GUIContent maxBehavior = EditorGUIUtility.TrTextContent("Max", "Stamp where the terrain's height is less than the input height.");
|
||
|
public static readonly GUIContent setBehavior = EditorGUIUtility.TrTextContent("Set", "Stamp the terrain setting it's height to the input height");
|
||
|
public static readonly GUIContent stampToolMode = EditorGUIUtility.TrTextContent("Stamp Mode", "Select the mode used to stamp your terrain.");
|
||
|
public static readonly GUIContent brushMode = EditorGUIUtility.TrTextContent("Brush", "Stamp the terrain using a brush.");
|
||
|
public static readonly GUIContent meshMode = EditorGUIUtility.TrTextContent("Mesh", "Stamp the terrain using a mesh.");
|
||
|
public static readonly GUIContent stampHeightContent = EditorGUIUtility.TrTextContent("Height Offset", "The height to stamp the mesh into the terrain at.");
|
||
|
public static readonly GUIContent stampScaleContent = EditorGUIUtility.TrTextContent("Scale", "The scale of the mesh.");
|
||
|
public static readonly GUIContent stampRotationContent = EditorGUIUtility.TrTextContent("Rotation", "The rotation of the mesh.");
|
||
|
public static readonly GUIContent meshContent = EditorGUIUtility.TrTextContent("Mesh", "The mesh to stamp.");
|
||
|
public static readonly GUIContent settings = EditorGUIUtility.TrTextContent("Mesh Stamp Settings");
|
||
|
public static readonly GUIContent transformSettings = EditorGUIUtility.TrTextContent("Transform Settings:");
|
||
|
public static readonly GUIContent resetTransformContent = EditorGUIUtility.TrTextContent("Reset",
|
||
|
"Resets the mesh's rotation, scale, and height to their default state.");
|
||
|
public static readonly string nullMeshString = "Must assign a mesh to use with the Mesh Stamp Tool.";
|
||
|
}
|
||
|
|
||
|
enum StampToolBehavior
|
||
|
{
|
||
|
Min,
|
||
|
Max,
|
||
|
Set,
|
||
|
}
|
||
|
|
||
|
[System.Serializable]
|
||
|
public enum StampToolMode
|
||
|
{
|
||
|
Mesh,
|
||
|
Brush
|
||
|
}
|
||
|
|
||
|
private enum ShaderPasses
|
||
|
{
|
||
|
BrushPreviewFrontFaces = 0,
|
||
|
BrushPreviewBackFaces,
|
||
|
DepthPassFrontFaces,
|
||
|
DepthPassBackFaces,
|
||
|
StampToHeightmap
|
||
|
}
|
||
|
|
||
|
static class RenderTextureIDs
|
||
|
{
|
||
|
public static int cameraView = "cameraView".GetHashCode();
|
||
|
public static int meshStamp = "meshStamp".GetHashCode();
|
||
|
public static int meshStampPreview = "meshStampPreview".GetHashCode();
|
||
|
public static int meshStampMask = "meshStampMask".GetHashCode();
|
||
|
public static int sourceHeight = "sourceHeight".GetHashCode();
|
||
|
public static int combinedHeight = "combinedHeight".GetHashCode();
|
||
|
}
|
||
|
|
||
|
[System.Serializable]
|
||
|
class StampToolSerializedProperties
|
||
|
{
|
||
|
public StampToolBehavior behavior;
|
||
|
public StampToolMode mode;
|
||
|
public float stampHeight;
|
||
|
public float blendAmount;
|
||
|
|
||
|
//Mesh stamp
|
||
|
public Quaternion rotation;
|
||
|
public Vector3 scale;
|
||
|
public string meshAssetGUID;
|
||
|
public bool showToolSettings;
|
||
|
|
||
|
public void SetDefaults()
|
||
|
{
|
||
|
behavior = StampToolBehavior.Set;
|
||
|
mode = StampToolMode.Brush;
|
||
|
stampHeight = 100.0f;
|
||
|
blendAmount = 0.0f;
|
||
|
rotation = Quaternion.identity;
|
||
|
scale = Vector3.one;
|
||
|
meshAssetGUID = null;
|
||
|
showToolSettings = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private Mesh m_ActiveMesh;
|
||
|
public Mesh activeMesh
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (m_ActiveMesh == null && !string.IsNullOrEmpty(s_StampToolProperties.meshAssetGUID))
|
||
|
{
|
||
|
m_ActiveMesh = AssetDatabase.LoadAssetAtPath<Mesh>(AssetDatabase.GUIDToAssetPath(s_StampToolProperties.meshAssetGUID));
|
||
|
}
|
||
|
|
||
|
return m_ActiveMesh;
|
||
|
}
|
||
|
|
||
|
set
|
||
|
{
|
||
|
m_ActiveMesh = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static StampToolSerializedProperties s_StampToolProperties = new StampToolSerializedProperties();
|
||
|
static bool s_PrevEditTransform = false;
|
||
|
static bool s_EditTransform = false;
|
||
|
[System.NonSerialized]
|
||
|
bool m_Initialized = false;
|
||
|
bool m_DebugOrtho = true;
|
||
|
float m_HandleHeightOffsetWS;
|
||
|
RTHandleCollection m_RtCollection;
|
||
|
Vector3 m_BaseHandlePos;
|
||
|
|
||
|
[SerializeField]
|
||
|
IBrushUIGroup m_CommonUI;
|
||
|
private IBrushUIGroup commonUI {
|
||
|
get
|
||
|
{
|
||
|
if (m_CommonUI == null)
|
||
|
{
|
||
|
LoadSettings();
|
||
|
m_CommonUI = new DefaultBrushUIGroup("StampTool", UpdateAnalyticParameters, DefaultBrushUIGroup.Feature.NoSpacing);
|
||
|
m_CommonUI.OnEnterToolMode();
|
||
|
}
|
||
|
|
||
|
return m_CommonUI;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private Material m_Material = null;
|
||
|
private Material GetMaterial()
|
||
|
{
|
||
|
if (m_Material == null)
|
||
|
{
|
||
|
m_Material = new Material(Shader.Find("Hidden/TerrainEngine/PaintHeightTool"));
|
||
|
}
|
||
|
|
||
|
return m_Material;
|
||
|
}
|
||
|
|
||
|
private void Init()
|
||
|
{
|
||
|
if (!m_Initialized)
|
||
|
{
|
||
|
m_RtCollection = new RTHandleCollection();
|
||
|
m_RtCollection.AddRTHandle(RenderTextureIDs.cameraView, "cameraView", GraphicsFormat.R8G8B8A8_UNorm);
|
||
|
m_RtCollection.AddRTHandle(RenderTextureIDs.meshStamp, "meshStamp", GraphicsFormat.R16_SFloat);
|
||
|
m_RtCollection.AddRTHandle(RenderTextureIDs.meshStampPreview, "meshStampPreview", GraphicsFormat.R16_SFloat);
|
||
|
m_RtCollection.AddRTHandle(RenderTextureIDs.meshStampMask, "meshStampMask", GraphicsFormat.R16_UNorm);
|
||
|
m_RtCollection.AddRTHandle(RenderTextureIDs.sourceHeight, "sourceHeight", GraphicsFormat.R16_UNorm);
|
||
|
m_RtCollection.AddRTHandle(RenderTextureIDs.combinedHeight, "combinedHeight", GraphicsFormat.R16_UNorm);
|
||
|
|
||
|
m_Initialized = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Allows overriding for unit testing purposes
|
||
|
/// </summary>
|
||
|
/// <param name="uiGroup"></param>
|
||
|
internal void ChangeCommonUI(IBrushUIGroup uiGroup)
|
||
|
{
|
||
|
m_CommonUI = uiGroup;
|
||
|
}
|
||
|
|
||
|
public override string GetName()
|
||
|
{
|
||
|
return "Stamp Terrain";
|
||
|
}
|
||
|
|
||
|
public override string GetDescription()
|
||
|
{
|
||
|
return "Projects the shape of a 3d mesh or brush mask onto the Terrain.\n\n" +
|
||
|
"Hold Ctrl + Scroll with the mouse wheel to change the Stamp Height.\n" +
|
||
|
"Hold Ctrl + Click to subtract the mesh.\n" +
|
||
|
"Hold C to rotate, scale, or set a height offset of the mesh using an interactive gizmo.";
|
||
|
}
|
||
|
|
||
|
internal void SetStampHeight(float height)
|
||
|
{
|
||
|
s_StampToolProperties.SetDefaults();
|
||
|
s_StampToolProperties.stampHeight = height;
|
||
|
}
|
||
|
|
||
|
private void ApplyBrushInternal(IPaintContextRender renderer, PaintContext paintContext, float brushStrength, Texture brushTexture, BrushTransform brushXform, Terrain terrain)
|
||
|
{
|
||
|
Material mat = GetMaterial();
|
||
|
|
||
|
float HeightUnderCursor = terrain.SampleHeight(commonUI.raycastHitUnderCursor.point) / (terrain.terrainData.size.y * 2.0f);
|
||
|
float height = s_StampToolProperties.stampHeight * brushStrength / (terrain.terrainData.size.y * 2f);
|
||
|
Vector4 brushParams = new Vector4((int) s_StampToolProperties.behavior, HeightUnderCursor, height, s_StampToolProperties.blendAmount);
|
||
|
mat.SetVector("_BrushParams", brushParams);
|
||
|
|
||
|
var brushMask = RTUtils.GetTempHandle(paintContext.sourceRenderTexture.width, paintContext.sourceRenderTexture.height, 0, FilterUtility.defaultFormat);
|
||
|
Utility.GenerateAndSetFilterRT(commonUI, paintContext.sourceRenderTexture, brushMask, mat);
|
||
|
|
||
|
if (s_StampToolProperties.mode == StampToolMode.Mesh)
|
||
|
{
|
||
|
Init();
|
||
|
m_RtCollection.ReleaseRTHandles();
|
||
|
m_RtCollection.GatherRTHandles(paintContext.sourceRenderTexture.width, paintContext.sourceRenderTexture.height, 16);
|
||
|
|
||
|
Graphics.Blit(paintContext.sourceRenderTexture, m_RtCollection[RenderTextureIDs.sourceHeight]);
|
||
|
|
||
|
Matrix4x4 toolMatrix = Matrix4x4.TRS(Vector3.zero, s_StampToolProperties.rotation, s_StampToolProperties.scale);
|
||
|
|
||
|
Bounds modelBounds = activeMesh.bounds;
|
||
|
float maxModelScale = Mathf.Max(Mathf.Max(modelBounds.size.x, modelBounds.size.y), modelBounds.size.z);
|
||
|
float x = .5f;
|
||
|
float y = .5f;
|
||
|
float xy = Mathf.Sqrt(x * x + y * y);
|
||
|
float z = .5f;
|
||
|
float xyz = Mathf.Sqrt(xy * xy + z * z);
|
||
|
maxModelScale *= xyz;
|
||
|
|
||
|
// build the model matrix to transform the mesh with. we want to scale it to fit in the brush bounds and also center it in the brush bounds
|
||
|
Matrix4x4 model = toolMatrix * Matrix4x4.Scale(Vector3.one / maxModelScale) * Matrix4x4.Translate(-modelBounds.center);
|
||
|
|
||
|
// actually render the mesh to texture to be used with the tool shader
|
||
|
MeshUtils.RenderTopdownProjection(activeMesh, model,
|
||
|
m_RtCollection[RenderTextureIDs.meshStamp],
|
||
|
MeshUtils.defaultProjectionMaterial,
|
||
|
MeshUtils.ShaderPass.Height);
|
||
|
// this doesn't actually apply any noise to the destination RT but will color the destination RT based on whether the fragment values are (+) or (-)
|
||
|
NoiseUtils.BlitPreview2D(m_RtCollection[RenderTextureIDs.meshStamp], m_RtCollection[RenderTextureIDs.meshStampPreview]);
|
||
|
Graphics.Blit(paintContext.destinationRenderTexture, m_RtCollection[RenderTextureIDs.combinedHeight]);
|
||
|
mat.SetTexture("_BrushTex", m_RtCollection[RenderTextureIDs.meshStamp]);
|
||
|
|
||
|
// restore old render target
|
||
|
RenderTexture.active = paintContext.oldRenderTexture;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mat.SetTexture("_BrushTex", brushTexture);
|
||
|
}
|
||
|
|
||
|
renderer.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat);
|
||
|
renderer.RenderBrush(paintContext, mat, (int)TerrainBuiltinPaintMaterialPasses.StampHeight);
|
||
|
RTUtils.Release(brushMask);
|
||
|
}
|
||
|
|
||
|
public override void OnEnterToolMode()
|
||
|
{
|
||
|
Init();
|
||
|
base.OnEnterToolMode();
|
||
|
commonUI.OnEnterToolMode();
|
||
|
}
|
||
|
|
||
|
public override void OnExitToolMode()
|
||
|
{
|
||
|
base.OnExitToolMode();
|
||
|
commonUI.OnExitToolMode();
|
||
|
}
|
||
|
|
||
|
public override bool OnPaint(Terrain terrain, IOnPaint editContext)
|
||
|
{
|
||
|
if (s_StampToolProperties.mode == StampToolMode.Mesh && activeMesh == null || s_EditTransform)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
commonUI.OnPaint(terrain, editContext);
|
||
|
|
||
|
// ignore mouse drags
|
||
|
if (commonUI.allowPaint && Event.current == null || Event.current.type != EventType.MouseDrag)
|
||
|
{
|
||
|
Texture brushTexture = editContext.brushTexture;
|
||
|
|
||
|
using (IBrushRenderUnderCursor brushRender = new BrushRenderUIGroupUnderCursor(commonUI, "Stamp", brushTexture))
|
||
|
{
|
||
|
if (brushRender.CalculateBrushTransform(out BrushTransform brushXform))
|
||
|
{
|
||
|
PaintContext paintContext = brushRender.AcquireHeightmap(true, brushXform.GetBrushXYBounds());
|
||
|
|
||
|
ApplyBrushInternal(brushRender, paintContext, commonUI.brushStrength, brushTexture, brushXform, terrain);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public override void OnSceneGUI(Terrain terrain, IOnSceneGUI editContext)
|
||
|
{
|
||
|
Init();
|
||
|
commonUI.OnSceneGUI2D(terrain, editContext);
|
||
|
|
||
|
if (!editContext.hitValidTerrain && !commonUI.isInUse && !s_EditTransform && !m_DebugOrtho)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
commonUI.OnSceneGUI(terrain, editContext);
|
||
|
|
||
|
bool justPressedEditKey = s_EditTransform && !s_PrevEditTransform;
|
||
|
bool justReleaseEditKey = s_PrevEditTransform && !s_EditTransform;
|
||
|
s_PrevEditTransform = s_EditTransform;
|
||
|
|
||
|
if (justPressedEditKey)
|
||
|
{
|
||
|
(commonUI as BaseBrushUIGroup).LockTerrainUnderCursor(true);
|
||
|
m_BaseHandlePos = commonUI.raycastHitUnderCursor.point;
|
||
|
m_HandleHeightOffsetWS = 0;
|
||
|
}
|
||
|
else if (justReleaseEditKey)
|
||
|
{
|
||
|
(commonUI as BaseBrushUIGroup).UnlockTerrainUnderCursor();
|
||
|
m_HandleHeightOffsetWS = 0;
|
||
|
}
|
||
|
|
||
|
// don't render mesh previews, etc. if the mesh field has not been populated yet
|
||
|
if (s_StampToolProperties.mode == StampToolMode.Mesh && activeMesh == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Event evt = Event.current;
|
||
|
if (evt.control && (evt.type == EventType.ScrollWheel))
|
||
|
{
|
||
|
const float k_mouseWheelToHeightRatio = -0.004f;
|
||
|
s_StampToolProperties.stampHeight += Event.current.delta.y * k_mouseWheelToHeightRatio * editContext.raycastHit.distance;
|
||
|
evt.Use();
|
||
|
editContext.Repaint();
|
||
|
SaveSettings();
|
||
|
}
|
||
|
|
||
|
// We're only doing painting operations, early out if it's not a repaint
|
||
|
if (evt.type == EventType.Repaint && commonUI.isRaycastHitUnderCursorValid)
|
||
|
{
|
||
|
Texture brushTexture = editContext.brushTexture;
|
||
|
using (IBrushRenderPreviewUnderCursor brushRender = new BrushRenderPreviewUIGroupUnderCursor(commonUI, "Stamp", brushTexture))
|
||
|
{
|
||
|
if (brushRender.CalculateBrushTransform(out BrushTransform brushXform))
|
||
|
{
|
||
|
PaintContext paintContext = brushRender.AcquireHeightmap(false, brushXform.GetBrushXYBounds(), 1);
|
||
|
Material previewMaterial = Utility.GetDefaultPreviewMaterial(commonUI.hasEnabledFilters);
|
||
|
|
||
|
var texelCtx = Utility.CollectTexelValidity(paintContext.originTerrain, brushXform.GetBrushXYBounds());
|
||
|
Utility.SetupMaterialForPaintingWithTexelValidityContext(paintContext, texelCtx, brushXform, previewMaterial);
|
||
|
var filterRT = RTUtils.GetTempHandle(paintContext.sourceRenderTexture.width,
|
||
|
paintContext.sourceRenderTexture.height, 0, FilterUtility.defaultFormat);
|
||
|
Utility.GenerateAndSetFilterRT(commonUI, paintContext.sourceRenderTexture, filterRT, previewMaterial);
|
||
|
TerrainPaintUtilityEditor.DrawBrushPreview(paintContext, TerrainBrushPreviewMode.SourceRenderTexture,
|
||
|
editContext.brushTexture, brushXform, previewMaterial, 0);
|
||
|
|
||
|
// draw result preview
|
||
|
{
|
||
|
ApplyBrushInternal(brushRender, paintContext, commonUI.brushStrength, brushTexture, brushXform, terrain);
|
||
|
|
||
|
// restore old render target
|
||
|
RenderTexture.active = paintContext.oldRenderTexture;
|
||
|
|
||
|
previewMaterial.SetTexture("_HeightmapOrig", paintContext.sourceRenderTexture);
|
||
|
TerrainPaintUtilityEditor.DrawBrushPreview(paintContext, TerrainBrushPreviewMode.DestinationRenderTexture,
|
||
|
editContext.brushTexture, brushXform, previewMaterial, 1);
|
||
|
}
|
||
|
TerrainPaintUtility.ReleaseContextResources(paintContext);
|
||
|
m_RtCollection.ReleaseRTHandles();
|
||
|
texelCtx.Cleanup();
|
||
|
RTUtils.Release(filterRT);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (s_EditTransform && s_StampToolProperties.mode == StampToolMode.Mesh)
|
||
|
{
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
{
|
||
|
Vector3 prevHandlePosWS = m_BaseHandlePos + Vector3.up * m_HandleHeightOffsetWS;
|
||
|
|
||
|
// draw transform handles
|
||
|
float handleSize = HandleUtility.GetHandleSize(prevHandlePosWS);
|
||
|
Quaternion brushRotation = Quaternion.AngleAxis(commonUI.brushRotation, Vector3.up);
|
||
|
Matrix4x4 brushRotMat = Matrix4x4.Rotate(brushRotation);
|
||
|
Matrix4x4 toolRotMat = Matrix4x4.Rotate(s_StampToolProperties.rotation);
|
||
|
Quaternion handleRot = MeshUtils.QuaternionFromMatrix(brushRotMat * toolRotMat);
|
||
|
Quaternion newRot = Handles.RotationHandle(handleRot, prevHandlePosWS);
|
||
|
s_StampToolProperties.rotation = MeshUtils.QuaternionFromMatrix(brushRotMat.inverse * Matrix4x4.Rotate(newRot));
|
||
|
|
||
|
s_StampToolProperties.scale = Handles.ScaleHandle(s_StampToolProperties.scale, prevHandlePosWS, handleRot, handleSize * 1.5f);
|
||
|
|
||
|
Vector3 currHandlePosWS = Handles.Slider(prevHandlePosWS, Vector3.up, handleSize, Handles.ArrowHandleCap, 1f);
|
||
|
float deltaHeight = (currHandlePosWS.y - prevHandlePosWS.y);
|
||
|
m_HandleHeightOffsetWS += deltaHeight;
|
||
|
s_StampToolProperties.stampHeight += deltaHeight;
|
||
|
}
|
||
|
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
SaveSettings();
|
||
|
editContext.Repaint();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool m_ShowControls = true;
|
||
|
public override void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext)
|
||
|
{
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
commonUI.OnInspectorGUI(terrain, editContext);
|
||
|
|
||
|
m_ShowControls = TerrainToolGUIHelper.DrawHeaderFoldoutForBrush(Styles.controls, m_ShowControls, s_StampToolProperties.SetDefaults);
|
||
|
|
||
|
if (!m_ShowControls)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
EditorGUI.BeginChangeCheck();
|
||
|
{
|
||
|
EditorGUILayout.BeginVertical("GroupBox");
|
||
|
{
|
||
|
// brush coordinate space toolbar
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
{
|
||
|
EditorGUILayout.PrefixLabel(Styles.stampToolMode);
|
||
|
|
||
|
if (GUILayout.Toggle(s_StampToolProperties.mode == StampToolMode.Brush, Styles.brushMode, GUI.skin.button))
|
||
|
{
|
||
|
s_StampToolProperties.mode = StampToolMode.Brush;
|
||
|
}
|
||
|
|
||
|
if (GUILayout.Toggle(s_StampToolProperties.mode == StampToolMode.Mesh, Styles.meshMode, GUI.skin.button))
|
||
|
{
|
||
|
s_StampToolProperties.mode = StampToolMode.Mesh;
|
||
|
}
|
||
|
}
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
EditorGUILayout.PrefixLabel(Styles.stampToolBehavior);
|
||
|
if (GUILayout.Toggle(s_StampToolProperties.behavior == StampToolBehavior.Min, Styles.minBehavior, GUI.skin.button))
|
||
|
{
|
||
|
s_StampToolProperties.behavior = StampToolBehavior.Min;
|
||
|
}
|
||
|
|
||
|
if (GUILayout.Toggle(s_StampToolProperties.behavior == StampToolBehavior.Set, Styles.setBehavior, GUI.skin.button))
|
||
|
{
|
||
|
s_StampToolProperties.behavior = StampToolBehavior.Set;
|
||
|
}
|
||
|
|
||
|
if (GUILayout.Toggle(s_StampToolProperties.behavior == StampToolBehavior.Max, Styles.maxBehavior, GUI.skin.button))
|
||
|
{
|
||
|
s_StampToolProperties.behavior = StampToolBehavior.Max;
|
||
|
}
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
s_StampToolProperties.stampHeight = EditorGUILayout.Slider(Styles.height, s_StampToolProperties.stampHeight, -terrain.terrainData.size.y, terrain.terrainData.size.y);
|
||
|
s_StampToolProperties.blendAmount = EditorGUILayout.Slider(Styles.blendAmount, s_StampToolProperties.blendAmount, 0.0f, 1.0f);
|
||
|
|
||
|
s_StampToolProperties.showToolSettings = TerrainToolGUIHelper.DrawDisableableLabelFoldout(Styles.settings, s_StampToolProperties.showToolSettings, s_StampToolProperties.mode != StampToolMode.Brush);
|
||
|
EditorGUI.BeginDisabledGroup(s_StampToolProperties.mode == StampToolMode.Brush);
|
||
|
{
|
||
|
EditorGUI.indentLevel++;
|
||
|
if (s_StampToolProperties.showToolSettings)
|
||
|
{
|
||
|
if (activeMesh == null)
|
||
|
{
|
||
|
EditorGUILayout.HelpBox(Styles.nullMeshString, MessageType.Warning);
|
||
|
}
|
||
|
|
||
|
activeMesh = EditorGUILayout.ObjectField(Styles.meshContent, activeMesh, typeof(Mesh), false) as Mesh;
|
||
|
s_StampToolProperties.scale = EditorGUILayout.Vector3Field(Styles.stampScaleContent, s_StampToolProperties.scale);
|
||
|
s_StampToolProperties.rotation = Quaternion.Euler(EditorGUILayout.Vector3Field(Styles.stampRotationContent, s_StampToolProperties.rotation.eulerAngles));
|
||
|
}
|
||
|
EditorGUI.indentLevel--;
|
||
|
}
|
||
|
EditorGUI.EndDisabledGroup();
|
||
|
}
|
||
|
EditorGUILayout.EndVertical();
|
||
|
}
|
||
|
|
||
|
if (EditorGUI.EndChangeCheck())
|
||
|
{
|
||
|
SaveSettings();
|
||
|
Save(true);
|
||
|
TerrainToolsAnalytics.OnParameterChange();
|
||
|
}
|
||
|
|
||
|
base.OnInspectorGUI(terrain, editContext);
|
||
|
}
|
||
|
|
||
|
private void SaveSettings()
|
||
|
{
|
||
|
s_StampToolProperties.meshAssetGUID = activeMesh == null ? "" : AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(activeMesh));
|
||
|
string stampToolData = JsonUtility.ToJson(s_StampToolProperties);
|
||
|
EditorPrefs.SetString("Unity.TerrainTools.Stamp", stampToolData);
|
||
|
}
|
||
|
|
||
|
private void LoadSettings()
|
||
|
{
|
||
|
string stampToolData = EditorPrefs.GetString("Unity.TerrainTools.Stamp");
|
||
|
s_StampToolProperties.SetDefaults();
|
||
|
JsonUtility.FromJsonOverwrite(stampToolData, s_StampToolProperties);
|
||
|
}
|
||
|
|
||
|
//Analytics Setup
|
||
|
private TerrainToolsAnalytics.IBrushParameter[] UpdateAnalyticParameters() => new TerrainToolsAnalytics.IBrushParameter[]{
|
||
|
new TerrainToolsAnalytics.BrushParameter<string>{Name = Styles.stampToolBehavior.text, Value = s_StampToolProperties.behavior.ToString()},
|
||
|
new TerrainToolsAnalytics.BrushParameter<float>{Name = Styles.height.text, Value = s_StampToolProperties.stampHeight},
|
||
|
new TerrainToolsAnalytics.BrushParameter<float>{Name = Styles.blendAmount.text, Value = s_StampToolProperties.blendAmount},
|
||
|
new TerrainToolsAnalytics.BrushParameter<Vector3>{Name = Styles.stampScaleContent.text, Value = s_StampToolProperties.scale},
|
||
|
new TerrainToolsAnalytics.BrushParameter<Vector3>{Name = Styles.stampRotationContent.text, Value = s_StampToolProperties.rotation.eulerAngles},
|
||
|
};
|
||
|
}
|
||
|
}
|