예제 #1
0
        /// <summary>
        /// First creates a poisson grid based on the passed density.
        /// Positions are then filtered based on the passed object placement
        /// type taking into account height and angle constraints.
        /// </summary>
        /// <param name="m">Mesh to sample height and angle values from</param>
        /// <param name="type">object placement type to sample</param>
        /// <param name="density">How dense should the samples be</param>
        /// <returns>List of vectors within the grid and sample constraints</returns>
        public List <Vector3> GetFilteredGrid(TerrainTile tile, ObjectPlacementType type, float density)
        {
            MeshFilter mf = tile.GetComponent <MeshFilter>();

            if (mf == null)
            {
                throw new ArgumentException("The passed TerrainTile does not have an attached MeshFilter. Has a mesh been created?");
            }

            return(GetFilteredGrid(mf.sharedMesh, type));
        }
예제 #2
0
            /// <summary>
            /// Computes positions for this TerrainTile and caches
            /// them.
            /// </summary>
            public void ComputePositions()
            {
                Positions = new PositionsContainer[Pool.Placer.ObjectsToPlace.Count];

                for (int i = 0; i < Positions.Length; i++)
                {
                    ObjectPlacementType type      = Pool.Placer.ObjectsToPlace[i];
                    Vector3[]           locations = Pool.Placer.GetFilteredGrid(Tile, type, 1).ToArray();
                    Positions[i] = new PositionsContainer(locations, type);
                }
            }
예제 #3
0
            /// <summary>
            /// Gets the container that holds the passed
            /// ObjectPlacementType
            /// </summary>
            /// <param name="type">type to search for</param>
            /// <returns>ObjectContainer, null if no matches were found</returns>
            ObjectContainer GetContainerForType(ObjectPlacementType type)
            {
                foreach (ObjectContainer c in Pool.Containers)
                {
                    if (c.Type.Equals(type))
                    {
                        return(c);
                    }
                }

                return(null);
            }
        /// <summary>
        /// Calculates a grid using the poisson disc sampling method.
        /// The 2D grid positions fall within the range of [0, 1].
        ///
        /// Can be called off of Unity's main thread.
        /// </summary>
        /// <param name="opt">Object placement type to sample</param>
        /// <returns>List of vectors within the grid</returns>
        public List <Vector2> GetPoissonGrid(ObjectPlacementType opt)
        {
            PoissonDiscSampler pds   = new PoissonDiscSampler(opt.GridSize, opt.GridSize, opt.Density);
            List <Vector2>     total = new List <Vector2>();

            foreach (Vector2 sample in pds.Samples())
            {
                total.Add(sample);
            }

            return(total);
        }
예제 #5
0
        /// <summary>
        /// First creates a poisson grid based on the passed density.
        /// Positions are then filtered based on the passed object placement
        /// type taking into account height and angle constraints.
        ///
        /// Unlike the <c>GetFilteredGrid(ObjectPlacementType, float)</c> method
        /// this method samples from the passed Mesh rather than pulling
        /// mesh information from TerraSettings.
        /// </summary>
        /// <param name="m">Mesh to sample height and angle values from</param>
        /// <param name="type">object placement type to sample</param>
        /// <returns>List of vectors within the grid and sample constraints</returns>
        public List <Vector3> GetFilteredGrid(Mesh m, ObjectPlacementType type)
        {
            MeshSampler    sampler = new MeshSampler(m, Settings.MeshResolution);
            List <Vector2> grid    = GetPoissonGrid(type.Spread / 10);
            List <Vector3> toAdd   = new List <Vector3>();

            foreach (Vector2 pos in grid)
            {
                MeshSampler.MeshSample sample = sampler.SampleAt(pos.x, pos.y);

                if (type.ShouldPlaceAt(sample.Height, sample.Angle))
                {
                    Vector3 newPos = new Vector3(pos.x, sample.Height, pos.y);
                    toAdd.Add(newPos);
                }
            }

            return(toAdd);
        }
예제 #6
0
 public PositionsContainer(Vector3[] positions, ObjectPlacementType type)
 {
     Positions = positions;
     Type      = type;
 }
예제 #7
0
 public ObjectContainer(ObjectPlacementType type)
 {
     Type = type;
 }
예제 #8
0
        /// <summary>
        /// Displays GUI elements for the "Object Placement" tab
        /// </summary>
        public void ObjectPlacement()
        {
            //Display each type
            for (int i = 0; i < Settings.ObjectPlacementSettings.Count; i++)
            {
                EditorGUILayout.Space();

                //Surround each material w/ box
                GUIStyle boxStyle = new GUIStyle();
                boxStyle.padding           = new RectOffset(3, 3, 3, 3);
                boxStyle.normal.background = GetWhiteTexture();
                EditorGUILayout.BeginVertical(boxStyle);

                ObjectPlacementType type = Settings.ObjectPlacementSettings[i];

                //Close button / name
                if (GUILayout.Button("X", GUILayout.Height(16), GUILayout.Width(18)))
                {
                    Settings.ObjectPlacementSettings.RemoveAt(i);
                    i--;
                    continue;
                }

                //General
                type.Prefab               = (GameObject)EditorGUILayout.ObjectField("Prefab", type.Prefab, typeof(GameObject), false);
                type.AllowsIntersection   = EditorGUILayout.Toggle("Can Intersect", type.AllowsIntersection);
                type.PlacementProbability = EditorGUILayout.IntSlider("Place Probability", type.PlacementProbability, 0, 100);
                type.Spread               = EditorGUILayout.Slider("Object Spread", type.Spread, 5f, 50f);
                type.MaxObjects           = EditorGUILayout.IntField("Max Objects", type.MaxObjects);
                if (type.MaxObjects < 1)
                {
                    type.MaxObjects = 1;
                }

                //Height
                type.ConstrainHeight = EditorGUILayout.Toggle("Constrain Height", type.ConstrainHeight);
                if (type.ConstrainHeight)
                {
                    EditorGUI.indentLevel = 1;

                    type.MinHeight = EditorGUILayout.FloatField("Min Height", type.MinHeight);
                    type.MaxHeight = EditorGUILayout.FloatField("Max Height", type.MaxHeight);

                    FitMinMax(ref type.MinHeight, ref type.MaxHeight);

                    EditorGUILayout.BeginHorizontal();
                    type.HeightProbCurve = EditorGUILayout.CurveField("Probability", type.HeightProbCurve, Color.green, new Rect(0, 0, 1, 1));
                    if (GUILayout.Button("?", GUILayout.Width(25)))
                    {
                        const string msg = "This is the height probability curve. The X axis represents the " +
                                           "min to max height and the Y axis represents the probability an " +
                                           "object will spawn. By default, the curve is set to a 100% probability " +
                                           "meaning all objects will spawn.";
                        EditorUtility.DisplayDialog("Help - Height Probability", msg, "Close");
                    }
                    EditorGUILayout.EndHorizontal();

                    EditorGUI.indentLevel = 0;
                }

                //Angle
                type.ConstrainAngle = EditorGUILayout.Toggle("Constrain Angle", type.ConstrainAngle);
                if (type.ConstrainAngle)
                {
                    EditorGUI.indentLevel = 1;

                    type.MinAngle = EditorGUILayout.FloatField("Min Angle", type.MinAngle);
                    type.MaxAngle = EditorGUILayout.FloatField("Max Angle", type.MaxAngle);

                    FitMinMax(ref type.MinAngle, ref type.MaxAngle);

                    EditorGUILayout.BeginHorizontal();
                    type.AngleProbCurve = EditorGUILayout.CurveField("Probability", type.AngleProbCurve, Color.green, new Rect(0, 0, 180, 1));
                    if (GUILayout.Button("?", GUILayout.Width(25)))
                    {
                        const string msg = "This is the angle probability curve. The X axis represents " +
                                           "0 to 180 degrees and the Y axis represents the probability an " +
                                           "object will spawn. By default, the curve is set to a 100% probability " +
                                           "meaning all objects will spawn.";
                        EditorUtility.DisplayDialog("Help - Angle Probability", msg, "Close");
                    }
                    EditorGUILayout.EndHorizontal();

                    EditorGUI.indentLevel = 0;
                }

                //Translate
                EditorGUI.indentLevel     = 1;
                type.ShowTranslateFoldout = EditorGUILayout.Foldout(type.ShowTranslateFoldout, "Translate");
                if (type.ShowTranslateFoldout)
                {
                    type.TranslationAmount = EditorGUILayout.Vector3Field("Translate", type.TranslationAmount);

                    EditorGUILayout.BeginHorizontal();
                    type.IsRandomTranslate = EditorGUILayout.Toggle("Random", type.IsRandomTranslate);
                    if (GUILayout.Button("?", GUILayout.Width(25)))
                    {
                        const string msg = "Optionally randomly translate the placed object. " +
                                           "Max and min extents for the random number generator can " +
                                           "be set.";
                        EditorUtility.DisplayDialog("Help - Random Translate", msg, "Close");
                    }
                    EditorGUILayout.EndHorizontal();

                    if (type.IsRandomTranslate)
                    {
                        EditorGUI.indentLevel = 2;

                        type.RandomTranslateExtents.Min = EditorGUILayout.Vector3Field("Min", type.RandomTranslateExtents.Min);
                        type.RandomTranslateExtents.Max = EditorGUILayout.Vector3Field("Max", type.RandomTranslateExtents.Max);

                        FitMinMax(ref type.RandomTranslateExtents.Min, ref type.RandomTranslateExtents.Max);
                        EditorGUI.indentLevel = 1;
                    }
                }

                //Rotate
                type.ShowRotateFoldout = EditorGUILayout.Foldout(type.ShowRotateFoldout, "Rotate");
                if (type.ShowRotateFoldout)
                {
                    type.RotationAmount = EditorGUILayout.Vector3Field("Rotation", type.RotationAmount);

                    EditorGUILayout.BeginHorizontal();
                    type.IsRandomRotation = EditorGUILayout.Toggle("Random", type.IsRandomRotation);
                    if (GUILayout.Button("?", GUILayout.Width(25)))
                    {
                        const string msg = "Optionally randomly rotate the placed object. " +
                                           "Max and min extents for the random number generator can " +
                                           "be set.";
                        EditorUtility.DisplayDialog("Help - Random Rotate", msg, "Close");
                    }
                    EditorGUILayout.EndHorizontal();

                    if (type.IsRandomRotation)
                    {
                        EditorGUI.indentLevel = 2;

                        type.RandomRotationExtents.Min = EditorGUILayout.Vector3Field("Min", type.RandomRotationExtents.Min);
                        type.RandomRotationExtents.Max = EditorGUILayout.Vector3Field("Max", type.RandomRotationExtents.Max);

                        FitMinMax(ref type.RandomRotationExtents.Min, ref type.RandomRotationExtents.Max);
                        EditorGUI.indentLevel = 1;
                    }
                }

                //Scale
                type.ShowScaleFoldout = EditorGUILayout.Foldout(type.ShowScaleFoldout, "Scale");
                if (type.ShowScaleFoldout)
                {
                    type.ScaleAmount = EditorGUILayout.Vector3Field("Scale", type.ScaleAmount);

                    EditorGUILayout.BeginHorizontal();
                    type.IsRandomScale = EditorGUILayout.Toggle("Random", type.IsRandomScale);
                    if (GUILayout.Button("?", GUILayout.Width(25)))
                    {
                        const string msg = "Optionally randomly scale the placed object. " +
                                           "Max and min extents for the random number generator can " +
                                           "be set.";
                        EditorUtility.DisplayDialog("Help - Random Scale", msg, "Close");
                    }
                    EditorGUILayout.EndHorizontal();

                    if (type.IsRandomScale)
                    {
                        type.IsUniformScale = EditorGUILayout.Toggle("Scale Uniformly", type.IsUniformScale);

                        EditorGUI.indentLevel = 2;

                        if (type.IsUniformScale)
                        {
                            type.UniformScaleMin = EditorGUILayout.FloatField("Min", type.UniformScaleMin);
                            type.UniformScaleMax = EditorGUILayout.FloatField("Max", type.UniformScaleMax);
                        }
                        else
                        {
                            type.RandomScaleExtents.Min = EditorGUILayout.Vector3Field("Min", type.RandomScaleExtents.Min);
                            type.RandomScaleExtents.Max = EditorGUILayout.Vector3Field("Max", type.RandomScaleExtents.Max);

                            FitMinMax(ref type.RandomScaleExtents.Min, ref type.RandomScaleExtents.Max);
                        }
                        EditorGUI.indentLevel = 1;
                    }
                }

                EditorGUI.indentLevel = 0;
                EditorGUILayout.EndVertical();
            }

            //Add new button
            EditorGUILayout.Space();
            if (GUILayout.Button("Add Object"))
            {
                if (Settings.ObjectPlacementSettings == null)
                {
                    Settings.ObjectPlacementSettings = new List <ObjectPlacementType>();
                }

                Settings.ObjectPlacementSettings.Add(new ObjectPlacementType(TerraSettings.GenerationSeed));
            }

            //Update preview
            if (Settings.DisplayPreview && GUILayout.Button("Update Preview"))
            {
                Settings.Preview.TriggerObjectPlacementUpdate();
            }
        }
 public ObjectContainer(ObjectPlacementType type, Transform parent)
 {
     Type   = type;
     Parent = parent;
 }