using UnityEngine; using UnityEngine.TerrainTools; using System.Collections.Generic; using UnityEditor.ShortcutManagement; namespace UnityEditor.TerrainTools { internal class NoiseHeightTool : TerrainPaintTool { #if UNITY_2019_1_OR_NEWER [Shortcut("Terrain/Select Noise Height Brush", typeof(TerrainToolShortcutContext))] // tells shortcut manager what to call the shortcut and what to pass as args static void SelectShortcut(ShortcutArguments args) { TerrainToolShortcutContext context = (TerrainToolShortcutContext)args.context; // gets interface to modify state of TerrainTools context.SelectPaintTool(); // set active tool TerrainToolsAnalytics.OnShortcutKeyRelease("Select Noise Height Brush"); } #endif [System.Serializable] public enum CoordinateSpace { World = 0, Brush, } [System.Serializable] private struct NoiseToolSettings { public Vector2 worldHeightRemap; public CoordinateSpace coordSpace; // TODO(wyatt): what happens if they don't have an active noise settings asset? public string noiseAssetGUID; public void Reset() { worldHeightRemap = new Vector2(0, 1); coordSpace = CoordinateSpace.World; noiseAssetGUID = null; } } private NoiseToolSettings m_toolSettings; private RenderTexture m_previewRT; private float m_simulationTime; private bool m_showToolGUI = true; private bool m_liveUpdate; private bool m_simulate; private float m_lastRotation; private Vector3 m_lastBrushPosition; private Matrix4x4 m_noiseToWorld; [SerializeField] IBrushUIGroup m_commonUI; private IBrushUIGroup commonUI { get { if (m_commonUI == null) { LoadSettings(); m_commonUI = new DefaultBrushUIGroup("NoiseHeightTool", UpdateAnalyticParameters, DefaultBrushUIGroup.Feature.All, new DefaultBrushUIGroup.FeatureDefaults { Strength = 0.37f } ); m_commonUI.OnEnterToolMode(); } return m_commonUI; } } private NoiseSettings m_noiseSettingsIfNull; private NoiseSettings noiseSettingsIfNull { get { if (m_noiseSettingsIfNull == null) { m_noiseSettingsIfNull = ScriptableObject.CreateInstance(); } return m_noiseSettingsIfNull; } } private string getNoiseSettingsPath { get { return Application.persistentDataPath + "/TerrainTools_NoiseHeightTool_NoiseSettings.noisesettings"; } } private NoiseSettings m_activeNoiseSettingsProfile; private NoiseSettings m_noiseSettings; private NoiseSettings noiseSettings { get { if (m_noiseSettings == null) { if (System.IO.File.Exists(getNoiseSettingsPath)) { UnityEngine.Object[] obs = UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(getNoiseSettingsPath); m_noiseSettings = obs[0] as NoiseSettings; } else { m_noiseSettings = ScriptableObject.CreateInstance(); m_noiseSettings.name = "NoiseHeightTool_NoiseSettings"; } } return m_noiseSettings; } } private NoiseSettingsGUI m_noiseSettingsGUI; private NoiseSettingsGUI noiseSettingsGUI { get { if (m_noiseSettingsGUI == null) { m_noiseSettingsGUI = new NoiseSettingsGUI(); } if (m_noiseSettingsGUI.target == null || m_noiseSettingsGUI.serializedNoise.targetObject == null) { m_noiseSettingsGUI.Init(noiseSettings); } return m_noiseSettingsGUI; } } /// /// Allows overriding for unit testing purposes /// /// internal void ChangeCommonUI(IBrushUIGroup uiGroup) { m_commonUI = uiGroup; } public override void OnEnterToolMode() { base.OnEnterToolMode(); m_noiseToWorld = Matrix4x4.identity; commonUI.OnEnterToolMode(); } public override void OnExitToolMode() { base.OnExitToolMode(); commonUI.OnExitToolMode(); } private static Material m_paintMaterial; private static Material paintMaterial { get { if (m_paintMaterial == null) { m_paintMaterial = new Material(Shader.Find("Hidden/TerrainTools/NoiseHeightTool")); } return m_paintMaterial; } } public override void OnDisable() { EditorApplication.update -= NoiseSimulationCB; } public override string GetName() { return "Sculpt/Noise"; } public override string GetDescription() { return "Increases or decreases the Terrain height using Noise and Fractal Types."; } private bool m_IsScrolling; private double m_ScrollTime; // GUI public override void OnInspectorGUI(Terrain terrain, IOnInspectorGUI editContext) { EditorGUI.BeginChangeCheck(); { GUILayout.Space(12); // brush GUI commonUI.OnInspectorGUI(terrain, editContext); m_showToolGUI = TerrainToolGUIHelper.DrawHeaderFoldout(Styles.noiseToolSettings, m_showToolGUI); if (m_showToolGUI) { GUILayout.Space(12); noiseSettingsGUI.DrawPreviewTexture(256f, true, m_IsScrolling); if (Event.current.type == EventType.ScrollWheel && !noiseSettingsGUI.isScrollingPreview) { m_IsScrolling = true; m_ScrollTime = Time.realtimeSinceStartupAsDouble; } if (m_IsScrolling && (Time.realtimeSinceStartupAsDouble - m_ScrollTime) > .2) { m_IsScrolling = false; } GUILayout.Space(12); // brush coordinate space toolbar EditorGUILayout.BeginHorizontal(); { EditorGUILayout.PrefixLabel(Styles.coordSpace); if (GUILayout.Toggle(m_toolSettings.coordSpace == CoordinateSpace.World, Styles.worldSpace, GUI.skin.button)) { m_toolSettings.coordSpace = CoordinateSpace.World; } if (GUILayout.Toggle(m_toolSettings.coordSpace == CoordinateSpace.Brush, Styles.brushSpace, GUI.skin.button)) { m_toolSettings.coordSpace = CoordinateSpace.Brush; } } EditorGUILayout.EndHorizontal(); GUILayout.Space(12); DoNoiseSettingsObjectField(); noiseSettingsGUI.OnGUI(NoiseSettingsGUIFlags.Settings); GUILayout.Space(12); } } if (EditorGUI.EndChangeCheck()) { SaveSettings(); Save(true); TerrainToolsAnalytics.OnParameterChange(); } } private void DoSimulationControls() { EditorGUILayout.BeginHorizontal(); { GUILayout.Label(Styles.simulationLabel, TerrainToolGUIHelper.dontExpandWidth); if (GUILayout.Toggle(m_simulate, Styles.simulationButton, GUI.skin.button, TerrainToolGUIHelper.dontExpandWidth)) { m_simulate = !m_simulate; EditorApplication.update -= NoiseSimulationCB; if (m_simulate) { EditorApplication.update += NoiseSimulationCB; } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label(Styles.time); m_simulationTime = EditorGUILayout.Slider(m_simulationTime, m_simulationTime - 1, m_simulationTime + 1, TerrainToolGUIHelper.dontExpandWidth); } EditorGUILayout.EndHorizontal(); GUILayout.Space(12); } private void DoNoiseSettingsObjectField() { bool profileInUse = m_activeNoiseSettingsProfile != null; float buttonWidth = 60; float indentOffset = EditorGUI.indentLevel * 15f; Rect lineRect = GUILayoutUtility.GetRect(1, EditorGUIUtility.singleLineHeight); Rect labelRect = new Rect(lineRect.x, lineRect.y, EditorGUIUtility.labelWidth - indentOffset, lineRect.height); Rect fieldRect = new Rect(labelRect.xMax, lineRect.y, lineRect.width - labelRect.width - buttonWidth * (profileInUse ? 3 : 2), lineRect.height); Rect resetButtonRect = new Rect(fieldRect.xMax, lineRect.y, buttonWidth, lineRect.height); Rect saveButtonRect = new Rect(resetButtonRect.xMax, lineRect.y, buttonWidth, lineRect.height); Rect saveAsButtonRect = new Rect(profileInUse ? saveButtonRect.xMax : resetButtonRect.xMax, lineRect.y, buttonWidth, lineRect.height); EditorGUI.PrefixLabel(labelRect, Styles.noiseSettingsProfile); NoiseSettings settingsProfile = m_activeNoiseSettingsProfile; settingsProfile = (NoiseSettings)EditorGUI.ObjectField(fieldRect, settingsProfile, typeof(NoiseSettings), false); if (m_activeNoiseSettingsProfile != null) { if (GUI.Button(resetButtonRect, Styles.revert)) { Undo.RecordObject(noiseSettings, "Noise Settings - Revert"); noiseSettings.Copy(m_activeNoiseSettingsProfile); } } else { if (GUI.Button(resetButtonRect, Styles.reset)) { Undo.RecordObject(noiseSettings, "Noise Settings - Reset"); noiseSettings.Reset(); } } if (profileInUse && GUI.Button(saveButtonRect, Styles.apply)) { Undo.RecordObject(m_activeNoiseSettingsProfile, "NoiseHeightTool - Apply Settings"); m_activeNoiseSettingsProfile.CopySerialized(noiseSettings); } if (GUI.Button(saveAsButtonRect, Styles.saveAs)) { string path = EditorUtility.SaveFilePanel("Save Noise Settings", Application.dataPath, "New Noise Settings.asset", "asset"); // saving to project's asset folder if (path.StartsWith(Application.dataPath)) { // TODO(wyatt): need to check if this works with different locales/languages. folder might not be // called "Assets" in non-English Editor builds string assetPath = path.Substring(Application.dataPath.Length - 6); // settingsProfile = NoiseSettings.CreateAsset(assetPath, noiseSettings); settingsProfile = NoiseSettingsFactory.CreateAsset(assetPath); settingsProfile.CopySerialized(noiseSettings); } // saving asset somewhere else. why? dunno! else if (!string.IsNullOrEmpty(path)) { Debug.LogError("Invalid path specified for creation of new Noise Settings asset. Must be a valid path within the current Unity project's Assets folder/data path."); } } // check if the profile in the object field changed bool changed = settingsProfile != m_activeNoiseSettingsProfile; if (changed) { if (settingsProfile == null) { noiseSettings.Copy(noiseSettingsIfNull); } else { if (m_activeNoiseSettingsProfile == null) { noiseSettingsIfNull.Copy(noiseSettings); } noiseSettings.Copy(settingsProfile); } noiseSettingsGUI.Init(noiseSettings); m_activeNoiseSettingsProfile = settingsProfile; } GUILayout.Space(12); } // Fill Tiles private void FillAllTiles(Terrain terrain) { Terrain[] terrains = TerrainFillUtility.GetTerrainsInGroup(terrain); foreach (Terrain tile in terrains) { FillTile(tile); } } private void FillTile(Terrain terrain) { // NoiseSettings noiseSettings = noiseSettings; // Material material = GetNoiseMaterial(NoiseLib.GetFractalFromName(noiseSettings.domainSettings.fractalTypeName).GetType()); // int pass = NoiseLib.GetNoiseIndex(noiseSettings.domainSettings.noiseTypeName); // float previewSize = 1 / 512f; // float brushSize = 1; // // brushSize = brushSize * previewSize; // float brushRotation = 0; // float brushStrength = commonUI.brushStrength; // Texture brushTexture = Texture2D.whiteTexture; // Vector3 brushPosWS = terrain.transform.position + .5f * new Vector3( terrain.terrainData.size.x, 0, terrain.terrainData.size.z ); // // set brush params // Vector4 brushParams = new Vector4( 0.01f * brushStrength, 0.0f, brushSize, 1 / brushSize ); // Quaternion rotQ = Quaternion.AxisAngle(Vector3.up, 0); // Matrix4x4 translation = Matrix4x4.Translate( brushPosWS ); // Matrix4x4 rotation = Matrix4x4.Rotate( rotQ ); // Matrix4x4 scale = Matrix4x4.Scale( Vector3.one * brushSize ); // Matrix4x4 b2w = translation * rotation * scale; // // brush mask and settings // material.SetTexture( "_BrushTex", brushTexture ); // material.SetVector( "_BrushParams", brushParams ); // // use this value to remap noise values // material.SetVector( "_WorldHeightRemap", m_toolSettings.worldHeightRemap ); // // assign matrices // material.SetMatrix( "_b2w", b2w ); // material.SetMatrix( "_b2w_Translation", translation ); // material.SetMatrix( "_b2w_Rotation", rotation ); // material.SetMatrix( "_b2w_Scale", scale ); // // assign inverse matrices // material.SetMatrix( "_w2b", b2w.inverse ); // material.SetMatrix( "_w2b_Translation", translation.inverse ); // material.SetMatrix( "_w2b_Rotation", rotation.inverse ); // material.SetMatrix( "_w2b_Scale", scale.inverse ); // noiseSettings.SetupMaterial(material); // BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, Vector2.one * .5f, // Mathf.Min(terrain.terrainData.size.x, terrain.terrainData.size.z), 0); // PaintContext ctx = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushXform.GetBrushXYBounds(), 1); // TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushXform, material); // Graphics.Blit(ctx.sourceRenderTexture, ctx.destinationRenderTexture, material, pass); // TerrainFillUtility.EndFillHeightmap(ctx, "Terrain Fill - Noise"); // terrain.ApplyDelayedHeightmapModification(); } private void ApplyBrushInternal(Terrain terrain, PaintContext ctx, BrushTransform brushXform, Vector3 brushPosWS, float brushRotation, float brushStrength, float brushSize, Texture brushTexture) { var prevRT = RenderTexture.active; var brushPositionOffset = brushPosWS - m_lastBrushPosition; m_lastBrushPosition = brushPosWS; brushPositionOffset.y = 0; var rotationDelta = brushRotation - m_lastRotation; m_lastRotation = brushRotation; //blit steps //1. blit noise to intermediate RT, this includes all the noise transformations and filters, //using the appropriate noise material. do this with NoiseUtils.Blit2D? //2. use that noise texture and mult it with brushmask to paint height on terrain // TODO(wyatt): remove magic number and tie it into NoiseSettingsGUI preview size somehow float previewSize = 1 / 512f; // get proper noise material from current noise settings NoiseSettings noiseSettings = this.noiseSettings; Material matNoise = NoiseUtils.GetDefaultBlitMaterial(noiseSettings); // setup the noise material with values in noise settings noiseSettings.SetupMaterial(matNoise); // change pos and scale so they match the noiseSettings preview bool isWorldSpace = (m_toolSettings.coordSpace == CoordinateSpace.World); brushSize = isWorldSpace ? brushSize * previewSize : 1; brushPositionOffset = isWorldSpace ? brushPositionOffset * previewSize : Vector3.zero; var brushTransform = NoiseFilter.GetBrushTransform(rotationDelta, brushSize); var scaleMultiplier = new Vector2( 1.0f / (brushSize / brushTransform.GetBrushXYBounds().width), 1.0f / (brushSize / brushTransform.GetBrushXYBounds().height)); // // override noise transform Quaternion rotQ = Quaternion.AngleAxis(-rotationDelta, Vector3.up); // accumulate transformation delta m_noiseToWorld *= Matrix4x4.TRS(brushPositionOffset, rotQ, Vector3.one); matNoise.SetMatrix(NoiseSettings.ShaderStrings.transform, noiseSettings.trs * m_noiseToWorld * Matrix4x4.Scale(new Vector3(scaleMultiplier.x, 1.0f, scaleMultiplier.y) * brushSize)); var noisePass = NoiseUtils.kNumBlitPasses * NoiseLib.GetNoiseIndex(noiseSettings.domainSettings.noiseTypeName); // render the noise field to a texture // TODO(wyatt): Handle the 3D case. Would need to blit to Volume Texture var rtDesc = ctx.destinationRenderTexture.descriptor; rtDesc.graphicsFormat = NoiseUtils.singleChannelFormat; rtDesc.sRGB = false; var noiseRT = RTUtils.GetTempHandle(rtDesc); RenderTexture.active = noiseRT; // keep this Graphics.Blit(noiseRT, matNoise, noisePass); // then add the result to the heightmap using the noise height tool shader Material matFinal = paintMaterial; var brushMask = RTUtils.GetTempHandle(ctx.sourceRenderTexture.width, ctx.sourceRenderTexture.height, 0, FilterUtility.defaultFormat); Utility.GenerateAndSetFilterRT(commonUI, ctx.sourceRenderTexture, brushMask, matFinal); TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushXform, matFinal); // set brush params Vector4 brushParams = new Vector4(0.01f * brushStrength, 0.0f, brushSize, 1 / brushSize); matFinal.SetVector("_BrushParams", brushParams); matFinal.SetTexture("_BrushTex", brushTexture); matFinal.SetTexture("_NoiseTex", noiseRT); matFinal.SetVector("_WorldHeightRemap", m_toolSettings.worldHeightRemap); Graphics.Blit(ctx.sourceRenderTexture, ctx.destinationRenderTexture, matFinal, 0); RTUtils.Release(noiseRT); RTUtils.Release(brushMask); RenderTexture.active = prevRT; } public override void OnSceneGUI(Terrain terrain, IOnSceneGUI editContext) { commonUI.OnSceneGUI2D(terrain, editContext); // only do the rest if user mouse hits valid terrain or they are using the // brush parameter hotkeys to resize, etc if (!editContext.hitValidTerrain && !commonUI.isInUse) { return; } // update brush UI group commonUI.OnSceneGUI(terrain, editContext); // dont render preview if this isnt a repaint. losing performance if we do if (Event.current.type != EventType.Repaint) { return; } using (IBrushRenderPreviewUnderCursor brushPreview = new BrushRenderPreviewUIGroupUnderCursor(commonUI, "NoiseHeightTool", editContext.brushTexture)) { float brushSize = commonUI.brushSize; float brushStrength = Event.current.control ? -commonUI.brushStrength : commonUI.brushStrength; Vector3 brushPosWS = commonUI.raycastHitUnderCursor.point; brushPreview.CalculateBrushTransform(out var brushXform); PaintContext ctx = brushPreview.AcquireHeightmap(false, brushXform.GetBrushXYBounds(), 1); Material previewMaterial = Utility.GetDefaultPreviewMaterial(commonUI.hasEnabledFilters); var filter = RTUtils.GetTempHandle(ctx.sourceRenderTexture.width, ctx.sourceRenderTexture.height, 0, FilterUtility.defaultFormat); Utility.GenerateAndSetFilterRT(commonUI, ctx.sourceRenderTexture, filter, previewMaterial); var texelCtx = Utility.CollectTexelValidity(ctx.originTerrain, brushXform.GetBrushXYBounds()); Utility.SetupMaterialForPaintingWithTexelValidityContext(ctx, texelCtx, brushXform, previewMaterial); previewMaterial.SetTexture("_HeightmapOrig", ctx.sourceRenderTexture); TerrainPaintUtilityEditor.DrawBrushPreview(ctx, TerrainBrushPreviewMode.SourceRenderTexture, editContext.brushTexture, brushXform, previewMaterial, 0); ApplyBrushInternal(terrain, ctx, brushXform, brushPosWS, commonUI.brushRotation, brushStrength, brushSize, editContext.brushTexture); TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushXform, previewMaterial); // restore old render target RenderTexture.active = ctx.oldRenderTexture; TerrainPaintUtilityEditor.DrawBrushPreview(ctx, TerrainBrushPreviewMode.DestinationRenderTexture, editContext.brushTexture, brushXform, previewMaterial, 1); texelCtx.Cleanup(); TerrainPaintUtility.ReleaseContextResources(ctx); RTUtils.Release(filter); } } private Vector3 WSPosFromTerrainUV(Terrain terrain, Vector2 uv) { return terrain.transform.position + terrain.terrainData.size.x * uv.x * Vector3.right + terrain.terrainData.size.z * uv.y * Vector3.forward; } public override bool OnPaint(Terrain terrain, IOnPaint editContext) { commonUI.OnPaint(terrain, editContext); if (commonUI.allowPaint) { Vector2 uv = editContext.uv; if (commonUI.ScatterBrushStamp(ref terrain, ref uv)) { BrushTransform brushXform = TerrainPaintUtility.CalculateBrushTransform(terrain, uv, commonUI.brushSize, commonUI.brushRotation); PaintContext paintContext = TerrainPaintUtility.BeginPaintHeightmap(terrain, brushXform.GetBrushXYBounds()); float brushStrength = commonUI.brushStrength; if (Event.current != null && Event.current.control) { brushStrength = -commonUI.brushStrength; } Vector3 brushPosWS = WSPosFromTerrainUV(terrain, uv); ApplyBrushInternal(terrain, paintContext, brushXform, brushPosWS, commonUI.brushRotation, brushStrength, commonUI.brushSize, editContext.brushTexture); TerrainPaintUtility.EndPaintHeightmap(paintContext, "Terrain Paint - Noise"); } } editContext.Repaint(RepaintFlags.UI); return true; } private void NoiseSimulationCB() { SceneView.RepaintAll(); } // Tool Settings I/O const string kToolSettingsName = "Unity.TerrainTools.NoiseHeightTool"; private void LoadSettings() { NoiseToolSettings defaultSettings = new NoiseToolSettings(); defaultSettings.Reset(); string settingsStr = EditorPrefs.GetString(kToolSettingsName, JsonUtility.ToJson(defaultSettings)); m_toolSettings = JsonUtility.FromJson(settingsStr); string assetPath = AssetDatabase.GUIDToAssetPath(m_toolSettings.noiseAssetGUID); if (!string.IsNullOrEmpty(assetPath)) { m_activeNoiseSettingsProfile = AssetDatabase.LoadAssetAtPath(assetPath); } } private void SaveSettings() { if (m_activeNoiseSettingsProfile != null) { string assetPath = AssetDatabase.GetAssetPath(m_activeNoiseSettingsProfile); if (!string.IsNullOrEmpty(assetPath)) { m_toolSettings.noiseAssetGUID = AssetDatabase.AssetPathToGUID(assetPath); } } string settingsStr = JsonUtility.ToJson(m_toolSettings); EditorPrefs.SetString(kToolSettingsName, settingsStr); // save the noise settings UnityEditorInternal.InternalEditorUtility.SaveToSerializedFileAndForget(new UnityEngine.Object[] { m_noiseSettings }, getNoiseSettingsPath, true); } // GUI Content and Styles static class Styles { public static GUILayoutOption dontExpandWidth = GUILayout.ExpandWidth(false); public static GUIContent simulationLabel = EditorGUIUtility.TrTextContent("Simulation Controls:"); public static GUIContent simulationButton = EditorGUIUtility.TrTextContent("Simulate"); public static GUIContent time = EditorGUIUtility.TrTextContent("Time"); public static GUIContent fillOptions = EditorGUIUtility.TrTextContent("Fill Options"); public static GUIContent fillSelected = EditorGUIUtility.TrTextContent("Fill Selected Tile"); public static GUIContent fillGroup = EditorGUIUtility.TrTextContent("Fill Tiles in Group"); public static GUIContent reset = EditorGUIUtility.TrTextContent("Reset", "Reset the Noise Settings to the default settings"); public static GUIContent revert = EditorGUIUtility.TrTextContent("Revert", "Revert the Noise Settings to the values of the Asset that is saved on disk"); public static GUIContent apply = EditorGUIUtility.TrTextContent("Apply", "Apply the current Noise Settings to the Asset that is saved on disk"); public static GUIContent saveAs = EditorGUIUtility.TrTextContent("Save As", "Open a window allowing you to save the current Noise Settings to a new Asset on disk"); public static GUIContent liveUpdate = EditorGUIUtility.TrTextContent("Live Update:"); public static GUIContent noiseSettingsProfile = EditorGUIUtility.TrTextContent("Noise Settings Asset", "The Noise Settings Asset to use when generating Noise for this tool"); public static GUIContent coordSpace = EditorGUIUtility.TrTextContent("Coordinate Space", "The coordinate space that is used when calculating positions fed into the Noise generation"); public static GUIContent worldSpace = EditorGUIUtility.TrTextContent("World", "World space positions are used to generate Noise"); public static GUIContent brushSpace = EditorGUIUtility.TrTextContent("Brush", "Brush space positions based on Brush UVs are used to generate Noise"); public static GUIContent worldSpaceHeightRange = EditorGUIUtility.TrTextContent("World Height Range"); public static GUIContent noiseToolSettings = EditorGUIUtility.TrTextContent("Noise Height Tool Settings", "Settings for the Noise Height Tool"); } //Analytics Setup List m_AnalyticsData = new List(); private TerrainToolsAnalytics.IBrushParameter[] UpdateAnalyticParameters() { m_AnalyticsData.Clear(); SerializedProperty transformSettings = noiseSettingsGUI.serializedNoise.FindProperty("transformSettings"); SerializedProperty domainSettings = noiseSettingsGUI.serializedNoise.FindProperty("domainSettings"); SerializedProperty fractalTypeName = domainSettings.FindPropertyRelative("fractalTypeName"); SerializedProperty fractalTypeParams = domainSettings.FindPropertyRelative("fractalTypeParams"); //Add Generic, Transform, and Domain type settings to be sent as analytic data m_AnalyticsData.AddRange(new TerrainToolsAnalytics.IBrushParameter[]{ //Generic Settings new TerrainToolsAnalytics.BrushParameter{Name = Styles.coordSpace.text, Value = m_toolSettings.coordSpace.ToString()}, //Transform Settings new TerrainToolsAnalytics.BrushParameter{Name = "Translation", Value = transformSettings.FindPropertyRelative("translation").vector3Value}, new TerrainToolsAnalytics.BrushParameter{Name = "Rotation", Value = transformSettings.FindPropertyRelative("rotation").vector3Value}, new TerrainToolsAnalytics.BrushParameter{Name = "Scale", Value = transformSettings.FindPropertyRelative("scale").vector3Value}, new TerrainToolsAnalytics.BrushParameter{Name = NoiseSettingsGUI.Styles.flipScaleX.text, Value = transformSettings.FindPropertyRelative("flipScaleX").boolValue}, new TerrainToolsAnalytics.BrushParameter{Name = NoiseSettingsGUI.Styles.flipScaleY.text, Value = transformSettings.FindPropertyRelative("flipScaleY").boolValue}, new TerrainToolsAnalytics.BrushParameter{Name = NoiseSettingsGUI.Styles.flipScaleZ.text, Value = transformSettings.FindPropertyRelative("flipScaleZ").boolValue}, //Domain new TerrainToolsAnalytics.BrushParameter{Name = NoiseSettingsGUI.Styles.noiseType.text, Value = domainSettings.FindPropertyRelative("noiseTypeName").stringValue}, new TerrainToolsAnalytics.BrushParameter{Name = NoiseSettingsGUI.Styles.fractalType.text, Value = domainSettings.FindPropertyRelative("fractalTypeName").stringValue}} ); //Add fractal specific settings to be sent as analytic data IFractalType fractalType = NoiseLib.GetFractalTypeInstance(fractalTypeName.stringValue); switch (domainSettings.FindPropertyRelative("fractalTypeName").stringValue) { case "Fbm": FbmFractalType.FbmFractalInput fbmFractalSettings = (FbmFractalType.FbmFractalInput)fractalType.FromSerializedString(fractalTypeParams.stringValue); m_AnalyticsData.AddRange(new TerrainToolsAnalytics.IBrushParameter[]{ new TerrainToolsAnalytics.BrushParameter{Name = FbmFractalType.Styles.octaves.text, Value = fbmFractalSettings.octaves}, new TerrainToolsAnalytics.BrushParameter{Name = FbmFractalType.Styles.amplitude.text, Value = fbmFractalSettings.amplitude}, new TerrainToolsAnalytics.BrushParameter{Name = FbmFractalType.Styles.persistence.text, Value = fbmFractalSettings.persistence}, new TerrainToolsAnalytics.BrushParameter{Name = FbmFractalType.Styles.frequency.text, Value = fbmFractalSettings.frequency}, new TerrainToolsAnalytics.BrushParameter{Name = FbmFractalType.Styles.lacunarity.text, Value = fbmFractalSettings.lacunarity}, new TerrainToolsAnalytics.BrushParameter{Name = FbmFractalType.Styles.domainWarpSettings.text, Value = fbmFractalSettings.warpEnabled}, new TerrainToolsAnalytics.BrushParameter{Name = FbmFractalType.Styles.warpIterations.text, Value = fbmFractalSettings.warpIterations}, new TerrainToolsAnalytics.BrushParameter{Name = FbmFractalType.Styles.warpStrength.text, Value = fbmFractalSettings.warpStrength}, new TerrainToolsAnalytics.BrushParameter{Name = FbmFractalType.Styles.warpOffsets.text, Value = fbmFractalSettings.warpOffsets}, }); break; case "Strata": StrataFractalType.StrataFractalInput strataFractalSettings = (StrataFractalType.StrataFractalInput)fractalType.FromSerializedString(fractalTypeParams.stringValue); m_AnalyticsData.AddRange(new TerrainToolsAnalytics.IBrushParameter[]{ new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.octaves.text, Value = strataFractalSettings.octaves}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.amplitude.text, Value = strataFractalSettings.amplitude}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.persistence.text, Value = strataFractalSettings.persistence}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.frequency.text, Value = strataFractalSettings.frequency}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.lacunarity.text, Value = strataFractalSettings.lacunarity}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.domainWarpSettings.text, Value = strataFractalSettings.warpEnabled}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.warpIterations.text, Value = strataFractalSettings.warpIterations}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.warpStrength.text, Value = strataFractalSettings.warpStrength}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.warpOffsets.text, Value = strataFractalSettings.warpOffsets}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.strataOffset.text, Value = strataFractalSettings.strataOffset}, new TerrainToolsAnalytics.BrushParameter{Name = StrataFractalType.Styles.strataScale.text, Value = strataFractalSettings.strataScale}, }); break; case "None": default: break; } return m_AnalyticsData.ToArray(); } } }