Exemplo n.º 1
0
        public void SpawnGrass(GrassPrefab item)
        {
            if (item.collisionCheck)
            {
                RebuildCollisionCacheIfNeeded();
            }

            item.instanceCount = 0;

            foreach (Terrain terrain in terrains)
            {
                //2 texels per unit
                //int density = Mathf.NextPowerOfTwo(Mathf.RoundToInt(terrain.terrainData.size.x * 2f));
                //int[,] map = new int[density, density];
                //terrain.terrainData.SetDetailResolution(density, terrain.terrainData.detailResolutionPerPatch);

#if UNITY_EDITOR
                //UnityEditor.EditorUtility.DisplayProgressBar("Vegetation Spawner", "Spawning grass...", 1f);
#endif
                int[,] map = terrain.terrainData.GetDetailLayer(0, 0, terrain.terrainData.detailWidth, terrain.terrainData.detailHeight, item.index);

                for (int x = 0; x < terrain.terrainData.detailWidth; x++)
                {
                    for (int y = 0; y < terrain.terrainData.detailHeight; y++)
                    {
                        InitializeSeed(x * y + item.seed);

                        //Default
                        int instanceCount = 1;
                        map[x, y] = 0;

                        //XZ world position
                        Vector3 wPos = terrain.DetailToWorld(y, x);

                        Vector2 normalizedPos = terrain.GetNormalizedPosition(wPos);

                        if (item.collisionCheck)
                        {
                            //Check for collision
                            if (InsideOccupiedCell(terrain, wPos, normalizedPos))
                            {
                                continue;
                            }

                            /* 1 second slower
                             * RaycastHit hit;
                             * if (Physics.Raycast(wPos + (Vector3.up * 50f), -Vector3.up, out hit, 100f, -1))
                             * {
                             *  if (hit.collider.gameObject != terrain.gameObject)
                             *  {
                             *      continue;
                             *  }
                             * }
                             */
                        }

                        //Skip if failing probability check
                        if (((Random.value * 100f) <= item.probability) == false)
                        {
                            instanceCount = 0;
                            continue;
                        }

                        terrain.SampleHeight(normalizedPos, out _, out wPos.y, out _);

                        if (item.rejectUnderwater && wPos.y < waterHeight)
                        {
                            instanceCount = 0;
                            continue;
                        }
                        //Check height
                        if (wPos.y < item.heightRange.x || wPos.y > item.heightRange.y)
                        {
                            instanceCount = 0;
                            continue;
                        }

                        if (item.slopeRange.x > 0 || item.slopeRange.y < 90)
                        {
                            float slope = terrain.GetSlope(normalizedPos);
                            //Reject if slope check fails
                            if (slope < item.slopeRange.x || slope > item.slopeRange.y)
                            {
                                instanceCount = 0;
                                continue;
                            }
                        }

                        if (item.curvatureRange.x > 0 || item.curvatureRange.y < 1f)
                        {
                            float curvature = terrain.SampleConvexity(normalizedPos);
                            //0=concave, 0.5=flat, 1=convex
                            curvature = TerrainSampler.ConvexityToCurvature(curvature);
                            if (curvature < item.curvatureRange.x || curvature > item.curvatureRange.y)
                            {
                                instanceCount = 0;
                                continue;
                            }
                        }

                        //Reject based on layer masks
                        float      spawnChance = 0f;
                        Vector2Int texelIndex  = terrain.SplatmapTexelIndex(normalizedPos);

                        if (item.layerMasks.Count == 0)
                        {
                            spawnChance = 100f;
                        }
                        foreach (TerrainLayerMask layer in item.layerMasks)
                        {
                            Texture2D splat = terrain.terrainData.GetAlphamapTexture(GetSplatmapID(layer.layerID));

                            Color color = splat.GetPixel(texelIndex.x, texelIndex.y);

                            int   channel = layer.layerID % 4;
                            float value   = SampleChannel(color, channel);

                            if (value > 0)
                            {
                                value = Mathf.Clamp01(value - layer.threshold);
                            }
                            value *= 100f;

                            spawnChance += value;
                        }
                        InitializeSeed(x * y + item.seed);
                        if ((Random.value <= spawnChance) == false)
                        {
                            instanceCount = 0;
                        }

                        //if (instanceCount == 1) DebugPoints.Add(wPos, true, sampler.slope);
                        item.instanceCount += instanceCount;
                        //Passed all conditions, spawn one instance here
                        map[x, y] = instanceCount;
                    }
                }


                terrain.terrainData.SetDetailLayer(0, 0, item.index, map);

#if UNITY_EDITOR
                UnityEditor.EditorUtility.ClearProgressBar();
#endif
            }

            onGrassRespawn?.Invoke(item);
        }
Exemplo n.º 2
0
        public void SpawnTree(TreeType item)
        {
            if (item.collisionCheck)
            {
                RebuildCollisionCacheIfNeeded();
            }

            item.instanceCount = 0;
            RefreshTreePrefabs();

            float height, worldHeight, normalizedHeight;

            foreach (Terrain terrain in terrains)
            {
                List <TreeInstance> treeInstanceCollection = new List <TreeInstance>(terrain.terrainData.treeInstances);

                //Clear all existing instances first
                for (int i = 0; i < treeInstanceCollection.Count; i++)
                {
                    foreach (TreePrefab prefab in item.prefabs)
                    {
                        treeInstanceCollection.RemoveAll(x => x.prototypeIndex == prefab.index);
                    }
                }

                InitializeSeed(item.seed);
                item.spawnPoints = PoissonDisc.GetSpawnpoints(terrain, item.distance, item.seed + seed);

                foreach (Vector3 pos in item.spawnPoints)
                {
                    //InitializeSeed(item.seed + index);

                    //Relative position as 0-1 value
                    Vector2 normalizedPos = terrain.GetNormalizedPosition(pos);

                    if (item.collisionCheck)
                    {
                        //Check for collision
                        if (InsideOccupiedCell(terrain, pos, normalizedPos))
                        {
                            continue;
                        }
                    }

                    InitializeSeed(item.seed + (int)pos.x + (int)pos.z);
                    //Skip if failing global probability check
                    if (((Random.value * 100f) <= item.probability) == false)
                    {
                        continue;
                    }

                    TreePrefab prefab = SpawnerBase.GetProbableTree(item);

                    //Failed probability checks entirely
                    if (prefab == null)
                    {
                        continue;
                    }

                    terrain.SampleHeight(normalizedPos, out height, out worldHeight, out normalizedHeight);

                    if (item.rejectUnderwater && worldHeight < waterHeight)
                    {
                        continue;
                    }

                    //Check height
                    if (worldHeight < item.heightRange.x || worldHeight > item.heightRange.y)
                    {
                        continue;
                    }

                    if (item.slopeRange.x > 0 || item.slopeRange.y < 90f)
                    {
                        float slope = terrain.GetSlope(normalizedPos, false);

                        //Reject if slope check fails
                        if (!(slope >= (item.slopeRange.x + 0.001f) && slope <= (item.slopeRange.y)))
                        {
                            continue;
                        }
                    }

                    if (item.curvatureRange.x > 0 || item.curvatureRange.y < 1f)
                    {
                        float curvature = terrain.SampleConvexity(normalizedPos);
                        //0=concave, 0.5=flat, 1=convex
                        curvature = TerrainSampler.ConvexityToCurvature(curvature);
                        if (curvature < item.curvatureRange.x || curvature > item.curvatureRange.y)
                        {
                            continue;
                        }
                    }

                    //Reject based on layer masks
                    Vector2Int texelIndex = terrain.SplatmapTexelIndex(normalizedPos);

                    float spawnChance = 0f;
                    if (item.layerMasks.Count == 0)
                    {
                        spawnChance = 100f;
                    }
                    foreach (TerrainLayerMask layer in item.layerMasks)
                    {
                        Texture2D splat = terrain.terrainData.GetAlphamapTexture(GetSplatmapID(layer.layerID));

                        Color color = splat.GetPixel(texelIndex.x, texelIndex.y);

                        int   channel = layer.layerID % 4;
                        float value   = SampleChannel(color, channel);

                        if (value > 0)
                        {
                            value = Mathf.Clamp01(value - layer.threshold);
                        }
                        value *= 100f;

                        spawnChance += value;
                    }
                    InitializeSeed((int)pos.x * (int)pos.z);
                    if ((Random.value <= spawnChance) == false)
                    {
                        continue;
                    }

                    //Passed all conditions, add instance
                    TreeInstance treeInstance = new TreeInstance();
                    treeInstance.prototypeIndex = prefab.index;

                    treeInstance.position = new Vector3(normalizedPos.x, normalizedHeight, normalizedPos.y);
                    treeInstance.rotation = Random.Range(0f, 359f) * Mathf.Deg2Rad;

                    float scale = Random.Range(item.scaleRange.x, item.scaleRange.y);
                    treeInstance.heightScale = scale;
                    treeInstance.widthScale  = scale;

                    treeInstance.color         = Color.white;
                    treeInstance.lightmapColor = Color.white;

                    treeInstanceCollection.Add(treeInstance);

                    item.instanceCount++;
                }



                item.spawnPoints.Clear();

#if UNITY_2019_1_OR_NEWER
                terrain.terrainData.SetTreeInstances(treeInstanceCollection.ToArray(), false);
#else
                terrain.terrainData.treeInstances = treeInstanceCollection.ToArray();
#endif
            }

            for (int i = 0; i < item.prefabs.Count; i++)
            {
                onTreeRespawn?.Invoke(item.prefabs[i]);
            }
        }