Unity Cave Population Tool Script

Previous Page: Back

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
#endif

#if UNITY_EDITOR
public class CavePopulation : EditorWindow
{

    public GameObject caveObject;

    public GameObject genObjectPrefab;

    public bool visualize;
    public int visualizerMode = 0;
    public int batchSize = 1;
    public int angleOfTolerance = 0;
    public float regressionValue = 0.0f;
    public int distributionPercentage;
    public bool isCeiling;
    public bool shouldRotate;
    public bool randomAngleOffsets;
    public float randomAngleOffsetValue = 0.0f;
    public bool boundBySphere;

    private bool visualizeEquipped = false;
    private GameObject caveMeshImmediate = null;
    private Mesh caveMesh = null;
    private MeshVisualizer mv = null;

    private GameObject boundingSphere = null;

    string[] visualizerModeNames = new string[] { "Vertex", "Normal/No Indication", "Normal/Vertical Indication" };
    int[] visualizerOptions = { 0, 1, 2 };

    [MenuItem("My Tools/Cave Population")]
    public static void ShowWindow()
    {
        GetWindow(typeof(CavePopulation));
    }

    public void OnGUI()
    {

        SerializedObject serialized = new SerializedObject(this);
        SerializedProperty caveObjectProperty = serialized.FindProperty("caveObject");

        EditorGUILayout.LabelField("Cave Population", EditorStyles.boldLabel);
        EditorGUILayout.PropertyField(caveObjectProperty, true);
        serialized.ApplyModifiedProperties();

        if(caveObject != null)
        {
            MeshFilter mf = caveObject.GetComponentInChildren<MeshFilter>();
            caveMeshImmediate = mf.gameObject;
            caveMesh = mf.sharedMesh;

            visualize = EditorGUILayout.Toggle("Should Visualize Mesh?", visualize);

            if(visualize && !visualizeEquipped)
            {
                visualizeEquipped = true;
                mv = caveMeshImmediate.AddComponent<MeshVisualizer>();
                mv.sphereRadius = 1.0f;
            }
            else if(!visualize && visualizeEquipped)
            {
                DestroyImmediate(mv);
                mv = null;
                visualizeEquipped = false;
            }

            if(visualize && visualizeEquipped)
            {
                visualizerMode = EditorGUILayout.IntPopup("Visualizer Mode:", visualizerMode, visualizerModeNames, visualizerOptions);
                mv.visualizerMode = visualizerMode;

                EditorGUILayout.PrefixLabel("# of Items:");
                batchSize = EditorGUILayout.IntSlider(batchSize, 1, 1000);
                if (mv.startingIndex + batchSize > mv.vertexCount)
                    batchSize = mv.vertexCount - mv.startingIndex;

                mv.batchSize = batchSize;

                EditorGUILayout.LabelField("Showing item " + mv.startingIndex + " through " + (mv.startingIndex + batchSize - 1) + " out of " + mv.vertexCount, EditorStyles.helpBox);
                EditorGUILayout.BeginHorizontal();

                if(GUILayout.Button("Previous Set"))
                {
                    if(mv.startingIndex - batchSize >= 0)
                    {
                        mv.startingIndex -= batchSize;
                    }
                    else
                    {
                        mv.startingIndex = 0;
                    }
                }

                if(GUILayout.Button("Next Set"))
                {
                    if (mv.startingIndex + batchSize + batchSize <= mv.vertexCount)
                    {
                        mv.startingIndex += batchSize;
                    }
                    else if (mv.startingIndex + batchSize <= mv.vertexCount)
                    {
                        mv.startingIndex = mv.vertexCount - batchSize;
                    }
                }

                EditorGUILayout.EndHorizontal();

            }

            EditorGUILayout.PrefixLabel("Angle of Tolerance:");
            angleOfTolerance = EditorGUILayout.IntSlider(angleOfTolerance, 0, 75);

            if(mv != null)
                mv.angleOfTolerance = angleOfTolerance;

            EditorGUILayout.PrefixLabel("Regression Into Mesh:");
            regressionValue = EditorGUILayout.Slider(regressionValue, 0.0f, 1.0f);

            SerializedProperty genObjectProperty = serialized.FindProperty("genObjectPrefab");
            EditorGUILayout.PropertyField(genObjectProperty, true);
            serialized.ApplyModifiedProperties();

            isCeiling = EditorGUILayout.Toggle("Is Ceiling?", isCeiling);

            shouldRotate = EditorGUILayout.Toggle("Should Rotate to Normals?", shouldRotate);

            if(shouldRotate)
                randomAngleOffsets = EditorGUILayout.Toggle("Randomize Offset Angles?", randomAngleOffsets);

            if(shouldRotate && randomAngleOffsets)
            {
                EditorGUILayout.PrefixLabel("Maximum Offset Angle:");
                randomAngleOffsetValue = EditorGUILayout.Slider(randomAngleOffsetValue, 0.1f, 10.0f);
            }

            boundBySphere = EditorGUILayout.Toggle("Bound Gen to Sphere?", boundBySphere);

            if(boundBySphere && boundingSphere == null)
            {
                boundingSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                boundingSphere.name = "Cave Tool Bounding Sphere";
            }

            if(!boundBySphere && boundingSphere)
            {
                DestroyImmediate(boundingSphere);
            }

            if (mv)
            {
                mv.boundBySphere = boundBySphere;

                if (boundBySphere)
                {
                    mv.boundingSphere = boundingSphere;
                }
            }

            EditorGUILayout.PrefixLabel("Distribution Percentage:");
            distributionPercentage = EditorGUILayout.IntSlider(distributionPercentage, 1, 100);

            if (GUILayout.Button("Populate Cave"))
            {
                PopulateCave();
            }

        }

        

    }

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnDestroy()
    {
        if(mv)
        {
            DestroyImmediate(mv);
        }

        if(boundingSphere)
        {
            DestroyImmediate(boundingSphere);
        }
    }

    private void PopulateCave()
    {
        MeshFilter mf = caveObject.GetComponentInChildren<MeshFilter>();
        GameObject immediateObj = mf.gameObject;
        Mesh mesh = mf.sharedMesh;

        GameObject parent = new GameObject();
        parent.name = "Rocks Generated";

        float tolerance = (angleOfTolerance / 90.0f);

        if (genObjectPrefab != null)
        {
            if(isCeiling)
                for(int i = 0; i < mf.sharedMesh.vertexCount; i++)
                {
                    if (checkBound(mesh.vertices[i]) && ShouldGen() && Vector3.Dot(mesh.normals[i], Vector3.up) < -tolerance)
                    {
                        GameObject obj = Instantiate(genObjectPrefab, parent.transform);
                        obj.transform.position = immediateObj.transform.position + mesh.vertices[i] + new Vector3(0, regressionValue, 0);

                        if(shouldRotate)
                        {
                            Vector3 rotateTo = mesh.normals[i];

                            if(randomAngleOffsets)
                            {
                                float theta;
                            }

                            obj.transform.rotation = Quaternion.FromToRotation(obj.transform.up, mesh.normals[i]);
                        }
                            
                    }
                }
            else
                for (int i = 0; i < mf.sharedMesh.vertexCount; i++)
                {
                    if (checkBound(mesh.vertices[i]) && ShouldGen() && Vector3.Dot(mesh.normals[i], Vector3.up) > tolerance)
                    {
                        GameObject obj = Instantiate(genObjectPrefab, parent.transform);
                        obj.transform.position = immediateObj.transform.position + mesh.vertices[i] - new Vector3(0, regressionValue, 0);

                        if (shouldRotate)
                            obj.transform.rotation = Quaternion.FromToRotation(obj.transform.up, mesh.normals[i]);
                    }
                }
        }
    }

    private bool ShouldGen()
    {
        float val = Random.Range(0.0f, 100.0f);

        return val < distributionPercentage;
    }

    private bool checkBound(Vector3 pos) //If bound by sphere, determine if location is in sphere. Otherwise, return true.
    {
        if (boundBySphere)
        {
            if (Vector3.Distance(pos, boundingSphere.transform.position) < boundingSphere.transform.localScale.x / 2.0f)
                return true;
            else
                return false;
        }
        else
            return true;
    }
}
#endif
#endif