using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using UnityEditorInternal; using System.IO; using UnityEngine.Rendering; using System.Linq; #if VEGETATION_STUDIO_PRO using AwesomeTechnologies; using AwesomeTechnologies.VegetationSystem; using AwesomeTechnologies.VegetationSystem.Biomes; #endif #if VEGETATION_STUDIO using AwesomeTechnologies; using AwesomeTechnologies.VegetationStudio; #endif [CustomEditor(typeof(RamSpline)), CanEditMultipleObjects] public class RamSplineEditor : Editor { //Vector2 scrollPos; RamSpline[] splines; RamSpline spline; Texture2D logo; int selectedPosition = -1; Vector3 pivotChange = Vector3.zero; bool terrainShapeShow = false; List> positionArray; int splitPoint = 1; Mesh meshTerrain; public string[] shadowcastingOptions = new string[] { "Off", "On", "TwoSided", "ShadowsOnly" }; public string[] toolbarStrings = new string[] { "Basic ", "Points", "Vertex Color", "Flow Map", "Simulate", "Terrain", "File Points", "Tips", "Manual", "Video Tutorials" #if VEGETATION_STUDIO , "Vegetation Studio" #endif #if VEGETATION_STUDIO_PRO , "Vegetation Studio Pro" #endif }; //, "Debug" }; // /// // /// The button editing style. // /// // GUIStyle buttonEditingStyle; [MenuItem("GameObject/3D Object/Create River Spline")] static public void CreateSpline() { Selection.activeGameObject = RamSpline.CreateSpline(AssetDatabase.GetBuiltinExtraResource("Default-Diffuse.mat")).gameObject; } void OnEnable() { splines = FindObjectsOfType(); #if VEGETATION_STUDIO spline = (RamSpline)target; spline.vegetationMaskArea = spline.gameObject.GetComponent(); #endif SceneView.duringSceneGui -= this.OnSceneGUIInvoke; SceneView.duringSceneGui += this.OnSceneGUIInvoke; } private void OnDisable() { if (spline != null && spline.meshGO != null) DestroyImmediate(spline.meshGO); SceneView.duringSceneGui -= this.OnSceneGUIInvoke; } private void OnDestroy() { if (spline != null && spline.meshGO != null) DestroyImmediate(spline.meshGO); } void CheckRotations() { bool nan = false; if (spline.controlPointsRotations == null) { spline.controlPointsRotations = new List(); nan = true; } if (spline.controlPoints.Count > spline.controlPointsRotations.Count) { nan = true; for (int i = 0; i < spline.controlPoints.Count - spline.controlPointsRotations.Count; i++) { spline.controlPointsRotations.Add(Quaternion.identity); } } for (int i = 0; i < spline.controlPointsRotations.Count; i++) { if (float.IsNaN(spline.controlPointsRotations[i].x) || float.IsNaN(spline.controlPointsRotations[i].y) || float.IsNaN(spline.controlPointsRotations[i].z) || float.IsNaN(spline.controlPointsRotations[i].w)) { spline.controlPointsRotations[i] = Quaternion.identity; nan = true; } if (spline.controlPointsRotations[i].x == 0 && spline.controlPointsRotations[i].y == 0 && spline.controlPointsRotations[i].z == 0 && spline.controlPointsRotations[i].w == 0) { spline.controlPointsRotations[i] = Quaternion.identity; nan = true; } spline.controlPointsRotations[i] = Quaternion.Euler(spline.controlPointsRotations[i].eulerAngles); } if (nan) spline.GenerateSpline(); } public override void OnInspectorGUI() { EditorGUILayout.Space(); logo = (Texture2D)Resources.Load("logoRAM"); Color baseCol = GUI.color; spline = (RamSpline)target; CheckRotations(); if (spline.controlPoints.Count > spline.controlPointsSnap.Count) { for (int i = 0; i < spline.controlPoints.Count - spline.controlPointsSnap.Count; i++) { spline.controlPointsSnap.Add(0); } } if (spline.controlPoints.Count > spline.controlPointsMeshCurves.Count) { for (int i = 0; i < spline.controlPoints.Count - spline.controlPointsMeshCurves.Count; i++) { spline.controlPointsMeshCurves.Add(new AnimationCurve(new Keyframe[] { new Keyframe(0, 0), new Keyframe(1, 0) })); } } if (spline.controlPoints.Count > spline.controlPointsOrientation.Count) spline.GenerateSpline(); GUIContent btnTxt = new GUIContent(logo); var rt = GUILayoutUtility.GetRect(btnTxt, GUI.skin.label, GUILayout.ExpandWidth(false)); rt.center = new Vector2(EditorGUIUtility.currentViewWidth / 2, rt.center.y); GUI.Button(rt, btnTxt, GUI.skin.label); EditorGUI.BeginChangeCheck(); // GUILayout.Toolbar(spline.toolbarInt, toolbarStrings); int toolbarNew = GUILayout.SelectionGrid(spline.toolbarInt, toolbarStrings, 3, GUILayout.Height(125)); if (toolbarNew == 8) { toolbarNew = spline.toolbarInt; string[] guids1 = AssetDatabase.FindAssets("River Auto and Lava Volcano Environment Manual 2019"); Application.OpenURL("file:///" + Application.dataPath.Replace("Assets", "") + AssetDatabase.GUIDToAssetPath(guids1[0])); } if (toolbarNew == 9) { toolbarNew = spline.toolbarInt; Application.OpenURL("https://www.youtube.com/playlist?list=PLWMxYDHySK5PkIlklmHKLYvRWK2sjDYXX"); } if (spline.toolbarInt != toolbarNew) { if (spline.meshGO != null) DestroyImmediate(spline.meshGO); } spline.toolbarInt = toolbarNew; EditorGUILayout.Space(); spline.drawOnMesh = false; spline.drawOnMeshFlowMap = false; if (spline.showFlowMap) { if (spline.uvRotation) spline.GetComponent().sharedMaterial.SetFloat("_RotateUV", 1); else spline.GetComponent().sharedMaterial.SetFloat("_RotateUV", 0); } if (spline.transform.eulerAngles.magnitude != 0 || spline.transform.localScale.x != 1 || spline.transform.localScale.y != 1 || spline.transform.localScale.z != 1) EditorGUILayout.HelpBox("River should have scale (1,1,1) and rotation (0,0,0) during edit!", MessageType.Error); if (spline.toolbarInt == 0) { EditorGUILayout.HelpBox("Add Point - CTRL + Left Mouse Button Click \n" + "Add point between existing points - SHIFT + Left Button Click \n" + "Remove point - CTRL + SHIFT + Left Button Click", MessageType.Info); EditorGUI.indentLevel++; AddPointAtEnd(); EditorGUI.indentLevel--; EditorGUILayout.Space(); MeshSettings(); GUILayout.Label("UV settings:", EditorStyles.boldLabel); if (spline.beginningSpline == null && spline.endingSpline == null) { spline.uvScale = EditorGUILayout.FloatField("UV scale (texture tiling)", spline.uvScale); } else { spline.uvScaleOverride = EditorGUILayout.Toggle("Parent UV scale override", spline.uvScaleOverride); if (!spline.uvScaleOverride) { if (spline.beginningSpline != null) spline.uvScale = spline.beginningSpline.uvScale; if (spline.endingSpline != null) spline.uvScale = spline.endingSpline.uvScale; GUI.enabled = false; } spline.uvScale = EditorGUILayout.FloatField("UV scale (texture tiling)", spline.uvScale); GUI.enabled = true; } spline.invertUVDirection = EditorGUILayout.Toggle("Invert UV direction", spline.invertUVDirection); spline.uvRotation = EditorGUILayout.Toggle("Rotate UV", spline.uvRotation); GUILayout.Label("Lightning settings:", EditorStyles.boldLabel); spline.receiveShadows = EditorGUILayout.Toggle("Receive Shadows", spline.receiveShadows); spline.shadowCastingMode = (ShadowCastingMode)EditorGUILayout.EnumPopup("Shadow Casting Mode", spline.shadowCastingMode); EditorGUILayout.Space(); //SetMaterials (); EditorGUILayout.Space(); ParentingSplineUI(); EditorGUILayout.Space(); EditorGUILayout.Space(); GUILayout.Label("Mesh spliting:", EditorStyles.boldLabel); spline.generateMeshParts = EditorGUILayout.Toggle("Split mesh into submeshes", spline.generateMeshParts); if (spline.generateMeshParts) { spline.meshPartsCount = EditorGUILayout.IntSlider("Parts", spline.meshPartsCount, 2, (int)((1 / (float)spline.traingleDensity) * (spline.controlPoints.Count - 1) * 0.5)); } EditorGUILayout.Space(); EditorGUILayout.LabelField("Split spline into 2 splines:"); EditorGUI.indentLevel++; if (spline.controlPoints.Count > 2) { splitPoint = EditorGUILayout.IntSlider("Split point", splitPoint, 1, spline.controlPoints.Count - 1); if (GUILayout.Button("Split spline")) { SplitRiver(splitPoint); } } EditorGUI.indentLevel--; EditorGUILayout.Space(); GUILayout.Label("Object settings:", EditorStyles.boldLabel); EditorGUILayout.Space(); if (GUILayout.Button("Set object pivot to center")) { Vector3 center = spline.meshfilter.sharedMesh.bounds.center; ChangePivot(center); } EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button("Set object pivot position")) { ChangePivot(pivotChange - spline.transform.position); } pivotChange = EditorGUILayout.Vector3Field("", pivotChange); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); EditorGUILayout.Space(); if (GUILayout.Button(new GUIContent("Regenerate spline", "Racalculates whole mesh"))) { spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } spline.generateOnStart = EditorGUILayout.Toggle("Regenerate on Start", spline.generateOnStart); EditorGUILayout.Space(); if (GUILayout.Button("Export as mesh")) { string path = EditorUtility.SaveFilePanelInProject("Save river mesh", "", "asset", "Save river mesh"); if (path.Length != 0 && spline.meshfilter.sharedMesh != null) { AssetDatabase.CreateAsset(spline.meshfilter.sharedMesh, path); AssetDatabase.Refresh(); spline.GenerateSpline(); } } EditorGUILayout.Space(); GUILayout.Label("Debug Settings: ", EditorStyles.boldLabel); spline.debug = EditorGUILayout.Toggle("Show debug gizmos", spline.debug); if (spline.debug) { EditorGUI.indentLevel++; // spline.debugMesh = EditorGUILayout.Toggle("Debug Mesh", spline.debugMesh); spline.distanceToDebug = EditorGUILayout.DelayedFloatField("Debug distance", spline.distanceToDebug); spline.debugTangents = EditorGUILayout.Toggle("Show tangents", spline.debugTangents); // spline.debugBitangent = EditorGUILayout.Toggle("Show bitangents", spline.debugBitangent); spline.debugNormals = EditorGUILayout.Toggle("Show normals", spline.debugNormals); spline.debugFlowmap = EditorGUILayout.Toggle("Show flow map", spline.debugFlowmap); spline.debugPoints = EditorGUILayout.Toggle("Show points", spline.debugPoints); spline.debugPointsConnect = EditorGUILayout.Toggle("Show points connect", spline.debugPointsConnect); EditorGUI.indentLevel--; } EditorGUILayout.Space(); EditorGUILayout.Space(); } else if (spline.toolbarInt == 1) { PointsUI(); } else if (spline.toolbarInt == 2) { DrawVertexColorsUI(); } else if (spline.toolbarInt == 3) { DrawFlowColorsUI(); } else if (spline.toolbarInt == 4) { EditorGUILayout.HelpBox("\nSet 1 point and R.A.M will show potential river direction.\n", MessageType.Info); GUILayout.Label("River simulation:", EditorStyles.boldLabel); EditorGUI.indentLevel++; spline.simulatedRiverLength = EditorGUILayout.FloatField("Simulation length", spline.simulatedRiverLength); if (spline.simulatedRiverLength < 1) spline.simulatedRiverLength = 1; spline.simulatedRiverPoints = EditorGUILayout.IntSlider("Simulation points interval", spline.simulatedRiverPoints, 1, 100); spline.simulatedMinStepSize = EditorGUILayout.Slider("Simulation sampling interval", spline.simulatedMinStepSize, 0.5f, 5); spline.simulatedNoUp = EditorGUILayout.Toggle("Simulation block uphill", spline.simulatedNoUp); spline.simulatedBreakOnUp = EditorGUILayout.Toggle("Simulation break on uphill", spline.simulatedBreakOnUp); spline.noiseWidth = EditorGUILayout.Toggle("Add width noise", spline.noiseWidth); if (spline.noiseWidth) { EditorGUI.indentLevel++; spline.noiseMultiplierWidth = EditorGUILayout.FloatField("Noise Multiplier Width", spline.noiseMultiplierWidth); spline.noiseSizeWidth = EditorGUILayout.FloatField("Noise Scale Width", spline.noiseSizeWidth); EditorGUI.indentLevel--; } EditorGUILayout.Space(); if (GUILayout.Button("Show simulated River")) { spline.SimulateRiver(false); } if (GUILayout.Button("Generate Simulated River")) { Undo.RecordObject(spline, "Spline changed"); spline.SimulateRiver(); } if (GUILayout.Button("Remove points except first")) { spline.RemovePoints(0); } EditorGUI.indentLevel--; } else if (spline.toolbarInt == 5) { Terrain terrain = Terrain.activeTerrain; if (terrain != null && terrain.terrainData != null && terrain.terrainData.terrainLayers != null) { RiverChannel(); } else EditorGUILayout.HelpBox("No terrain on scene.", MessageType.Warning); } else if (spline.toolbarInt == 6) { FilesManager(); } else if (spline.toolbarInt == 7) { Tips(); } #if VEGETATION_STUDIO if (spline.toolbarInt == 10) { EditorGUILayout.Space(); GUILayout.Label("Vegetation Studio: ", EditorStyles.boldLabel); spline.vegetationMaskPerimeter = EditorGUILayout.FloatField("Vegetation Mask Perimeter", spline.vegetationMaskPerimeter); if (spline.vegetationMaskArea == null && GUILayout.Button("Add Vegetation Mask Area")) { spline.vegetationMaskArea = spline.gameObject.AddComponent(); RegenerateVegetationMask(); } if (spline.vegetationMaskArea != null && GUILayout.Button("Calculate hull outline")) { RegenerateVegetationMask(); } } #endif #if VEGETATION_STUDIO_PRO if (spline.toolbarInt == 10) { EditorGUILayout.Space(); GUILayout.Label("Vegetation Studio Pro: ", EditorStyles.boldLabel); spline.vegetationMaskSize = EditorGUILayout.FloatField("Vegetation Mask Size", spline.vegetationMaskSize); spline.vegetationBlendDistance = EditorGUILayout.FloatField("Vegetation Blend Distance", spline.vegetationBlendDistance); spline.biomMaskResolution = EditorGUILayout.Slider("Mask Resolution", spline.biomMaskResolution, 0.1f, 1); if (spline.biomeMaskArea != null) spline.refreshMask = EditorGUILayout.Toggle("Auto Refresh Biome Mask", spline.refreshMask); if (GUILayout.Button("Add Vegetation Biome Mask Area")) { spline.GenerateSpline(); if (spline.biomeMaskArea == null) { spline.biomeMaskArea = spline.GetComponentInChildren(); if (spline.biomeMaskArea == null) { GameObject maskObject = new GameObject("MyMask"); maskObject.transform.SetParent(spline.transform); spline.biomeMaskArea = maskObject.AddComponent(); spline.biomeMaskArea.BiomeType = BiomeType.River; } } if (spline.biomeMaskArea == null) return; RegeneratBiomeMask(false); } } #endif //if (spline.toolbarInt == 6) //{ // DebugOptions(); //} if (EditorGUI.EndChangeCheck()) { if (spline != null) { Undo.RecordObject(spline, "Spline changed"); spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } } EditorGUILayout.Space(); if (spline.beginningSpline) { if (!spline.beginningSpline.endingChildSplines.Contains(spline)) { spline.beginningSpline.endingChildSplines.Add(spline); } } if (spline.endingSpline) { if (!spline.endingSpline.beginnigChildSplines.Contains(spline)) { spline.endingSpline.beginnigChildSplines.Add(spline); } } } #if VEGETATION_STUDIO private void RegenerateVegetationMask() { spline.vegetationMaskArea.AdditionalGrassPerimiterMax = spline.vegetationMaskPerimeter; spline.vegetationMaskArea.AdditionalLargeObjectPerimiterMax = spline.vegetationMaskPerimeter; spline.vegetationMaskArea.AdditionalObjectPerimiterMax = spline.vegetationMaskPerimeter; spline.vegetationMaskArea.AdditionalPlantPerimiterMax = spline.vegetationMaskPerimeter; spline.vegetationMaskArea.AdditionalTreePerimiterMax = spline.vegetationMaskPerimeter; spline.vegetationMaskArea.GenerateHullNodes(spline.vegetationMaskArea.ReductionTolerance); spline.GenerateSpline(); List worldspacePointList = new List(); for (int i = 0; i < spline.pointsUp.Count; i += 5) { Vector3 position = spline.transform.TransformPoint(spline.pointsUp[i]) + (spline.transform.TransformPoint(spline.pointsUp[i]) - spline.transform.TransformPoint(spline.pointsDown[i])).normalized * spline.vegetationMaskPerimeter; worldspacePointList.Add(position); } for (int i = 0; i < spline.pointsDown.Count; i += 5) { int ind = spline.pointsDown.Count - i - 1; Vector3 position = spline.transform.TransformPoint(spline.pointsDown[ind]) + (spline.transform.TransformPoint(spline.pointsDown[ind]) - spline.transform.TransformPoint(spline.pointsUp[ind])).normalized * spline.vegetationMaskPerimeter; worldspacePointList.Add(position); } spline.vegetationMaskArea.ClearNodes(); for (var i = 0; i <= worldspacePointList.Count - 1; i++) { spline.vegetationMaskArea.AddNodeToEnd(worldspacePointList[i]); } spline.vegetationMaskArea.UpdateVegetationMask(); } #endif #if VEGETATION_STUDIO_PRO void RegeneratBiomeMask(bool checkAuto = true) { if (checkAuto && !spline.refreshMask) return; if (spline.biomeMaskArea == null) return; List disableEdges = new List(); List worldspacePointList = new List(); for (int i = 0; i < spline.pointsUp.Count; i += (int)(1 / (float)spline.biomMaskResolution)) { Vector3 position = spline.transform.TransformPoint(spline.pointsUp[i]) + (spline.transform.TransformPoint(spline.pointsUp[i]) - spline.transform.TransformPoint(spline.pointsDown[i])).normalized * spline.vegetationMaskSize; worldspacePointList.Add(position); if (i == 0 || (i + (int)(1 / (float)spline.biomMaskResolution)) >= spline.pointsUp.Count) { disableEdges.Add(true); } else { disableEdges.Add(false); } } for (int i = 0; i < spline.pointsDown.Count; i += (int)(1 / (float)spline.biomMaskResolution)) { int ind = spline.pointsDown.Count - i - 1; Vector3 position = spline.transform.TransformPoint(spline.pointsDown[ind]) + (spline.transform.TransformPoint(spline.pointsDown[ind]) - spline.transform.TransformPoint(spline.pointsUp[ind])).normalized * spline.vegetationMaskSize; worldspacePointList.Add(position); if (i == 0 || (i + (int)(1 / (float)spline.biomMaskResolution)) >= spline.pointsDown.Count) { disableEdges.Add(true); } else { disableEdges.Add(false); } } spline.biomeMaskArea.ClearNodes(); spline.biomeMaskArea.AddNodesToEnd(worldspacePointList.ToArray(), disableEdges.ToArray()); //these have default values but you can set them if you want a different default setting spline.biomeMaskArea.BlendDistance = spline.vegetationBlendDistance; spline.biomeMaskArea.NoiseScale = 5; spline.biomeMaskArea.UseNoise = true; if (spline.currentProfile != null) { spline.biomeMaskArea.BiomeType = (BiomeType)spline.currentProfile.biomeType; } else spline.biomeMaskArea.BiomeType = BiomeType.River; //These 3 curves holds the blend curves for vegetation and textures. they have default values; //biomeMaskArea.BlendCurve; //biomeMaskArea.InverseBlendCurve; //biomeMaskArea.TextureBlendCurve; spline.biomeMaskArea.UpdateBiomeMask(); } #endif void RiverChannel() { EditorGUI.BeginChangeCheck(); EditorGUILayout.Space(); GUILayout.Label("Terrain carve:", EditorStyles.boldLabel); EditorGUI.indentLevel++; spline.terrainCarve = EditorGUILayout.CurveField("Terrain carve", spline.terrainCarve); spline.terrainSmoothMultiplier = EditorGUILayout.Slider("Smooth", spline.terrainSmoothMultiplier, 0, 20); spline.distSmooth = EditorGUILayout.FloatField("Smooth distance", spline.distSmooth); spline.maskCarve = LayerMaskField("Layers", spline.maskCarve, true); spline.noiseCarve = EditorGUILayout.Toggle("Add noise", spline.noiseCarve); EditorGUILayout.Space(); if (spline.noiseCarve) { EditorGUI.indentLevel++; spline.noiseMultiplierInside = EditorGUILayout.FloatField("Noise Multiplier Inside", spline.noiseMultiplierInside); spline.noiseMultiplierOutside = EditorGUILayout.FloatField("Noise Multiplier Outside", spline.noiseMultiplierOutside); spline.noiseSizeX = EditorGUILayout.FloatField("Noise scale X", spline.noiseSizeX); spline.noiseSizeZ = EditorGUILayout.FloatField("Noise scale Z", spline.noiseSizeZ); EditorGUI.indentLevel--; } //spline.distSmoothStart = EditorGUILayout.FloatField("Smooth start distance", spline.distSmoothStart); EditorGUI.indentLevel--; if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(spline, "River terrain changed"); if (terrainShapeShow) spline.ShowTerrainCarve(); } if (!terrainShapeShow && GUILayout.Button("Show terrain shape")) { spline.ShowTerrainCarve(); terrainShapeShow = true; } if (terrainShapeShow && GUILayout.Button("Hide terrain shape")) { if (spline.meshGO != null) DestroyImmediate(spline.meshGO); terrainShapeShow = false; } EditorGUI.BeginChangeCheck(); EditorGUI.indentLevel++; spline.overrideRiverRender = EditorGUILayout.Toggle("Debug Override river render", spline.overrideRiverRender); EditorGUI.indentLevel--; if (GUILayout.Button("Carve terrain")) { spline.ShowTerrainCarve(); spline.TerrainCarve(); terrainShapeShow = false; } EditorGUILayout.Space(); GUILayout.Label("Terrain paint:", EditorStyles.boldLabel); EditorGUI.indentLevel++; spline.terrainPaintCarve = EditorGUILayout.CurveField("Terrain paint", spline.terrainPaintCarve); Terrain terrain = Terrain.activeTerrain; //Debug.Log("terrain " + terrain.name); int splatNumber = terrain.terrainData.terrainLayers.Length; //Debug.Log("splatNumber "+ splatNumber); string[] options = new string[splatNumber]; for (int i = 0; i < splatNumber; i++) { options[i] = i + " - "; //Debug.Log("diffuseTexture is null " + (terrain.terrainData.terrainLayers[i].diffuseTexture == null)); if (terrain.terrainData.terrainLayers[i] != null && terrain.terrainData.terrainLayers[i].diffuseTexture != null) { //Debug.Log(terrain.terrainData.terrainLayers[i].diffuseTexture.name); options[i] += terrain.terrainData.terrainLayers[i].diffuseTexture.name; } } EditorGUILayout.BeginHorizontal(); GUILayout.Label(" Splat id:"); spline.currentSplatMap = EditorGUILayout.Popup(spline.currentSplatMap, options); EditorGUILayout.EndHorizontal(); spline.noisePaint = EditorGUILayout.Toggle("Add noise", spline.noisePaint); if (spline.noisePaint) { EditorGUI.indentLevel++; spline.noiseMultiplierInsidePaint = EditorGUILayout.FloatField("Noise Multiplier Inside", spline.noiseMultiplierInsidePaint); spline.noiseMultiplierOutsidePaint = EditorGUILayout.FloatField("Noise Multiplier Outside", spline.noiseMultiplierOutsidePaint); spline.noiseSizeXPaint = EditorGUILayout.FloatField("Noise scale X", spline.noiseSizeXPaint); spline.noiseSizeZPaint = EditorGUILayout.FloatField("Noise scale Z", spline.noiseSizeZPaint); EditorGUI.indentLevel--; } spline.mixTwoSplatMaps = EditorGUILayout.Toggle("Mix two splat maps", spline.mixTwoSplatMaps); if (spline.mixTwoSplatMaps) { EditorGUI.indentLevel++; EditorGUILayout.BeginHorizontal(); GUILayout.Label(" Second splat id:"); spline.secondSplatMap = EditorGUILayout.Popup(spline.secondSplatMap, options); EditorGUILayout.EndHorizontal(); EditorGUI.indentLevel--; } spline.addCliffSplatMap = EditorGUILayout.Toggle("Add cliff splatmap", spline.addCliffSplatMap); if (spline.addCliffSplatMap) { EditorGUI.indentLevel++; EditorGUILayout.BeginHorizontal(); GUILayout.Label(" Cliff splat id:"); spline.cliffSplatMap = EditorGUILayout.Popup(spline.cliffSplatMap, options); EditorGUILayout.EndHorizontal(); spline.cliffAngle = EditorGUILayout.FloatField("Cliff angle", spline.cliffAngle); spline.cliffBlend = EditorGUILayout.FloatField("Cliff blend", spline.cliffBlend); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); GUILayout.Label(" Cliff outside splat id:"); spline.cliffSplatMapOutside = EditorGUILayout.Popup(spline.cliffSplatMapOutside, options); EditorGUILayout.EndHorizontal(); spline.cliffAngleOutside = EditorGUILayout.FloatField("Cliff outside angle", spline.cliffAngleOutside); spline.cliffBlendOutside = EditorGUILayout.FloatField("Cliff outside blend", spline.cliffBlendOutside); EditorGUI.indentLevel--; } EditorGUILayout.Space(); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(spline, "River terrain changed"); if (spline.meshGO != null) { if (spline.overrideRiverRender) spline.meshGO.GetComponent().sharedMaterial.renderQueue = 5000; else spline.meshGO.GetComponent().sharedMaterial.renderQueue = 2980; } } EditorGUI.indentLevel--; //Debug.Log(splatNumber); //Debug.Log(spline.currentSplatMap); if (splatNumber > 0 && splatNumber > spline.currentSplatMap) { if (GUILayout.Button("Paint Terrain")) { spline.ShowTerrainCarve(); spline.TerrainPaintMeshBased(); terrainShapeShow = false; } } else EditorGUILayout.HelpBox("No splat id selected to paint", MessageType.Error); EditorGUILayout.Space(); GUILayout.Label("Terrain clear foliage:", EditorStyles.boldLabel); EditorGUI.indentLevel++; spline.distanceClearFoliage = EditorGUILayout.FloatField("Remove Details Distance", spline.distanceClearFoliage); if (GUILayout.Button("Remove Details Foliage")) { spline.ShowTerrainCarve(spline.distanceClearFoliage); spline.TerrainClearFoliage(); terrainShapeShow = false; } spline.distanceClearFoliageTrees = EditorGUILayout.FloatField("Remove Trees Distance", spline.distanceClearFoliageTrees); if (GUILayout.Button("Remove Trees")) { spline.ShowTerrainCarve(spline.distanceClearFoliageTrees); spline.TerrainClearFoliage(false); terrainShapeShow = false; } EditorGUI.indentLevel--; } public static float DistancePointLine(Vector3 point, Vector3 lineStart, Vector3 lineEnd) { return Vector3.Distance(ProjectPointLine(point, lineStart, lineEnd), point); } public static Vector3 ProjectPointLine(Vector3 point, Vector3 lineStart, Vector3 lineEnd) { Vector3 rhs = point - lineStart; Vector3 vector2 = lineEnd - lineStart; float magnitude = vector2.magnitude; Vector3 lhs = vector2; if (magnitude > 1E-06f) { lhs = (Vector3)(lhs / magnitude); } float num2 = Mathf.Clamp(Vector3.Dot(lhs, rhs), 0f, magnitude); return (lineStart + ((Vector3)(lhs * num2))); } void DebugOptions() { EditorGUILayout.LabelField("splitParameter", spline.uvBeginning.ToString()); EditorGUILayout.LabelField("beginningMinWidth", spline.beginningMinWidth.ToString()); EditorGUILayout.LabelField("beginningMaxWidth", spline.beginningMaxWidth.ToString()); EditorGUILayout.LabelField("minMaxWidth", spline.minMaxWidth.ToString()); EditorGUILayout.LabelField("uvBeginning", spline.uvBeginning.ToString()); EditorGUILayout.LabelField("uvWidth", spline.uvWidth.ToString()); if (GUILayout.Button(new GUIContent("Regenerate spline", "Racalculates whole mesh"))) { spline.GenerateSpline(); } } void AddPointAtEnd() { if (GUILayout.Button("Add point at end")) { int i = spline.controlPoints.Count - 1; Vector4 position = Vector3.zero; position.w = spline.width; if (i < spline.controlPoints.Count - 1 && spline.controlPoints.Count > i + 1) { position = spline.controlPoints[i]; Vector4 positionSecond = spline.controlPoints[i + 1]; if (Vector3.Distance((Vector3)positionSecond, (Vector3)position) > 0) position = (position + positionSecond) * 0.5f; else position.x += 1; } else if (spline.controlPoints.Count > 1 && i == spline.controlPoints.Count - 1) { position = spline.controlPoints[i]; Vector4 positionSecond = spline.controlPoints[i - 1]; if (Vector3.Distance((Vector3)positionSecond, (Vector3)position) > 0) position = position + (position - positionSecond); else position.x += 1; } else if (spline.controlPoints.Count > 0) { position = spline.controlPoints[i]; position.x += 1; } spline.controlPointsRotations.Add(Quaternion.identity); spline.controlPoints.Add(position); spline.controlPointsSnap.Add(0); spline.controlPointsMeshCurves.Add(new AnimationCurve(new Keyframe[] { new Keyframe (0, 0), new Keyframe (1, 0) })); spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } } void SplitRiver(int pointID) { if (pointID < 0 || pointID >= spline.controlPoints.Count) return; Undo.RecordObject(spline, "Split river"); List ramFirstPoints = new List(); List ramSecondPoints = new List(); for (int i = 0; i < spline.controlPoints.Count; i++) { if (i <= pointID) { ramFirstPoints.Add(spline.controlPoints[i]); } if (i >= pointID) { ramSecondPoints.Add(spline.controlPoints[i]); } } MeshRenderer ren = spline.GetComponent(); RamSpline ramFirst = RamSpline.CreateSpline(ren.sharedMaterial, ramFirstPoints, spline.name + "_1"); RamSpline ramSecond = RamSpline.CreateSpline(ren.sharedMaterial, ramSecondPoints, spline.name + "_2"); if (spline.currentProfile != null) { ramFirst.currentProfile = spline.currentProfile; ramFirst.oldProfile = ramFirst.currentProfile; ramSecond.currentProfile = spline.currentProfile; ramSecond.oldProfile = ramSecond.currentProfile; } // ramFirst.meshCurve = new AnimationCurve(spline.meshCurve.keys); ramFirst.flowFlat = new AnimationCurve(spline.flowFlat.keys); ramFirst.flowWaterfall = new AnimationCurve(spline.flowWaterfall.keys); ramFirst.terrainCarve = new AnimationCurve(spline.terrainCarve.keys); ramFirst.terrainPaintCarve = new AnimationCurve(spline.terrainPaintCarve.keys); for (int i = 0; i < ramFirst.controlPointsMeshCurves.Count; i++) { ramFirst.controlPointsMeshCurves[i] = new AnimationCurve(spline.meshCurve.keys); } ramFirst.minVal = spline.minVal; ramFirst.maxVal = spline.maxVal; ramFirst.traingleDensity = spline.traingleDensity; ramFirst.vertsInShape = spline.vertsInShape; ramFirst.uvScale = spline.uvScale; ramFirst.uvRotation = spline.uvRotation; ramFirst.noiseflowMap = spline.noiseflowMap; ramFirst.noiseMultiplierflowMap = spline.noiseMultiplierflowMap; ramFirst.noiseSizeXflowMap = spline.noiseSizeXflowMap; ramFirst.noiseSizeZflowMap = spline.noiseSizeZflowMap; ramFirst.floatSpeed = spline.floatSpeed; ramFirst.distSmooth = spline.distSmooth; ramFirst.distSmoothStart = spline.distSmoothStart; ramFirst.noiseCarve = spline.noiseCarve; ramFirst.noiseMultiplierInside = spline.noiseMultiplierInside; ramFirst.noiseMultiplierOutside = spline.noiseMultiplierOutside; ramFirst.noiseSizeX = spline.noiseSizeX; ramFirst.noiseSizeZ = spline.noiseSizeZ; ramFirst.terrainSmoothMultiplier = spline.terrainSmoothMultiplier; ramFirst.currentSplatMap = spline.currentSplatMap; ramFirst.mixTwoSplatMaps = spline.mixTwoSplatMaps; ramFirst.secondSplatMap = spline.secondSplatMap; ramFirst.addCliffSplatMap = spline.addCliffSplatMap; ramFirst.cliffSplatMap = spline.cliffSplatMap; ramFirst.cliffAngle = spline.cliffAngle; ramFirst.cliffBlend = spline.cliffBlend; ramFirst.cliffSplatMapOutside = spline.cliffSplatMapOutside; ramFirst.cliffAngleOutside = spline.cliffAngleOutside; ramFirst.cliffBlendOutside = spline.cliffBlendOutside; ramFirst.distanceClearFoliage = spline.distanceClearFoliage; ramFirst.distanceClearFoliageTrees = spline.distanceClearFoliageTrees; ramFirst.noisePaint = spline.noisePaint; ramFirst.noiseMultiplierInsidePaint = spline.noiseMultiplierInsidePaint; ramFirst.noiseMultiplierOutsidePaint = spline.noiseMultiplierOutsidePaint; ramFirst.noiseSizeXPaint = spline.noiseSizeXPaint; ramFirst.noiseSizeZPaint = spline.noiseSizeZPaint; ramFirst.simulatedRiverLength = spline.simulatedRiverLength; ramFirst.simulatedRiverPoints = spline.simulatedRiverPoints; ramFirst.simulatedMinStepSize = spline.simulatedMinStepSize; ramFirst.simulatedNoUp = spline.simulatedNoUp; ramFirst.simulatedBreakOnUp = spline.simulatedBreakOnUp; ramFirst.noiseWidth = spline.noiseWidth; ramFirst.noiseMultiplierWidth = spline.noiseMultiplierWidth; ramFirst.noiseSizeWidth = spline.noiseSizeWidth; ramFirst.receiveShadows = spline.receiveShadows; ramFirst.shadowCastingMode = spline.shadowCastingMode; ramSecond.meshCurve = new AnimationCurve(spline.meshCurve.keys); ramSecond.flowFlat = new AnimationCurve(spline.flowFlat.keys); ramSecond.flowWaterfall = new AnimationCurve(spline.flowWaterfall.keys); ramSecond.terrainCarve = new AnimationCurve(spline.terrainCarve.keys); ramSecond.terrainPaintCarve = new AnimationCurve(spline.terrainPaintCarve.keys); for (int i = 0; i < ramSecond.controlPointsMeshCurves.Count; i++) { ramSecond.controlPointsMeshCurves[i] = new AnimationCurve(spline.meshCurve.keys); } ramSecond.minVal = spline.minVal; ramSecond.maxVal = spline.maxVal; ramSecond.traingleDensity = spline.traingleDensity; ramSecond.vertsInShape = spline.vertsInShape; ramSecond.uvScale = spline.uvScale; ramSecond.uvRotation = spline.uvRotation; ramSecond.noiseflowMap = spline.noiseflowMap; ramSecond.noiseMultiplierflowMap = spline.noiseMultiplierflowMap; ramSecond.noiseSizeXflowMap = spline.noiseSizeXflowMap; ramSecond.noiseSizeZflowMap = spline.noiseSizeZflowMap; ramSecond.floatSpeed = spline.floatSpeed; ramSecond.distSmooth = spline.distSmooth; ramSecond.distSmoothStart = spline.distSmoothStart; ramSecond.noiseCarve = spline.noiseCarve; ramSecond.noiseMultiplierInside = spline.noiseMultiplierInside; ramSecond.noiseMultiplierOutside = spline.noiseMultiplierOutside; ramSecond.noiseSizeX = spline.noiseSizeX; ramSecond.noiseSizeZ = spline.noiseSizeZ; ramSecond.terrainSmoothMultiplier = spline.terrainSmoothMultiplier; ramSecond.currentSplatMap = spline.currentSplatMap; ramSecond.mixTwoSplatMaps = spline.mixTwoSplatMaps; ramSecond.secondSplatMap = spline.secondSplatMap; ramSecond.addCliffSplatMap = spline.addCliffSplatMap; ramSecond.cliffSplatMap = spline.cliffSplatMap; ramSecond.cliffAngle = spline.cliffAngle; ramSecond.cliffBlend = spline.cliffBlend; ramSecond.cliffSplatMapOutside = spline.cliffSplatMapOutside; ramSecond.cliffAngleOutside = spline.cliffAngleOutside; ramSecond.cliffBlendOutside = spline.cliffBlendOutside; ramSecond.distanceClearFoliage = spline.distanceClearFoliage; ramSecond.distanceClearFoliageTrees = spline.distanceClearFoliageTrees; ramSecond.noisePaint = spline.noisePaint; ramSecond.noiseMultiplierInsidePaint = spline.noiseMultiplierInsidePaint; ramSecond.noiseMultiplierOutsidePaint = spline.noiseMultiplierOutsidePaint; ramSecond.noiseSizeXPaint = spline.noiseSizeXPaint; ramSecond.noiseSizeZPaint = spline.noiseSizeZPaint; ramSecond.simulatedRiverLength = spline.simulatedRiverLength; ramSecond.simulatedRiverPoints = spline.simulatedRiverPoints; ramSecond.simulatedMinStepSize = spline.simulatedMinStepSize; ramSecond.simulatedNoUp = spline.simulatedNoUp; ramSecond.simulatedBreakOnUp = spline.simulatedBreakOnUp; ramSecond.noiseWidth = spline.noiseWidth; ramSecond.noiseMultiplierWidth = spline.noiseMultiplierWidth; ramSecond.noiseSizeWidth = spline.noiseSizeWidth; ramSecond.receiveShadows = spline.receiveShadows; ramSecond.shadowCastingMode = spline.shadowCastingMode; // ramFirst.endingSpline = ramSecond; ramFirst.endingMinWidth = 0; ramFirst.endingMaxWidth = 1; ramSecond.GenerateSpline(); ramFirst.GenerateSpline(); ramFirst.transform.position = spline.transform.position; ramSecond.transform.position = spline.transform.position; Undo.DestroyObjectImmediate(spline.gameObject); } void MeshSettings() { GUILayout.Label("Mesh settings:", EditorStyles.boldLabel); EditorGUI.indentLevel++; spline.currentProfile = (SplineProfile)EditorGUILayout.ObjectField("Spline profile", spline.currentProfile, typeof(SplineProfile), false); if (GUILayout.Button("Create profile from settings")) { SplineProfile asset = ScriptableObject.CreateInstance(); //asset.meshCurve = spline.meshCurve; asset.meshCurve = new AnimationCurve(spline.meshCurve.keys); asset.flowFlat = new AnimationCurve(spline.flowFlat.keys); asset.flowWaterfall = new AnimationCurve(spline.flowWaterfall.keys); asset.terrainCarve = new AnimationCurve(spline.terrainCarve.keys); asset.terrainPaintCarve = new AnimationCurve(spline.terrainPaintCarve.keys); MeshRenderer ren = spline.GetComponent(); asset.splineMaterial = ren.sharedMaterial; asset.minVal = spline.minVal; asset.maxVal = spline.maxVal; asset.traingleDensity = spline.traingleDensity; asset.vertsInShape = spline.vertsInShape; asset.uvScale = spline.uvScale; asset.uvRotation = spline.uvRotation; //asset.flowFlat = spline.flowFlat; //asset.flowWaterfall = spline.flowWaterfall; asset.noiseflowMap = spline.noiseflowMap; asset.noiseMultiplierflowMap = spline.noiseMultiplierflowMap; asset.noiseSizeXflowMap = spline.noiseSizeXflowMap; asset.noiseSizeZflowMap = spline.noiseSizeZflowMap; asset.floatSpeed = spline.floatSpeed; // asset.terrainCarve = spline.terrainCarve; asset.distSmooth = spline.distSmooth; asset.distSmoothStart = spline.distSmoothStart; // asset.terrainPaintCarve = spline.terrainPaintCarve; asset.noiseCarve = spline.noiseCarve; asset.noiseMultiplierInside = spline.noiseMultiplierInside; asset.noiseMultiplierOutside = spline.noiseMultiplierOutside; asset.noiseSizeX = spline.noiseSizeX; asset.noiseSizeZ = spline.noiseSizeZ; asset.terrainSmoothMultiplier = spline.terrainSmoothMultiplier; asset.currentSplatMap = spline.currentSplatMap; asset.mixTwoSplatMaps = spline.mixTwoSplatMaps; asset.secondSplatMap = spline.secondSplatMap; asset.addCliffSplatMap = spline.addCliffSplatMap; asset.cliffSplatMap = spline.cliffSplatMap; asset.cliffAngle = spline.cliffAngle; asset.cliffBlend = spline.cliffBlend; asset.cliffSplatMapOutside = spline.cliffSplatMapOutside; asset.cliffAngleOutside = spline.cliffAngleOutside; asset.cliffBlendOutside = spline.cliffBlendOutside; asset.distanceClearFoliage = spline.distanceClearFoliage; asset.distanceClearFoliageTrees = spline.distanceClearFoliageTrees; asset.noisePaint = spline.noisePaint; asset.noiseMultiplierInsidePaint = spline.noiseMultiplierInsidePaint; asset.noiseMultiplierOutsidePaint = spline.noiseMultiplierOutsidePaint; asset.noiseSizeXPaint = spline.noiseSizeXPaint; asset.noiseSizeZPaint = spline.noiseSizeZPaint; asset.simulatedRiverLength = spline.simulatedRiverLength; asset.simulatedRiverPoints = spline.simulatedRiverPoints; asset.simulatedMinStepSize = spline.simulatedMinStepSize; asset.simulatedNoUp = spline.simulatedNoUp; asset.simulatedBreakOnUp = spline.simulatedBreakOnUp; asset.noiseWidth = spline.noiseWidth; asset.noiseMultiplierWidth = spline.noiseMultiplierWidth; asset.noiseSizeWidth = spline.noiseSizeWidth; asset.receiveShadows = spline.receiveShadows; asset.shadowCastingMode = spline.shadowCastingMode; string path = EditorUtility.SaveFilePanelInProject("Save new spline profile", spline.gameObject.name + ".asset", "asset", "Please enter a file name to save the spline profile to"); if (!string.IsNullOrEmpty(path)) { AssetDatabase.CreateAsset(asset, path); AssetDatabase.SaveAssets(); spline.currentProfile = asset; } } if (spline.currentProfile != null && GUILayout.Button("Save profile from settings")) { //spline.currentProfile.meshCurve = spline.meshCurve; MeshRenderer ren = spline.GetComponent(); spline.currentProfile.splineMaterial = ren.sharedMaterial; spline.currentProfile.minVal = spline.minVal; spline.currentProfile.maxVal = spline.maxVal; spline.currentProfile.meshCurve = new AnimationCurve(spline.meshCurve.keys); spline.currentProfile.flowFlat = new AnimationCurve(spline.flowFlat.keys); spline.currentProfile.flowWaterfall = new AnimationCurve(spline.flowWaterfall.keys); spline.currentProfile.terrainCarve = new AnimationCurve(spline.terrainCarve.keys); spline.currentProfile.terrainPaintCarve = new AnimationCurve(spline.terrainPaintCarve.keys); spline.currentProfile.traingleDensity = spline.traingleDensity; spline.currentProfile.vertsInShape = spline.vertsInShape; spline.currentProfile.uvScale = spline.uvScale; spline.currentProfile.uvRotation = spline.uvRotation; // spline.currentProfile.flowFlat = spline.flowFlat; //spline.currentProfile.flowWaterfall = spline.flowWaterfall; spline.currentProfile.noiseflowMap = spline.noiseflowMap; spline.currentProfile.noiseMultiplierflowMap = spline.noiseMultiplierflowMap; spline.currentProfile.noiseSizeXflowMap = spline.noiseSizeXflowMap; spline.currentProfile.noiseSizeZflowMap = spline.noiseSizeZflowMap; spline.currentProfile.floatSpeed = spline.floatSpeed; //spline.currentProfile.terrainCarve = spline.terrainCarve; spline.currentProfile.distSmooth = spline.distSmooth; spline.currentProfile.distSmoothStart = spline.distSmoothStart; spline.currentProfile.maskCarve = spline.maskCarve; //spline.currentProfile.terrainPaintCarve = spline.terrainPaintCarve; spline.currentProfile.noiseCarve = spline.noiseCarve; spline.currentProfile.noiseMultiplierInside = spline.noiseMultiplierInside; spline.currentProfile.noiseMultiplierOutside = spline.noiseMultiplierOutside; spline.currentProfile.noiseSizeX = spline.noiseSizeX; spline.currentProfile.noiseSizeZ = spline.noiseSizeZ; spline.currentProfile.terrainSmoothMultiplier = spline.terrainSmoothMultiplier; spline.currentProfile.currentSplatMap = spline.currentSplatMap; spline.currentProfile.mixTwoSplatMaps = spline.mixTwoSplatMaps; spline.currentProfile.secondSplatMap = spline.secondSplatMap; spline.currentProfile.addCliffSplatMap = spline.addCliffSplatMap; spline.currentProfile.cliffSplatMap = spline.cliffSplatMap; spline.currentProfile.cliffAngle = spline.cliffAngle; spline.currentProfile.cliffBlend = spline.cliffBlend; spline.currentProfile.cliffSplatMapOutside = spline.cliffSplatMapOutside; spline.currentProfile.cliffAngleOutside = spline.cliffAngleOutside; spline.currentProfile.cliffBlendOutside = spline.cliffBlendOutside; spline.currentProfile.distanceClearFoliage = spline.distanceClearFoliage; spline.currentProfile.distanceClearFoliageTrees = spline.distanceClearFoliageTrees; spline.currentProfile.noisePaint = spline.noisePaint; spline.currentProfile.noiseMultiplierInsidePaint = spline.noiseMultiplierInsidePaint; spline.currentProfile.noiseMultiplierOutsidePaint = spline.noiseMultiplierOutsidePaint; spline.currentProfile.noiseSizeXPaint = spline.noiseSizeXPaint; spline.currentProfile.noiseSizeZPaint = spline.noiseSizeZPaint; spline.currentProfile.simulatedRiverLength = spline.simulatedRiverLength; spline.currentProfile.simulatedRiverPoints = spline.simulatedRiverPoints; spline.currentProfile.simulatedMinStepSize = spline.simulatedMinStepSize; spline.currentProfile.simulatedNoUp = spline.simulatedNoUp; spline.currentProfile.simulatedBreakOnUp = spline.simulatedBreakOnUp; spline.currentProfile.noiseWidth = spline.noiseWidth; spline.currentProfile.noiseMultiplierWidth = spline.noiseMultiplierWidth; spline.currentProfile.noiseSizeWidth = spline.noiseSizeWidth; spline.currentProfile.receiveShadows = spline.receiveShadows; spline.currentProfile.shadowCastingMode = spline.shadowCastingMode; AssetDatabase.SaveAssets(); } if (spline.currentProfile != null && spline.currentProfile != spline.oldProfile) { ResetToProfile(); EditorUtility.SetDirty(spline); } bool profileChanged = CheckProfileChange(); if (spline.currentProfile != null && GUILayout.Button("Reset to profile" + (profileChanged ? " (Profile data changed)" : ""))) { ResetToProfile(); } EditorGUILayout.Space(); string meshResolution = "Triangles density"; if (spline.meshfilter != null && spline.meshfilter.sharedMesh != null) { float tris = spline.meshfilter.sharedMesh.triangles.Length / 3; meshResolution += " (" + tris + " tris)"; } else if (spline.meshfilter != null && spline.meshfilter.sharedMesh == null) { spline.GenerateSpline(); } EditorGUILayout.LabelField(meshResolution); EditorGUI.indentLevel++; spline.traingleDensity = 1 / (float)EditorGUILayout.IntSlider("U", (int)(1 / (float)spline.traingleDensity), 1, 100); if (spline.beginningSpline == null && spline.endingSpline == null) { spline.vertsInShape = EditorGUILayout.IntSlider("V", spline.vertsInShape - 1, 1, 20) + 1; } else { GUI.enabled = false; if (spline.beginningSpline != null) { spline.vertsInShape = (int)Mathf.Round((spline.beginningSpline.vertsInShape - 1) * (spline.beginningMaxWidth - spline.beginningMinWidth) + 1); } else if (spline.endingSpline != null) spline.vertsInShape = (int)Mathf.Round((spline.endingSpline.vertsInShape - 1) * (spline.endingMaxWidth - spline.endingMinWidth) + 1); EditorGUILayout.IntSlider("V", spline.vertsInShape - 1, 1, 20); GUI.enabled = true; } EditorGUI.indentLevel--; EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); { spline.width = EditorGUILayout.FloatField("River width", spline.width); if (GUILayout.Button("Change width for whole river")) { if (spline.width > 0) { for (int i = 0; i < spline.controlPoints.Count; i++) { Vector4 point = spline.controlPoints[i]; point.w = spline.width; spline.controlPoints[i] = point; } spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } } } EditorGUILayout.EndHorizontal(); EditorGUI.indentLevel++; spline.noiseWidth = EditorGUILayout.Toggle("Add width noise", spline.noiseWidth); if (spline.noiseWidth) { EditorGUI.indentLevel++; spline.noiseMultiplierWidth = EditorGUILayout.FloatField("Noise Multiplier Width", spline.noiseMultiplierWidth); spline.noiseSizeWidth = EditorGUILayout.FloatField("Noise scale Width", spline.noiseSizeWidth); EditorGUI.indentLevel--; if (GUILayout.Button("Add noise to width for whole river")) { Undo.RecordObject(spline, "Change widths"); spline.AddNoiseToWidths(); spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } } EditorGUI.indentLevel--; EditorGUILayout.Space(); spline.meshCurve = EditorGUILayout.CurveField("Mesh curve", spline.meshCurve); if (GUILayout.Button("Set all mesh curves")) { for (int i = 0; i < spline.controlPointsMeshCurves.Count; i++) { spline.controlPointsMeshCurves[i] = new AnimationCurve(spline.meshCurve.keys); } } EditorGUILayout.Space(); EditorGUILayout.LabelField("Vertice distribution: " + spline.minVal.ToString() + " " + spline.maxVal.ToString()); EditorGUILayout.MinMaxSlider(ref spline.minVal, ref spline.maxVal, 0, 1); //Debug.Log (spline.minVal + " " + spline.maxVal); spline.minVal = (int)(spline.minVal * 100) * 0.01f; spline.maxVal = (int)(spline.maxVal * 100) * 0.01f; if (spline.minVal > 0.5f) spline.minVal = 0.5f; if (spline.minVal < 0.01f) spline.minVal = 0.01f; if (spline.maxVal < 0.5f) spline.maxVal = 0.5f; if (spline.maxVal > 0.99f) spline.maxVal = 0.99f; EditorGUILayout.Space(); if (GUILayout.Button("Snap/Unsnap mesh to terrain")) { spline.snapToTerrain = !spline.snapToTerrain; for (int i = 0; i < spline.controlPointsSnap.Count; i++) { spline.controlPointsSnap[i] = spline.snapToTerrain == true ? 1 : 0; } } ///spline.snapMask = EditorGUILayout.MaskField ("Layers", spline.snapMask, InternalEditorUtility.layers); spline.snapMask = LayerMaskField("Layers", spline.snapMask, true); spline.normalFromRaycast = EditorGUILayout.Toggle("Take Normal from terrain", spline.normalFromRaycast); EditorGUILayout.Space(); } bool CheckProfileChange() { if (spline.currentProfile == null) return false; //if (ren.material != spline.currentProfile.splineMaterial) // return true; if (spline.minVal != spline.currentProfile.minVal) return true; if (spline.maxVal != spline.currentProfile.maxVal) return true; if (spline.traingleDensity != spline.currentProfile.traingleDensity) return true; if (spline.vertsInShape != spline.currentProfile.vertsInShape) return true; if (spline.uvScale != spline.currentProfile.uvScale) return true; if (spline.uvRotation != spline.currentProfile.uvRotation) return true; // if (spline.flowFlat != spline.currentProfile.flowFlat) // return true; // if (spline.flowWaterfall != spline.currentProfile.flowWaterfall) // return true; if (spline.noiseflowMap != spline.currentProfile.noiseflowMap) return true; if (spline.noiseMultiplierflowMap != spline.currentProfile.noiseMultiplierflowMap) return true; if (spline.noiseSizeXflowMap != spline.currentProfile.noiseSizeXflowMap) return true; if (spline.noiseSizeZflowMap != spline.currentProfile.noiseSizeZflowMap) return true; if (spline.floatSpeed != spline.currentProfile.floatSpeed) return true; // if (spline.terrainCarve != spline.currentProfile.terrainCarve) // return true; if (spline.distSmooth != spline.currentProfile.distSmooth) return true; if (spline.distSmoothStart != spline.currentProfile.distSmoothStart) return true; if (spline.maskCarve != spline.currentProfile.maskCarve) return true; // if (spline.terrainPaintCarve != spline.currentProfile.terrainPaintCarve) // return true; if (spline.currentProfile.noiseCarve != spline.noiseCarve) return true; if (spline.currentProfile.noiseMultiplierInside != spline.noiseMultiplierInside) return true; if (spline.currentProfile.noiseMultiplierOutside != spline.noiseMultiplierOutside) return true; if (spline.currentProfile.noiseSizeX != spline.noiseSizeX) return true; if (spline.currentProfile.noiseSizeZ != spline.noiseSizeZ) return true; if (spline.currentProfile.terrainSmoothMultiplier != spline.terrainSmoothMultiplier) return true; if (spline.currentProfile.currentSplatMap != spline.currentSplatMap) return true; if (spline.currentProfile.mixTwoSplatMaps != spline.mixTwoSplatMaps) return true; if (spline.currentProfile.secondSplatMap != spline.secondSplatMap) return true; if (spline.currentProfile.addCliffSplatMap != spline.addCliffSplatMap) return true; if (spline.currentProfile.cliffSplatMap != spline.cliffSplatMap) return true; if (spline.currentProfile.cliffAngle != spline.cliffAngle) return true; if (spline.currentProfile.cliffBlend != spline.cliffBlend) return true; if (spline.currentProfile.cliffSplatMapOutside != spline.cliffSplatMapOutside) return true; if (spline.currentProfile.cliffAngleOutside != spline.cliffAngleOutside) return true; if (spline.currentProfile.cliffBlendOutside != spline.cliffBlendOutside) return true; if (spline.currentProfile.distanceClearFoliage != spline.distanceClearFoliage) return true; if (spline.currentProfile.distanceClearFoliageTrees != spline.distanceClearFoliageTrees) return true; if (spline.currentProfile.noisePaint != spline.noisePaint) return true; if (spline.currentProfile.noiseMultiplierInsidePaint != spline.noiseMultiplierInsidePaint) return true; if (spline.currentProfile.noiseMultiplierOutsidePaint != spline.noiseMultiplierOutsidePaint) return true; if (spline.currentProfile.noiseSizeXPaint != spline.noiseSizeXPaint) return true; if (spline.currentProfile.noiseSizeZPaint != spline.noiseSizeZPaint) return true; if (spline.currentProfile.simulatedRiverLength != spline.simulatedRiverLength) return true; if (spline.currentProfile.simulatedRiverPoints != spline.simulatedRiverPoints) return true; if (spline.currentProfile.simulatedMinStepSize != spline.simulatedMinStepSize) return true; if (spline.currentProfile.simulatedNoUp != spline.simulatedNoUp) return true; if (spline.currentProfile.simulatedBreakOnUp != spline.simulatedBreakOnUp) return true; if (spline.currentProfile.noiseWidth != spline.noiseWidth) return true; if (spline.currentProfile.noiseMultiplierWidth != spline.noiseMultiplierWidth) return true; if (spline.currentProfile.noiseSizeWidth != spline.noiseSizeWidth) return true; if (spline.receiveShadows != spline.currentProfile.receiveShadows) return true; if (spline.shadowCastingMode != spline.currentProfile.shadowCastingMode) return true; return false; } public void ResetToProfile() { if (spline == null) spline = (RamSpline)target; //spline.meshCurve = spline.currentProfile.meshCurve; spline.meshCurve = new AnimationCurve(spline.currentProfile.meshCurve.keys); spline.flowFlat = new AnimationCurve(spline.currentProfile.flowFlat.keys); spline.flowWaterfall = new AnimationCurve(spline.currentProfile.flowWaterfall.keys); spline.terrainCarve = new AnimationCurve(spline.currentProfile.terrainCarve.keys); spline.terrainPaintCarve = new AnimationCurve(spline.currentProfile.terrainPaintCarve.keys); for (int i = 0; i < spline.controlPointsMeshCurves.Count; i++) { spline.controlPointsMeshCurves[i] = new AnimationCurve(spline.meshCurve.keys); } MeshRenderer ren = spline.GetComponent(); ren.sharedMaterial = spline.currentProfile.splineMaterial; spline.minVal = spline.currentProfile.minVal; spline.maxVal = spline.currentProfile.maxVal; spline.traingleDensity = spline.currentProfile.traingleDensity; spline.vertsInShape = spline.currentProfile.vertsInShape; spline.uvScale = spline.currentProfile.uvScale; spline.uvRotation = spline.currentProfile.uvRotation; //spline.flowFlat = spline.currentProfile.flowFlat; //spline.flowWaterfall = spline.currentProfile.flowWaterfall; spline.noiseflowMap = spline.currentProfile.noiseflowMap; spline.noiseMultiplierflowMap = spline.currentProfile.noiseMultiplierflowMap; spline.noiseSizeXflowMap = spline.currentProfile.noiseSizeXflowMap; spline.noiseSizeZflowMap = spline.currentProfile.noiseSizeZflowMap; spline.floatSpeed = spline.currentProfile.floatSpeed; //spline.terrainCarve = spline.currentProfile.terrainCarve; spline.distSmooth = spline.currentProfile.distSmooth; spline.distSmoothStart = spline.currentProfile.distSmoothStart; spline.maskCarve = spline.currentProfile.maskCarve; //spline.terrainPaintCarve = spline.currentProfile.terrainPaintCarve; spline.noiseCarve = spline.currentProfile.noiseCarve; spline.noiseMultiplierInside = spline.currentProfile.noiseMultiplierInside; spline.noiseMultiplierOutside = spline.currentProfile.noiseMultiplierOutside; spline.noiseSizeX = spline.currentProfile.noiseSizeX; spline.noiseSizeZ = spline.currentProfile.noiseSizeZ; spline.terrainSmoothMultiplier = spline.currentProfile.terrainSmoothMultiplier; spline.currentSplatMap = spline.currentProfile.currentSplatMap; spline.mixTwoSplatMaps = spline.currentProfile.mixTwoSplatMaps; spline.secondSplatMap = spline.currentProfile.secondSplatMap; spline.addCliffSplatMap = spline.currentProfile.addCliffSplatMap; spline.cliffSplatMap = spline.currentProfile.cliffSplatMap; spline.cliffAngle = spline.currentProfile.cliffAngle; spline.cliffBlend = spline.currentProfile.cliffBlend; spline.cliffSplatMapOutside = spline.currentProfile.cliffSplatMapOutside; spline.cliffAngleOutside = spline.currentProfile.cliffAngleOutside; spline.cliffBlendOutside = spline.currentProfile.cliffBlendOutside; spline.distanceClearFoliage = spline.currentProfile.distanceClearFoliage; spline.distanceClearFoliageTrees = spline.currentProfile.distanceClearFoliageTrees; spline.noisePaint = spline.currentProfile.noisePaint; spline.noiseMultiplierInsidePaint = spline.currentProfile.noiseMultiplierInsidePaint; spline.noiseMultiplierOutsidePaint = spline.currentProfile.noiseMultiplierOutsidePaint; spline.noiseSizeXPaint = spline.currentProfile.noiseSizeXPaint; spline.noiseSizeZPaint = spline.currentProfile.noiseSizeZPaint; spline.simulatedRiverLength = spline.currentProfile.simulatedRiverLength; spline.simulatedRiverPoints = spline.currentProfile.simulatedRiverPoints; spline.simulatedMinStepSize = spline.currentProfile.simulatedMinStepSize; spline.simulatedNoUp = spline.currentProfile.simulatedNoUp; spline.simulatedBreakOnUp = spline.currentProfile.simulatedBreakOnUp; spline.noiseWidth = spline.currentProfile.noiseWidth; spline.noiseMultiplierWidth = spline.currentProfile.noiseMultiplierWidth; spline.noiseSizeWidth = spline.currentProfile.noiseSizeWidth; spline.receiveShadows = spline.currentProfile.receiveShadows; spline.shadowCastingMode = spline.currentProfile.shadowCastingMode; spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif spline.oldProfile = spline.currentProfile; } void DrawVertexColorsUI() { spline.drawOnMesh = true; if (spline.drawOnMesh) { EditorGUILayout.HelpBox("R - Slow Water G - Small Cascade B - Big Cascade A - Opacity", MessageType.Info); EditorGUILayout.Space(); spline.drawColor = EditorGUILayout.ColorField("Draw color", spline.drawColor); spline.opacity = EditorGUILayout.FloatField("Opacity", spline.opacity); spline.drawSize = EditorGUILayout.FloatField("Size", spline.drawSize); if (spline.drawSize < 0) { spline.drawSize = 0; } spline.drawColorR = EditorGUILayout.Toggle("Draw R", spline.drawColorR); spline.drawColorG = EditorGUILayout.Toggle("Draw G", spline.drawColorG); spline.drawColorB = EditorGUILayout.Toggle("Draw B", spline.drawColorB); spline.drawColorA = EditorGUILayout.Toggle("Draw A", spline.drawColorA); EditorGUILayout.Space(); spline.drawOnMultiple = EditorGUILayout.Toggle("Draw on multiple rivers", spline.drawOnMultiple); } EditorGUILayout.Space(); if (!spline.showVertexColors) { if (GUILayout.Button("Show vertex colors")) { if (!spline.showFlowMap && !spline.showVertexColors) spline.oldMaterial = spline.GetComponent().sharedMaterial; ResetMaterial(); spline.GetComponent().sharedMaterial = new Material(Shader.Find("NatureManufacture Shaders/Debug/Vertex color")); spline.showVertexColors = true; } } else { if (GUILayout.Button("Hide vertex colors")) { ResetMaterial(); spline.GetComponent().sharedMaterial = spline.oldMaterial; spline.showVertexColors = false; } } if (GUILayout.Button("Reset vertex colors") && EditorUtility.DisplayDialog("Reset vertex colors?", "Are you sure you want to reset f vertex colors?", "Yes", "No")) { spline.colors = null; spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } } void DrawFlowColorsUI() { EditorGUILayout.Space(); EditorGUILayout.HelpBox("Sharp gradient could generate bugged effect. Keep flow changes smooth.", MessageType.Info); GUILayout.Label("Flow Map Manual: ", EditorStyles.boldLabel); spline.drawOnMeshFlowMap = true; if (spline.drawOnMeshFlowMap) { EditorGUILayout.Space(); spline.flowSpeed = EditorGUILayout.Slider("Flow U Speed", spline.flowSpeed, -1, 1); spline.flowDirection = EditorGUILayout.Slider("Flow V Speed", spline.flowDirection, -1, 1); spline.opacity = EditorGUILayout.FloatField("Opacity", spline.opacity); spline.drawSize = EditorGUILayout.FloatField("Size", spline.drawSize); if (spline.drawSize < 0) { spline.drawSize = 0; } EditorGUILayout.Space(); spline.drawOnMultiple = EditorGUILayout.Toggle("Draw on multiple rivers", spline.drawOnMultiple); } EditorGUILayout.Space(); if (!spline.showFlowMap) { if (GUILayout.Button("Show flow directions")) { if (!spline.showFlowMap && !spline.showVertexColors) spline.oldMaterial = spline.GetComponent().sharedMaterial; ResetMaterial(); spline.GetComponent().sharedMaterial = new Material(Shader.Find("NatureManufacture Shaders/Debug/Flowmap Direction")); spline.GetComponent().sharedMaterial.SetTexture("_Direction", Resources.Load("Debug_Arrow")); spline.showFlowMap = true; } if (GUILayout.Button("Show flow smoothness")) { if (!spline.showFlowMap && !spline.showVertexColors) spline.oldMaterial = spline.GetComponent().sharedMaterial; ResetMaterial(); spline.GetComponent().sharedMaterial = new Material(Shader.Find("NatureManufacture Shaders/Debug/FlowMapUV4")); spline.showFlowMap = true; } } if (spline.showFlowMap) { if (GUILayout.Button("Hide flow")) { ResetMaterial(); spline.GetComponent().sharedMaterial = spline.oldMaterial; } } EditorGUILayout.Space(); GUILayout.Label("Flow Map Automatic: ", EditorStyles.boldLabel); spline.flowFlat = EditorGUILayout.CurveField("Flow curve flat speed", spline.flowFlat); spline.flowWaterfall = EditorGUILayout.CurveField("Flow curve waterfall speed", spline.flowWaterfall); spline.noiseflowMap = EditorGUILayout.Toggle("Add noise", spline.noiseflowMap); if (spline.noiseflowMap) { EditorGUI.indentLevel++; spline.noiseMultiplierflowMap = EditorGUILayout.FloatField("Noise multiplier inside", spline.noiseMultiplierflowMap); spline.noiseSizeXflowMap = EditorGUILayout.FloatField("Noise scale X", spline.noiseSizeXflowMap); spline.noiseSizeZflowMap = EditorGUILayout.FloatField("Noise scale Z", spline.noiseSizeZflowMap); EditorGUI.indentLevel--; } EditorGUILayout.Space(); if (GUILayout.Button("Reset flow to automatic") && EditorUtility.DisplayDialog("Reset flow to automatic?", "Are you sure you want to reset flow to automatic?", "Yes", "No")) { spline.overrideFlowMap = false; spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } EditorGUILayout.Space(); GUILayout.Label("Flow Map Physic: ", EditorStyles.boldLabel); spline.floatSpeed = EditorGUILayout.FloatField("River float speed", spline.floatSpeed); } void ResetMaterial() { //if (spline.oldMaterial != null) // spline.GetComponent ().sharedMaterial = spline.oldMaterial; spline.showFlowMap = false; spline.showVertexColors = false; } void FilesManager() { if (GUILayout.Button("Save points to csv file")) { PointsToFile(); } if (GUILayout.Button("Load points from csv file")) { PointsFromFile(); } } void Tips() { EditorGUILayout.Space(); EditorGUILayout.HelpBox("\nReflections - Use box projection in reflection probes to get proper render even at multiple river conection.\n", MessageType.Info); EditorGUILayout.HelpBox("\nKeep resonable quasi- square vertex shapes at river mesh, " + "this will give better tesselation result. Don't worry about low amount of poly, tesselation will smooth shapes.\n", MessageType.Info); EditorGUILayout.HelpBox("\nBy rotating point you could get simmilar effect as vertex color painting.\n" + "You could adjust waterfalls or add noise in the river. " + "Note that if rotation will be bigger then +/- 90 degree you could invert normals.\n", MessageType.Info); EditorGUILayout.HelpBox("\nUse low resolution reflection probes, and only around the water. " + "\nFar clip planes also should be short, you probably only need colors from the surounding world.\n", MessageType.Info); EditorGUILayout.HelpBox("\nPut reflection probes behind, in and after dark area (tunel, cave) so you will get exelent result in lighting and reflections.\n", MessageType.Info); EditorGUILayout.HelpBox("\nTry to keep quite simmilar distance between spline points. Huge distance between them could create strange result.\n", MessageType.Info); EditorGUILayout.HelpBox("\nWhen you use multiple connected rivers, you shoud put reflection probe at fork of the rivers to keep proper reflections\n", MessageType.Info); EditorGUILayout.Space(); } void ParentingSplineUI() { GUILayout.Label("Rivers connections", EditorStyles.boldLabel); spline.beginningSpline = (RamSpline)EditorGUILayout.ObjectField("Beginning spline", spline.beginningSpline, typeof(RamSpline), true); if (spline.beginningSpline == spline) spline.beginningSpline = null; spline.endingSpline = (RamSpline)EditorGUILayout.ObjectField("Ending spline", spline.endingSpline, typeof(RamSpline), true); if (spline.endingSpline == spline) spline.endingSpline = null; if (spline.beginningSpline != null) { if (spline.controlPoints.Count > 0 && spline.beginningSpline.points.Count > 0) { spline.beginningMinWidth = spline.beginningMinWidth * (spline.beginningSpline.vertsInShape - 1); spline.beginningMaxWidth = spline.beginningMaxWidth * (spline.beginningSpline.vertsInShape - 1); EditorGUILayout.MinMaxSlider("Part parent", ref spline.beginningMinWidth, ref spline.beginningMaxWidth, 0, spline.beginningSpline.vertsInShape - 1); spline.beginningMinWidth = (int)spline.beginningMinWidth; spline.beginningMaxWidth = (int)spline.beginningMaxWidth; spline.beginningMinWidth = Mathf.Clamp(spline.beginningMinWidth, 0, spline.beginningSpline.vertsInShape - 1); spline.beginningMaxWidth = Mathf.Clamp(spline.beginningMaxWidth, 0, spline.beginningSpline.vertsInShape - 1); if (spline.beginningMinWidth == spline.beginningMaxWidth) { if (spline.beginningMinWidth > 0) spline.beginningMinWidth--; else spline.beginningMaxWidth++; } spline.vertsInShape = (int)(spline.beginningMaxWidth - spline.beginningMinWidth) + 1; spline.beginningMinWidth = spline.beginningMinWidth / (float)(spline.beginningSpline.vertsInShape - 1); spline.beginningMaxWidth = spline.beginningMaxWidth / (float)(spline.beginningSpline.vertsInShape - 1); spline.GenerateBeginningParentBased(); } } else { spline.beginningMaxWidth = 1; spline.beginningMinWidth = 0; } if (spline.endingSpline != null) { if (spline.controlPoints.Count > 1 && spline.endingSpline.points.Count > 0) { spline.endingMinWidth = spline.endingMinWidth * (spline.endingSpline.vertsInShape - 1); spline.endingMaxWidth = spline.endingMaxWidth * (spline.endingSpline.vertsInShape - 1); EditorGUILayout.MinMaxSlider("Part parent", ref spline.endingMinWidth, ref spline.endingMaxWidth, 0, spline.endingSpline.vertsInShape - 1); spline.endingMinWidth = (int)spline.endingMinWidth; spline.endingMaxWidth = (int)spline.endingMaxWidth; spline.endingMinWidth = Mathf.Clamp(spline.endingMinWidth, 0, spline.endingSpline.vertsInShape - 1); spline.endingMaxWidth = Mathf.Clamp(spline.endingMaxWidth, 0, spline.endingSpline.vertsInShape - 1); if (spline.endingMinWidth == spline.endingMaxWidth) { if (spline.endingMinWidth > 0) spline.endingMinWidth--; else spline.endingMaxWidth++; } spline.vertsInShape = (int)(spline.endingMaxWidth - spline.endingMinWidth) + 1; spline.endingMinWidth = spline.endingMinWidth / (float)(spline.endingSpline.vertsInShape - 1); spline.endingMaxWidth = spline.endingMaxWidth / (float)(spline.endingSpline.vertsInShape - 1); spline.GenerateEndingParentBased(); } } else { spline.endingMaxWidth = 1; spline.endingMinWidth = 0; } } void PointsUI() { if (GUILayout.Button(new GUIContent("Remove all points", "Removes all points"))) { spline.RemovePoints(); } for (int i = 0; i < spline.controlPoints.Count; i++) { GUILayout.Label("Point: " + i.ToString(), EditorStyles.boldLabel); EditorGUI.indentLevel++; EditorGUILayout.BeginHorizontal(); spline.controlPoints[i] = EditorGUILayout.Vector4Field("", spline.controlPoints[i]); if (spline.controlPoints[i].w <= 0) { Vector4 vec4 = spline.controlPoints[i]; vec4.w = 0; spline.controlPoints[i] = vec4; } if (GUILayout.Button(new GUIContent("A", "Add point after this point"), GUILayout.MaxWidth(20))) { spline.AddPointAfter(i); spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } if (GUILayout.Button(new GUIContent("R", "Remove this Point"), GUILayout.MaxWidth(20))) { spline.RemovePoint(i); spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } if (GUILayout.Toggle(selectedPosition == i, new GUIContent("S", "Select point"), "Button", GUILayout.MaxWidth(20))) { selectedPosition = i; } else if (selectedPosition == i) { selectedPosition = -1; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); if (spline.controlPointsRotations.Count > i) spline.controlPointsRotations[i] = Quaternion.Euler(EditorGUILayout.Vector3Field("", spline.controlPointsRotations[i].eulerAngles)); if (GUILayout.Button(new GUIContent(" Clear rotation ", "Clear Rotation"))) { spline.controlPointsRotations[i] = Quaternion.identity; spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } EditorGUILayout.EndHorizontal(); if (spline.controlPointsSnap.Count > i) spline.controlPointsSnap[i] = EditorGUILayout.Toggle("Snap to terrain", spline.controlPointsSnap[i] == 1 ? true : false) == true ? 1 : 0; if (spline.controlPointsMeshCurves.Count > i) spline.controlPointsMeshCurves[i] = EditorGUILayout.CurveField("Mesh curve", spline.controlPointsMeshCurves[i]); EditorGUILayout.Space(); EditorGUI.indentLevel--; } } void SetMaterials() { GUILayout.Label("Set materials: ", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button("Basic", GUILayout.MinWidth(80))) { try { string materialName = "RAM_River_Material_Gamma"; if (PlayerSettings.colorSpace == ColorSpace.Linear) materialName = "RAM_River_Material_Linear"; Material riverMat = (Material)Resources.Load(materialName); if (riverMat != null) { spline.GetComponent().sharedMaterial = riverMat; } } catch { } } if (GUILayout.Button("Vertex color", GUILayout.MinWidth(80))) { try { string materialName = "RAM_River_Material_Gamma_Vertex_Color"; if (PlayerSettings.colorSpace == ColorSpace.Linear) materialName = "RAM_River_Material_Linear_Vertex_Color"; Material riverMat = (Material)Resources.Load(materialName); if (riverMat != null) { spline.GetComponent().sharedMaterial = riverMat; } } catch { } } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { if (GUILayout.Button("Basic tesseled", GUILayout.MinWidth(80))) { try { string materialName = "RAM_River_Material_Gamma_Tess"; if (PlayerSettings.colorSpace == ColorSpace.Linear) materialName = "RAM_River_Material_Linear_Tess"; Material riverMat = (Material)Resources.Load(materialName); if (riverMat != null) { spline.GetComponent().sharedMaterial = riverMat; } } catch { } } if (GUILayout.Button("Basic tesseled - vertex color", GUILayout.MinWidth(80))) { try { string materialName = "RAM_River_Material_Gamma_Tess_Vertex_Color"; if (PlayerSettings.colorSpace == ColorSpace.Linear) materialName = "RAM_River_Material_Linear_Tess_Vertex_Color"; Material riverMat = (Material)Resources.Load(materialName); if (riverMat != null) { spline.GetComponent().sharedMaterial = riverMat; } } catch { } } } EditorGUILayout.EndHorizontal(); } void ChangePivot(Vector3 center) { Vector3 position = spline.transform.position; spline.transform.position += center; for (int i = 0; i < spline.controlPoints.Count; i++) { Vector4 vec = spline.controlPoints[i]; vec.x -= center.x; vec.y -= center.y; vec.z -= center.z; spline.controlPoints[i] = vec; } spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } protected virtual void OnSceneGUIInvoke(SceneView sceneView) { if (spline == null) spline = (RamSpline)target; Color baseColor = Handles.color; int controlId = GUIUtility.GetControlID(FocusType.Passive); if (spline != null) { Camera sceneCamera = SceneView.lastActiveSceneView.camera; CheckRotations(); if (spline.drawOnMesh || spline.drawOnMeshFlowMap) { Tools.current = Tool.None; if (spline.meshfilter != null) { Handles.color = Color.magenta; Vector3[] vertices = spline.meshfilter.sharedMesh.vertices; Vector2[] uv4 = spline.meshfilter.sharedMesh.uv4; Vector3[] normals = spline.meshfilter.sharedMesh.normals; Quaternion up = Quaternion.Euler(90, 0, 0); for (int i = 0; i < vertices.Length; i += 5) { Vector3 item = vertices[i]; Vector3 handlePos = spline.transform.TransformPoint(item); if (spline.drawOnMesh) Handles.RectangleHandleCap(0, handlePos, up, 0.05f, EventType.Repaint); } } if (spline.drawOnMesh) DrawOnVertexColors(); else DrawOnFlowMap(); return; } if (Event.current.commandName == "UndoRedoPerformed") { spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif return; } if (selectedPosition >= 0 && selectedPosition < spline.controlPoints.Count) { Handles.color = Color.red; Handles.SphereHandleCap(0, (Vector3)spline.controlPoints[selectedPosition] + spline.transform.position, Quaternion.identity, 1, EventType.Repaint); } if (spline.debug) { ShowDebugHandles(); } int controlPointToDelete = -1; for (int j = 0; j < spline.controlPoints.Count; j++) { EditorGUI.BeginChangeCheck(); Vector3 handlePos = (Vector3)spline.controlPoints[j] + spline.transform.position; GUIStyle style = new GUIStyle(); style.normal.textColor = Color.red; Vector3 screenPoint = Camera.current.WorldToScreenPoint(handlePos); if (screenPoint.z > 0) { Handles.Label(handlePos + Vector3.up * HandleUtility.GetHandleSize(handlePos), "Point: " + j.ToString(), style); } float width = spline.controlPoints[j].w; if (Event.current.control && Event.current.shift && spline.controlPoints.Count > 1) { int id = GUIUtility.GetControlID(FocusType.Passive); if (HandleUtility.nearestControl == id) { Handles.color = Color.white; if (Event.current.type == EventType.MouseDown && Event.current.button == 0) controlPointToDelete = j; } else Handles.color = Handles.xAxisColor; float size = 0.6f; size = HandleUtility.GetHandleSize(handlePos) * size; if (Event.current.type == EventType.Repaint) { Handles.SphereHandleCap(id, (Vector3)spline.controlPoints[j] + spline.transform.position, Quaternion.identity, size, EventType.Repaint); } else if (Event.current.type == EventType.Layout) { Handles.SphereHandleCap(id, (Vector3)spline.controlPoints[j] + spline.transform.position, Quaternion.identity, size, EventType.Layout); } } else if (Tools.current == Tool.Move) { float size = 0.6f; size = HandleUtility.GetHandleSize(handlePos) * size; Handles.color = Handles.xAxisColor; Vector4 pos = Handles.Slider((Vector3)spline.controlPoints[j] + spline.transform.position, Vector3.right, size, Handles.ArrowHandleCap, 0.01f) - spline.transform.position; Handles.color = Handles.yAxisColor; pos = Handles.Slider((Vector3)pos + spline.transform.position, Vector3.up, size, Handles.ArrowHandleCap, 0.01f) - spline.transform.position; Handles.color = Handles.zAxisColor; pos = Handles.Slider((Vector3)pos + spline.transform.position, Vector3.forward, size, Handles.ArrowHandleCap, 0.01f) - spline.transform.position; Vector3 halfPos = (Vector3.right + Vector3.forward) * size * 0.3f; Handles.color = Handles.yAxisColor; pos = Handles.Slider2D((Vector3)pos + spline.transform.position + halfPos, Vector3.up, Vector3.right, Vector3.forward, size * 0.3f, Handles.RectangleHandleCap, 0.01f) - spline.transform.position - halfPos; halfPos = (Vector3.right + Vector3.up) * size * 0.3f; Handles.color = Handles.zAxisColor; pos = Handles.Slider2D((Vector3)pos + spline.transform.position + halfPos, Vector3.forward, Vector3.right, Vector3.up, size * 0.3f, Handles.RectangleHandleCap, 0.01f) - spline.transform.position - halfPos; halfPos = (Vector3.up + Vector3.forward) * size * 0.3f; Handles.color = Handles.xAxisColor; pos = Handles.Slider2D((Vector3)pos + spline.transform.position + halfPos, Vector3.right, Vector3.up, Vector3.forward, size * 0.3f, Handles.RectangleHandleCap, 0.01f) - spline.transform.position - halfPos; pos.w = width; spline.controlPoints[j] = pos; } else if (Tools.current == Tool.Rotate) { if (spline.controlPointsRotations.Count > j && spline.controlPointsOrientation.Count > j) { if (!((spline.beginningSpline && j == 0) || (spline.endingSpline && j == spline.controlPoints.Count - 1))) { float size = 0.6f; size = HandleUtility.GetHandleSize(handlePos) * size; Handles.color = Handles.zAxisColor; Quaternion rotation = Handles.Disc(spline.controlPointsOrientation[j], handlePos, spline.controlPointsOrientation[j] * new Vector3(0, 0, 1), size, true, 0.1f); Handles.color = Handles.yAxisColor; rotation = Handles.Disc(rotation, handlePos, rotation * new Vector3(0, 1, 0), size, true, 0.1f); Handles.color = Handles.xAxisColor; rotation = Handles.Disc(rotation, handlePos, rotation * new Vector3(1, 0, 0), size, true, 0.1f); spline.controlPointsRotations[j] *= (Quaternion.Inverse(spline.controlPointsOrientation[j]) * rotation); if (float.IsNaN(spline.controlPointsRotations[j].x) || float.IsNaN(spline.controlPointsRotations[j].y) || float.IsNaN(spline.controlPointsRotations[j].z) || float.IsNaN(spline.controlPointsRotations[j].w)) { spline.controlPointsRotations[j] = Quaternion.identity; spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } Handles.color = baseColor; Handles.FreeRotateHandle(Quaternion.identity, handlePos, size); Handles.CubeHandleCap(0, handlePos, spline.controlPointsOrientation[j], size * 0.3f, EventType.Repaint); Handles.DrawLine(spline.controlPointsUp[j] + spline.transform.position, spline.controlPointsDown[j] + spline.transform.position); } } } else if (Tools.current == Tool.Scale) { Handles.color = Handles.xAxisColor; //Vector3 handlePos = (Vector3)spline.controlPoints [j] + spline.transform.position; width = Handles.ScaleSlider(spline.controlPoints[j].w, (Vector3)spline.controlPoints[j] + spline.transform.position, new Vector3(0, 0.5f, 0), Quaternion.Euler(-90, 0, 0), HandleUtility.GetHandleSize(handlePos), 0.01f); Vector4 pos = spline.controlPoints[j]; pos.w = width; spline.controlPoints[j] = pos; } if (EditorGUI.EndChangeCheck()) { CheckRotations(); Undo.RecordObject(spline, "Change Position"); spline.GenerateSpline(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } } if (controlPointToDelete >= 0) { Undo.RecordObject(spline, "Remove point"); spline.RemovePoint(controlPointToDelete); spline.GenerateSpline(); GUIUtility.hotControl = controlId; Event.current.Use(); HandleUtility.Repaint(); controlPointToDelete = -1; } if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && Event.current.control && !Event.current.shift) { Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { Undo.RecordObject(spline, "Add point"); Vector4 position = hit.point - spline.transform.position; if (!Event.current.alt) spline.AddPoint(position); else { spline.AddPointAfter(-1); spline.ChangePointPosition(0, position); spline.GenerateSpline(); } spline.GenerateSpline(); GUIUtility.hotControl = controlId; Event.current.Use(); HandleUtility.Repaint(); } } if (!Event.current.control && Event.current.shift && spline.controlPoints.Count > 1) { Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { int idMin = -1; float distanceMin = float.MaxValue; for (int j = 0; j < spline.controlPoints.Count; j++) { Vector3 handlePos = (Vector3)spline.controlPoints[j] + spline.transform.position; float pointDist = Vector3.Distance(hit.point, handlePos); if (pointDist < distanceMin) { distanceMin = pointDist; idMin = j; } } Vector3 posOne = (Vector3)spline.controlPoints[idMin] + spline.transform.position; Vector3 posTwo; if (idMin == 0) { posTwo = (Vector3)spline.controlPoints[1] + spline.transform.position; } else if (idMin == spline.controlPoints.Count - 1) { posTwo = (Vector3)spline.controlPoints[spline.controlPoints.Count - 2] + spline.transform.position; idMin = idMin - 1; } else { Vector3 posPrev = (Vector3)spline.controlPoints[idMin - 1] + spline.transform.position; Vector3 posNext = (Vector3)spline.controlPoints[idMin + 1] + spline.transform.position; if (Vector3.Distance(hit.point, posPrev) > Vector3.Distance(hit.point, posNext)) posTwo = posNext; else { posTwo = posPrev; idMin = idMin - 1; } } Handles.DrawLine(hit.point, posOne); Handles.DrawLine(hit.point, posTwo); if (Event.current.type == EventType.MouseDown && Event.current.button == 0) { Undo.RecordObject(spline, "Add point"); Vector4 position = hit.point - spline.transform.position; spline.AddPointAfter(idMin); spline.ChangePointPosition(idMin + 1, position); spline.GenerateSpline(); GUIUtility.hotControl = controlId; Event.current.Use(); HandleUtility.Repaint(); #if VEGETATION_STUDIO_PRO RegeneratBiomeMask(); #endif } } } if (Event.current.type == EventType.MouseUp && Event.current.button == 0 && Event.current.control) { GUIUtility.hotControl = 0; } if (Event.current.type == EventType.MouseUp && Event.current.button == 0 && Event.current.shift) { GUIUtility.hotControl = 0; } } } private void ShowDebugHandles() { Vector3[] points = new Vector3[spline.controlPoints.Count]; for (int i = 0; i < spline.controlPoints.Count; i++) { points[i] = (Vector3)spline.controlPoints[i] + spline.transform.position; } Handles.color = Color.white; Handles.DrawPolyLine(points); Handles.color = new Color(1, 0, 0, 0.5f); for (int i = 0; i < spline.pointsDown.Count; i++) { Vector3 handlePos = (Vector3)spline.pointsDown[i] + spline.transform.position; Vector3 handlePos2 = (Vector3)spline.pointsUp[i] + spline.transform.position; if (spline.debugPointsConnect) Handles.DrawLine(handlePos, handlePos2); } Handles.color = Color.blue; points = new Vector3[spline.pointsDown.Count]; for (int i = 0; i < spline.pointsDown.Count; i++) { if (spline.debugPoints) Handles.SphereHandleCap(0, spline.pointsDown[i] + spline.transform.position, Quaternion.identity, 0.1f, EventType.Repaint); points[i] = (Vector3)spline.pointsDown[i] + spline.transform.position; } Handles.DrawPolyLine(points); points = new Vector3[spline.pointsUp.Count]; for (int i = 0; i < spline.pointsUp.Count; i++) { if (spline.debugPoints) Handles.SphereHandleCap(0, spline.pointsUp[i] + spline.transform.position, Quaternion.identity, 0.1f, EventType.Repaint); points[i] = (Vector3)spline.pointsUp[i] + spline.transform.position; } Handles.DrawPolyLine(points); spline.debugMesh = true; //Normals, tangents //if (!spline.debugMesh) //{ //points = spline.points.ToArray(); //for (int i = 0; i < points.Length; i++) //{ // points[i] += spline.transform.position; // Handles.color = Color.green; // if (spline.debugNormals) // { // Handles.DrawLine(points[i], points[i] + spline.normalsList[i]); // } // if (spline.debugBitangent) // { // Vector3 posUp = spline.orientations[i] * Vector3.right; // Handles.DrawLine(points[i], points[i] + posUp); // } // Handles.color = Color.red; // if (spline.debugTangents) // Handles.DrawLine(points[i] - spline.tangents[i], points[i] + spline.tangents[i]); //} //} //else if (spline.debugMesh) //{ Vector3 camPosition = SceneView.lastActiveSceneView.camera.transform.position; GUIStyle style = new GUIStyle(); style.normal.textColor = Color.red; Mesh mesh = spline.meshfilter.sharedMesh; if (mesh) { Vector3[] vertices = mesh.vertices; Vector3[] normals = mesh.normals; Vector4[] tangents = mesh.tangents; Vector2[] uv4 = mesh.uv4; float distDebug = spline.distanceToDebug * spline.distanceToDebug; for (int i = 0; i < vertices.Length; i++) { vertices[i] += spline.transform.position; Vector3 offset = vertices[i] - camPosition; float sqrLen = offset.sqrMagnitude; if (sqrLen > distDebug) continue; Handles.color = Color.green; if (spline.debugNormals) { Handles.DrawLine(vertices[i], vertices[i] + normals[i]); } Handles.color = Color.red; if (spline.debugTangents) Handles.DrawLine(vertices[i] - (Vector3)tangents[i], vertices[i] + (Vector3)tangents[i]); Handles.color = Color.magenta; if (spline.debugFlowmap) { Handles.DrawLine(vertices[i], vertices[i] + new Vector3(uv4[i].x, uv4[i].y, 0) * 2); Handles.Label(vertices[i] + new Vector3(uv4[i].x, uv4[i].y, 0) * 2, uv4[i].x + " " + uv4[i].y, style); } } } //} } void DrawOnVertexColors() { if (Event.current.type == EventType.MouseUp && Event.current.button == 0) { Undo.RegisterCompleteObjectUndo(spline, "Painted"); } HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive)); //Camera sceneCamera = SceneView.lastActiveSceneView.camera; //Vector2 mousePos = Event.current.mousePosition; //mousePos.y = Screen.height - mousePos.y - 40; Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); List meshColliders = new List(); foreach (var item in splines) { meshColliders.Add(item.gameObject.AddComponent()); } RaycastHit[] hits = Physics.RaycastAll(ray, Mathf.Infinity); GameObject go = null; Vector3 hitPosition = Vector3.zero; Vector3 hitNormal = Vector3.zero; RamSpline hitedSpline = null; if (hits.Length > 0) { foreach (var hit in hits) { if (hit.collider is MeshCollider) { go = hit.collider.gameObject; hitedSpline = go.GetComponent(); if (hitedSpline != null && (spline.drawOnMultiple || hitedSpline == spline)) { hitPosition = hit.point; hitNormal = hit.normal; break; } else go = null; } } } foreach (var item in meshColliders) { if (item != null) DestroyImmediate(item); } if (go != null) { Handles.color = new Color(spline.drawColor.r, spline.drawColor.g, spline.drawColor.b, 1); Handles.DrawLine(hitPosition, hitPosition + hitNormal * 2); Handles.CircleHandleCap( 0, hitPosition, Quaternion.LookRotation(hitNormal), spline.drawSize, EventType.Repaint ); Handles.color = Color.black; Handles.CircleHandleCap( 0, hitPosition, Quaternion.LookRotation(hitNormal), spline.drawSize - 0.1f, EventType.Repaint ); if (!(Event.current.type == EventType.MouseDown || Event.current.type == EventType.MouseDrag) || Event.current.button != 0) return; if (Event.current.type == EventType.MouseDown && Event.current.button == 0) { } MeshFilter meshFilter = hitedSpline.GetComponent(); if (meshFilter.sharedMesh != null) { Mesh mesh = meshFilter.sharedMesh; if (hitedSpline.colors.Length == 0) hitedSpline.colors = new Color[mesh.vertices.Length]; int length = mesh.vertices.Length; float dist = 0; hitPosition -= hitedSpline.transform.position; Vector3[] vertices = mesh.vertices; Color[] colors = hitedSpline.colors; for (int i = 0; i < length; i++) { dist = Vector3.Distance(hitPosition, vertices[i]); if (dist < hitedSpline.drawSize) { if (Event.current.shift) { if (spline.drawColorR) colors[i].r = Mathf.Lerp(colors[i].r, 0, spline.opacity); if (spline.drawColorG) colors[i].g = Mathf.Lerp(colors[i].g, 0, spline.opacity); if (spline.drawColorB) colors[i].b = Mathf.Lerp(colors[i].b, 0, spline.opacity); if (spline.drawColorA) colors[i].a = Mathf.Lerp(colors[i].a, 1, spline.opacity); } else { if (spline.drawColorR) colors[i].r = Mathf.Lerp(colors[i].r, spline.drawColor.r, spline.opacity); if (spline.drawColorG) colors[i].g = Mathf.Lerp(colors[i].g, spline.drawColor.g, spline.opacity); if (spline.drawColorB) colors[i].b = Mathf.Lerp(colors[i].b, spline.drawColor.b, spline.opacity); if (spline.drawColorA) colors[i].a = Mathf.Lerp(colors[i].a, spline.drawColor.a, spline.opacity); } } } mesh.colors = colors; meshFilter.sharedMesh = mesh; if (hitedSpline.generateMeshParts) hitedSpline.GenerateMeshParts(mesh); } } } void DrawOnFlowMap() { if (Event.current.type == EventType.MouseUp && Event.current.button == 0) { Undo.RegisterCompleteObjectUndo(spline, "Painted"); } HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive)); //Camera sceneCamera = SceneView.lastActiveSceneView.camera; //Vector2 mousePos = Event.current.mousePosition; //mousePos.y = Screen.height - mousePos.y - 40; //Ray ray = sceneCamera.ScreenPointToRay(mousePos); Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); List meshColliders = new List(); foreach (var item in splines) { meshColliders.Add(item.gameObject.AddComponent()); } RaycastHit[] hits = Physics.RaycastAll(ray, Mathf.Infinity); GameObject go = null; Vector3 hitPosition = Vector3.zero; Vector3 hitNormal = Vector3.zero; RamSpline hitedSpline = null; if (hits.Length > 0) { foreach (var hit in hits) { if (hit.collider is MeshCollider) { go = hit.collider.gameObject; hitedSpline = go.GetComponent(); if (hitedSpline != null && (spline.drawOnMultiple || hitedSpline == spline)) { hitPosition = hit.point; hitNormal = hit.normal; break; } else go = null; } } } foreach (var item in meshColliders) { if (item != null) DestroyImmediate(item); } if (go != null) { Handles.color = new Color(spline.flowDirection, spline.flowSpeed, 0, 1); Handles.DrawLine(hitPosition, hitPosition + hitNormal * 2); Handles.CircleHandleCap( 0, hitPosition, Quaternion.LookRotation(hitNormal), spline.drawSize, EventType.Repaint ); Handles.color = Color.black; Handles.CircleHandleCap( 0, hitPosition, Quaternion.LookRotation(hitNormal), spline.drawSize - 0.1f, EventType.Repaint ); if (!(Event.current.type == EventType.MouseDown || Event.current.type == EventType.MouseDrag) || Event.current.button != 0) return; if (Event.current.type == EventType.MouseDown && Event.current.button == 0) { } hitedSpline.overrideFlowMap = true; MeshFilter meshFilter = hitedSpline.GetComponent(); if (meshFilter.sharedMesh != null) { Mesh mesh = meshFilter.sharedMesh; List colorsFlowMap = hitedSpline.colorsFlowMap; int length = mesh.vertices.Length; float dist = 0; float distValue = 0; hitPosition -= hitedSpline.transform.position; Vector3[] vertices = mesh.vertices; for (int i = 0; i < length; i++) { dist = Vector3.Distance(hitPosition, vertices[i]); if (dist < spline.drawSize) { distValue = (spline.drawSize - dist) / (float)spline.drawSize; if (Event.current.shift) { colorsFlowMap[i] = Vector2.Lerp(colorsFlowMap[i], new Vector2(0, 0), spline.opacity); } else { colorsFlowMap[i] = Vector2.Lerp(colorsFlowMap[i], new Vector2(spline.flowDirection, spline.flowSpeed), spline.opacity * distValue); } } } mesh.uv4 = colorsFlowMap.ToArray(); hitedSpline.colorsFlowMap = colorsFlowMap; meshFilter.sharedMesh = mesh; if (hitedSpline.generateMeshParts) hitedSpline.GenerateMeshParts(mesh); } } } public static LayerMask LayerMaskField(string label, LayerMask selected, bool showSpecial) { List layers = new List(); List layerNumbers = new List(); string selectedLayers = ""; for (int i = 0; i < 32; i++) { string layerName = LayerMask.LayerToName(i); if (layerName != "") { if (selected == (selected | (1 << i))) { if (selectedLayers == "") { selectedLayers = layerName; } else { selectedLayers = "Mixed"; } } } } EventType lastEvent = Event.current.type; if (Event.current.type != EventType.MouseDown && Event.current.type != EventType.ExecuteCommand) { if (selected.value == 0) { layers.Add("Nothing"); } else if (selected.value == -1) { layers.Add("Everything"); } else { layers.Add(selectedLayers); } layerNumbers.Add(-1); } if (showSpecial) { layers.Add((selected.value == 0 ? "[X] " : " ") + "Nothing"); layerNumbers.Add(-2); layers.Add((selected.value == -1 ? "[X] " : " ") + "Everything"); layerNumbers.Add(-3); } for (int i = 0; i < 32; i++) { string layerName = LayerMask.LayerToName(i); if (layerName != "") { if (selected == (selected | (1 << i))) { layers.Add("[X] " + i + ": " + layerName); } else { layers.Add(" " + i + ": " + layerName); } layerNumbers.Add(i); } } bool preChange = GUI.changed; GUI.changed = false; int newSelected = 0; if (Event.current.type == EventType.MouseDown) { newSelected = -1; } newSelected = EditorGUILayout.Popup(label, newSelected, layers.ToArray(), EditorStyles.layerMaskField); if (GUI.changed && newSelected >= 0) { if (showSpecial && newSelected == 0) { selected = 0; } else if (showSpecial && newSelected == 1) { selected = -1; } else { if (selected == (selected | (1 << layerNumbers[newSelected]))) { selected &= ~(1 << layerNumbers[newSelected]); } else { selected = selected | (1 << layerNumbers[newSelected]); } } } else { GUI.changed = preChange; } return selected; } public void PointsToFile() { var path = EditorUtility.SaveFilePanelInProject( "Save Spline Points", spline.name + "Points.csv", "csv", "Save Spline " + spline.name + " Points in CSV"); if (string.IsNullOrEmpty(path)) return; string fileData = ""; foreach (Vector4 v in spline.controlPoints) { fileData += v.x + ";" + v.y + ";" + v.z + ";" + v.w + "\n"; } if (fileData.Length > 0) fileData.Remove(fileData.Length - 1, 1); // Debug.Log(fileData); File.WriteAllText(path, fileData); } public void PointsFromFile() { string path = EditorUtility.OpenFilePanel("Read Spline Points from CSV", Application.dataPath, "csv"); if (string.IsNullOrEmpty(path)) return; string fileData = File.ReadAllText(path); string[] lines = fileData.Split(new char[] { '\n' }, System.StringSplitOptions.RemoveEmptyEntries); Vector4[] vectors = new Vector4[lines.Length]; for (int i = 0; i < vectors.Length; i++) { string[] values = lines[i].Split(new char[] { ';' }, System.StringSplitOptions.RemoveEmptyEntries); if (values.Length != 4) Debug.LogError("Wrong file data"); else { try { vectors[i] = new Vector4(float.Parse(values[0]), float.Parse(values[1]), float.Parse(values[2]), float.Parse(values[3])); } catch (System.Exception) { Debug.LogError("Wrong file data"); return; } } } Undo.RecordObject(spline, "Spline changed"); if (vectors.Length > 0) { foreach (var item in vectors) { spline.AddPoint(item); } } } }