private ulong ParsePackageId(TreeInstance treeInstance)
 {
     ulong result = 0;
     var match = Regex.Match(treeInstance.Info.name, RegexExpression.PackageId);
     if (match.Success && !string.IsNullOrEmpty(match.Value))
         result = ulong.Parse(match.Value);
     return result;
 }
Example #2
0
    void copyTerrain(Terrain origTerrain, string newName, float xMin, float xMax, float zMin, float zMax, int heightmapResolution, int detailResolution, int alphamapResolution)
    {
        if (heightmapResolution < 33 || heightmapResolution > 4097)
        {
            Debug.Log("Invalid heightmapResolution " + heightmapResolution);
            return;
        }
        if (detailResolution < 0 || detailResolution > 4048)
        {
            Debug.Log("Invalid detailResolution " + detailResolution);
            return;
        }
        if (alphamapResolution < 16 || alphamapResolution > 2048)
        {
            Debug.Log("Invalid alphamapResolution " + alphamapResolution);
            return;
        }

        if (xMin < 0 || xMin > xMax || xMax > origTerrain.terrainData.size.x)
        {
            Debug.Log("Invalid xMin or xMax");
            return;
        }
        if (zMin < 0 || zMin > zMax || zMax > origTerrain.terrainData.size.z)
        {
            Debug.Log("Invalid zMin or zMax");
            return;
        }

        if (AssetDatabase.FindAssets(newName).Length != 0)
        {
            Debug.Log("Asset with name " + newName + " already exists");
            return;
        }

        TerrainData td         = new TerrainData();
        GameObject  gameObject = Terrain.CreateTerrainGameObject(td);
        Terrain     newTerrain = gameObject.GetComponent <Terrain>();

        if (!AssetDatabase.IsValidFolder("Assets/Resources"))
        {
            AssetDatabase.CreateFolder("Assets", "Resources");
        }
        // Must do this before Splat
        AssetDatabase.CreateAsset(td, "Assets/Resources/" + newName + ".asset");

        // Copy over all vars
        newTerrain.bakeLightProbesForTrees     = origTerrain.bakeLightProbesForTrees;
        newTerrain.basemapDistance             = origTerrain.basemapDistance;
        newTerrain.castShadows                 = origTerrain.castShadows;
        newTerrain.collectDetailPatches        = origTerrain.collectDetailPatches;
        newTerrain.detailObjectDensity         = origTerrain.detailObjectDensity;
        newTerrain.detailObjectDistance        = origTerrain.detailObjectDistance;
        newTerrain.drawHeightmap               = origTerrain.drawHeightmap;
        newTerrain.drawTreesAndFoliage         = origTerrain.drawTreesAndFoliage;
        newTerrain.editorRenderFlags           = origTerrain.editorRenderFlags;
        newTerrain.heightmapMaximumLOD         = origTerrain.heightmapMaximumLOD;
        newTerrain.heightmapPixelError         = origTerrain.heightmapPixelError;
        newTerrain.legacyShininess             = origTerrain.legacyShininess;
        newTerrain.legacySpecular              = origTerrain.legacySpecular;
        newTerrain.lightmapIndex               = origTerrain.lightmapIndex;
        newTerrain.lightmapScaleOffset         = origTerrain.lightmapScaleOffset;
        newTerrain.materialTemplate            = origTerrain.materialTemplate;
        newTerrain.materialType                = origTerrain.materialType;
        newTerrain.realtimeLightmapIndex       = origTerrain.realtimeLightmapIndex;
        newTerrain.realtimeLightmapScaleOffset = origTerrain.realtimeLightmapScaleOffset;
        newTerrain.reflectionProbeUsage        = origTerrain.reflectionProbeUsage;
        newTerrain.treeBillboardDistance       = origTerrain.treeBillboardDistance;
        newTerrain.treeCrossFadeLength         = origTerrain.treeCrossFadeLength;
        newTerrain.treeDistance                = origTerrain.treeDistance;
        newTerrain.treeMaximumFullLODCount     = origTerrain.treeMaximumFullLODCount;

        td.splatPrototypes  = origTerrain.terrainData.splatPrototypes;
        td.treePrototypes   = origTerrain.terrainData.treePrototypes;
        td.detailPrototypes = origTerrain.terrainData.detailPrototypes;

        // Get percent of original
        float xMinNorm = xMin / origTerrain.terrainData.size.x;
        float xMaxNorm = xMax / origTerrain.terrainData.size.x;
        float zMinNorm = zMin / origTerrain.terrainData.size.z;
        float zMaxNorm = zMax / origTerrain.terrainData.size.z;
        float dimRatio1, dimRatio2;

        // Height
        td.heightmapResolution = heightmapResolution;
        float[,] newHeights    = new float[heightmapResolution, heightmapResolution];
        dimRatio1 = (xMax - xMin) / heightmapResolution;
        dimRatio2 = (zMax - zMin) / heightmapResolution;
        for (int i = 0; i < heightmapResolution; i++)
        {
            for (int j = 0; j < heightmapResolution; j++)
            {
                // Divide by size.y because height is stored as percentage
                // Note this is [j, i] and not [i, j] (Why?!)
                newHeights[j, i] = origTerrain.SampleHeight(new Vector3(xMin + (i * dimRatio1), 0, zMin + (j * dimRatio2))) / origTerrain.terrainData.size.y;
            }
        }
        td.SetHeightsDelayLOD(0, 0, newHeights);

        // Detail
        td.SetDetailResolution(detailResolution, 8); // Default? Haven't messed with resolutionPerPatch
        for (int layer = 0; layer < origTerrain.terrainData.detailPrototypes.Length; layer++)
        {
            int[,] detailLayer = origTerrain.terrainData.GetDetailLayer(
                Mathf.FloorToInt(xMinNorm * origTerrain.terrainData.detailWidth),
                Mathf.FloorToInt(zMinNorm * origTerrain.terrainData.detailHeight),
                Mathf.FloorToInt((xMaxNorm - xMinNorm) * origTerrain.terrainData.detailWidth),
                Mathf.FloorToInt((zMaxNorm - zMinNorm) * origTerrain.terrainData.detailHeight),
                layer);
            int[,] newDetailLayer = new int[detailResolution, detailResolution];
            dimRatio1             = (float)detailLayer.GetLength(0) / detailResolution;
            dimRatio2             = (float)detailLayer.GetLength(1) / detailResolution;
            for (int i = 0; i < newDetailLayer.GetLength(0); i++)
            {
                for (int j = 0; j < newDetailLayer.GetLength(1); j++)
                {
                    newDetailLayer[i, j] = detailLayer[Mathf.FloorToInt(i * dimRatio1), Mathf.FloorToInt(j * dimRatio2)];
                }
            }
            td.SetDetailLayer(0, 0, layer, newDetailLayer);
        }

        // Splat
        td.alphamapResolution = alphamapResolution;
        float[,,] alphamaps   = origTerrain.terrainData.GetAlphamaps(
            Mathf.FloorToInt(xMinNorm * origTerrain.terrainData.alphamapWidth),
            Mathf.FloorToInt(zMinNorm * origTerrain.terrainData.alphamapHeight),
            Mathf.FloorToInt((xMaxNorm - xMinNorm) * origTerrain.terrainData.alphamapWidth),
            Mathf.FloorToInt((zMaxNorm - zMinNorm) * origTerrain.terrainData.alphamapHeight));
        // Last dim is always origTerrain.terrainData.splatPrototypes.Length so don't ratio
        float[,,] newAlphamaps = new float[alphamapResolution, alphamapResolution, alphamaps.GetLength(2)];
        dimRatio1 = (float)alphamaps.GetLength(0) / alphamapResolution;
        dimRatio2 = (float)alphamaps.GetLength(1) / alphamapResolution;
        for (int i = 0; i < newAlphamaps.GetLength(0); i++)
        {
            for (int j = 0; j < newAlphamaps.GetLength(1); j++)
            {
                for (int k = 0; k < newAlphamaps.GetLength(2); k++)
                {
                    newAlphamaps[i, j, k] = alphamaps[Mathf.FloorToInt(i * dimRatio1), Mathf.FloorToInt(j * dimRatio2), k];
                }
            }
        }
        td.SetAlphamaps(0, 0, newAlphamaps);

        // Tree
        for (int i = 0; i < origTerrain.terrainData.treeInstanceCount; i++)
        {
            TreeInstance ti = origTerrain.terrainData.treeInstances[i];
            if (ti.position.x < xMinNorm || ti.position.x >= xMaxNorm)
            {
                continue;
            }
            if (ti.position.z < zMinNorm || ti.position.z >= zMaxNorm)
            {
                continue;
            }
            ti.position = new Vector3(((ti.position.x * origTerrain.terrainData.size.x) - xMin) / (xMax - xMin), ti.position.y, ((ti.position.z * origTerrain.terrainData.size.z) - zMin) / (zMax - zMin));
            newTerrain.AddTreeInstance(ti);
        }

        gameObject.transform.position = new Vector3(origTerrain.transform.position.x + xMin, origTerrain.transform.position.y, origTerrain.transform.position.z + zMin);
        gameObject.name = newName;

        // Must happen after setting heightmapResolution
        td.size = new Vector3(xMax - xMin, origTerrain.terrainData.size.y, zMax - zMin);

        AssetDatabase.SaveAssets();
    }
		public void AddTreeInstance(TreeInstance instance){}
Example #4
0
        public void PopulateGroupData(
            ushort segmentID, uint laneID, NetInfo.Lane laneInfo, bool destroyed,
            NetNode.Flags startFlags, NetNode.Flags endFlags,
            float startAngle, float endAngle,
            bool invert, bool terrainHeight, int layer,
            ref int vertexIndex, ref int triangleIndex, Vector3 groupPosition, RenderGroup.MeshData data, ref Vector3 min, ref Vector3 max, ref float maxRenderDistance, ref float maxInstanceDistance, ref bool hasProps)
        {
            NetLaneProps laneProps = laneInfo.m_laneProps;

            if (laneProps?.m_props == null)
            {
                return;
            }
            bool backward = (laneInfo.m_finalDirection & NetInfo.Direction.Both) == NetInfo.Direction.Backward || (laneInfo.m_finalDirection & NetInfo.Direction.AvoidBoth) == NetInfo.Direction.AvoidForward;
            bool reverse  = backward != invert;

            if (backward)  //swap
            {
                NetNode.Flags flags = startFlags;
                startFlags = endFlags;
                endFlags   = flags;
            }
            int nProps = laneProps.m_props.Length;

            for (int i = 0; i < nProps; i++)
            {
                NetLaneProps.Prop prop = laneProps.m_props[i];
                if (!prop.CheckFlags(m_flags, startFlags, endFlags) || m_length < prop.m_minLength)
                {
                    continue;
                }
                int repeatCountTimes2 = 2;
                if (prop.m_repeatDistance > 1f)
                {
                    repeatCountTimes2 *= Mathf.Max(1, Mathf.RoundToInt(m_length / prop.m_repeatDistance));
                }
                float halfSegmentOffset = prop.m_segmentOffset * 0.5f;
                if (m_length != 0f)
                {
                    halfSegmentOffset = Mathf.Clamp(halfSegmentOffset + prop.m_position.z / m_length, -0.5f, 0.5f);
                }
                if (reverse)
                {
                    halfSegmentOffset = 0f - halfSegmentOffset;
                }
                PropInfo finalProp = prop.m_finalProp;
                if ((object)finalProp != null)
                {
                    hasProps = true;
                    if (finalProp.m_prefabDataLayer == layer || finalProp.m_effectLayer == layer)
                    {
                        Color      color = Color.white;
                        Randomizer r     = new Randomizer((int)laneID + i);
                        for (int j = 1; j <= repeatCountTimes2; j += 2)
                        {
                            if (r.Int32(100u) >= prop.m_probability)
                            {
                                continue;
                            }
                            float    t         = halfSegmentOffset + (float)j / (float)repeatCountTimes2;
                            PropInfo variation = finalProp.GetVariation(ref r);
                            float    scale     = variation.m_minScale + (float)r.Int32(10000u) * (variation.m_maxScale - variation.m_minScale) * 0.0001f;
                            if (prop.m_colorMode == NetLaneProps.ColorMode.Default)
                            {
                                color = variation.GetColor(ref r);
                            }
                            if (!variation.m_isDecal && destroyed)
                            {
                                continue;
                            }
                            Vector3 pos = m_bezier.Position(t);
                            Vector3 tan = m_bezier.Tangent(t);
                            if (!(tan != Vector3.zero))
                            {
                                continue;
                            }
                            if (reverse)
                            {
                                tan = -tan;
                            }
                            tan.y = 0f;
                            if (prop.m_position.x != 0f)
                            {
                                tan    = Vector3.Normalize(tan);
                                pos.x += tan.z * prop.m_position.x;
                                pos.z -= tan.x * prop.m_position.x;
                            }
                            float normalAngle = Mathf.Atan2(tan.x, 0f - tan.z);
                            if (prop.m_cornerAngle != 0f || prop.m_position.x != 0f)
                            {
                                float angleDiff = endAngle - startAngle;
                                if (angleDiff > Mathf.PI)
                                {
                                    angleDiff -= Mathf.PI * 2f;
                                }
                                if (angleDiff < -Mathf.PI)
                                {
                                    angleDiff += Mathf.PI * 2f;
                                }
                                var angle2 = startAngle + angleDiff * t - normalAngle;
                                if (angle2 > Mathf.PI)
                                {
                                    angle2 -= Mathf.PI * 2f;
                                }
                                if (angle2 < -Mathf.PI)
                                {
                                    angle2 += Mathf.PI * 2f;
                                }
                                normalAngle += angle2 * prop.m_cornerAngle;
                                if (angle2 != 0f && prop.m_position.x != 0f)
                                {
                                    float d = Mathf.Tan(angle2);
                                    pos.x += tan.x * d * prop.m_position.x;
                                    pos.z += tan.z * d * prop.m_position.x;
                                }
                            }
                            if (terrainHeight)
                            {
                                if (variation.m_requireWaterMap)
                                {
                                    pos.y = Singleton <TerrainManager> .instance.SampleRawHeightSmoothWithWater(pos, timeLerp : false, 0f);
                                }
                                else
                                {
                                    pos.y = Singleton <TerrainManager> .instance.SampleDetailHeight(pos);
                                }
                            }
                            pos.y += prop.m_position.y;
                            InstanceID id = default(InstanceID);
                            id.NetSegment = segmentID;
                            PropInstance.PopulateGroupData(angle: normalAngle + prop.m_angle * (Mathf.PI / 180f), info: variation, layer: layer, id: id, position: pos, scale: scale, color: color, vertexIndex: ref vertexIndex, triangleIndex: ref triangleIndex, groupPosition: groupPosition, data: data, min: ref min, max: ref max, maxRenderDistance: ref maxRenderDistance, maxInstanceDistance: ref maxInstanceDistance);
                        }
                    }
                }
                if (destroyed)
                {
                    continue;
                }
                TreeInfo finalTree = prop.m_finalTree;
                if ((object)finalTree == null)
                {
                    continue;
                }
                hasProps = true;
                if (finalTree.m_prefabDataLayer != layer)
                {
                    continue;
                }
                Randomizer r2 = new Randomizer((int)laneID + i);
                for (int k = 1; k <= repeatCountTimes2; k += 2)
                {
                    if (r2.Int32(100u) >= prop.m_probability)
                    {
                        continue;
                    }
                    float    t          = halfSegmentOffset + (float)k / (float)repeatCountTimes2;
                    TreeInfo variation2 = finalTree.GetVariation(ref r2);
                    float    scale2     = variation2.m_minScale + (float)r2.Int32(10000u) * (variation2.m_maxScale - variation2.m_minScale) * 0.0001f;
                    float    brightness = variation2.m_minBrightness + (float)r2.Int32(10000u) * (variation2.m_maxBrightness - variation2.m_minBrightness) * 0.0001f;
                    Vector3  vector3    = m_bezier.Position(t);
                    if (prop.m_position.x != 0f)
                    {
                        Vector3 vector4 = m_bezier.Tangent(t);
                        if (reverse)
                        {
                            vector4 = -vector4;
                        }
                        vector4.y  = 0f;
                        vector4    = Vector3.Normalize(vector4);
                        vector3.x += vector4.z * prop.m_position.x;
                        vector3.z -= vector4.x * prop.m_position.x;
                    }
                    if (terrainHeight)
                    {
                        vector3.y = Singleton <TerrainManager> .instance.SampleDetailHeight(vector3);
                    }
                    vector3.y += prop.m_position.y;
                    TreeInstance.PopulateGroupData(variation2, vector3, scale2, brightness, RenderManager.DefaultColorLocation, ref vertexIndex, ref triangleIndex, groupPosition, data, ref min, ref max, ref maxRenderDistance, ref maxInstanceDistance);
                }
            }
        }
Example #5
0
    private void TraverseColliders(GameObject gameObject, List <ColliderShapePair> colliderList, GameObject rootObject, NewtonBody body)
    {
        // Don't fetch colliders from children with NewtonBodies
        if ((gameObject == rootObject) || (gameObject.GetComponent <NewtonBody>() == null))
        {
            //Fetch all colliders
            foreach (NewtonCollider collider in gameObject.GetComponents <NewtonCollider>())
            {
                dNewtonCollision shape = collider.CreateBodyShape(body.m_world);
                if (shape != null)
                {
                    ColliderShapePair pair;
                    pair.m_collider = collider;
                    pair.m_shape    = shape;
                    colliderList.Add(pair);
                }
            }

            Terrain terrain = gameObject.GetComponent <Terrain>();
            if (terrain)
            {
                NewtonHeighfieldCollider heighfield = gameObject.GetComponent <NewtonHeighfieldCollider>();
                if (heighfield)
                {
                    TerrainData data = terrain.terrainData;

                    int             treesCount        = data.treeInstanceCount;
                    TreeInstance[]  treeInstanceArray = data.treeInstances;
                    TreePrototype[] treeProtoArray    = data.treePrototypes;

                    Vector3 posit = Vector3.zero;
                    for (int i = 0; i < treesCount; i++)
                    {
                        TreeInstance tree = treeInstanceArray[i];
                        posit.x = tree.position.x * data.size.x;
                        posit.y = tree.position.y * data.size.y;
                        posit.z = tree.position.z * data.size.z;

                        //Debug.Log("xxx0 " + posit);
                        TreePrototype treeProto      = treeProtoArray[tree.prototypeIndex];
                        GameObject    treeGameObject = treeProto.prefab;
                        foreach (NewtonCollider treeCollider in treeGameObject.GetComponents <NewtonCollider>())
                        {
                            dNewtonCollision treeShape = treeCollider.CreateBodyShape(body.m_world);
                            if (treeShape != null)
                            {
                                ColliderShapePair pair;
                                Vector3           treePosit = terrain.transform.position + treeCollider.m_posit + posit;
                                //Debug.Log("xxx1 " + treePosit);
                                dMatrix matrix = Utils.ToMatrix(treePosit, Quaternion.identity);
                                treeShape.SetMatrix(matrix);

                                pair.m_collider = treeCollider;
                                pair.m_shape    = treeShape;
                                colliderList.Add(pair);
                            }
                        }
                    }
                }
            }


            foreach (Transform child in gameObject.transform)
            {
                TraverseColliders(child.gameObject, colliderList, rootObject, body);
            }
        }
    }
Example #6
0
    void SplitIt()
    {
        if (Selection.activeGameObject == null)
        {
            Debug.LogWarning("No terrain was selected");
            return;
        }

        var objects            = Selection.objects;
        var currentObjectIndex = 0;

        foreach (var obj in objects)
        {
            currentObjectIndex++;

            var tObj = obj as GameObject;

            if (tObj == null)
            {
                continue;
            }

            parentTerrain = tObj.GetComponent <Terrain>() as Terrain;

            if (parentTerrain == null)
            {
                Debug.LogWarning("Current selection is not a terrain");
                return;
            }

            var progressCaption = "Spliting terrain " + parentTerrain.name + " (" + currentObjectIndex.ToString() + " of " + objects.Length.ToString() + ")";

            //Split terrain
            for (int i = 0; i < terrainsCount; i++)
            {
                EditorUtility.DisplayProgressBar(progressCaption, "Process " + i, (float)i / terrainsCount);

                TerrainData td  = new TerrainData();
                GameObject  tgo = Terrain.CreateTerrainGameObject(td);

                tgo.name = parentTerrain.name + " " + i;

                terrainData.Add(td);
                terrainGo.Add(tgo);

                Terrain genTer = tgo.GetComponent(typeof(Terrain)) as Terrain;
                genTer.terrainData = td;

                AssetDatabase.CreateAsset(td, "Assets/" + genTer.name + ".asset");


                // Assign splatmaps
                genTer.terrainData.splatPrototypes = parentTerrain.terrainData.splatPrototypes;

                // Assign detail prototypes
                genTer.terrainData.detailPrototypes = parentTerrain.terrainData.detailPrototypes;

                // Assign tree information
                genTer.terrainData.treePrototypes = parentTerrain.terrainData.treePrototypes;


                // Copy parent terrain propeties
                #region parent properties
                genTer.basemapDistance         = parentTerrain.basemapDistance;
                genTer.castShadows             = parentTerrain.castShadows;
                genTer.detailObjectDensity     = parentTerrain.detailObjectDensity;
                genTer.detailObjectDistance    = parentTerrain.detailObjectDistance;
                genTer.heightmapMaximumLOD     = parentTerrain.heightmapMaximumLOD;
                genTer.heightmapPixelError     = parentTerrain.heightmapPixelError;
                genTer.treeBillboardDistance   = parentTerrain.treeBillboardDistance;
                genTer.treeCrossFadeLength     = parentTerrain.treeCrossFadeLength;
                genTer.treeDistance            = parentTerrain.treeDistance;
                genTer.treeMaximumFullLODCount = parentTerrain.treeMaximumFullLODCount;

                #endregion

                //Start processing it

                // Translate peace to position
                #region translate peace to right position

                Vector3 parentPosition = parentTerrain.GetPosition();

                int terraPeaces = (int)Mathf.Sqrt(terrainsCount);

                float spaceShiftX = parentTerrain.terrainData.size.z / terraPeaces;
                float spaceShiftY = parentTerrain.terrainData.size.x / terraPeaces;

                float xWShift = (i % terraPeaces) * spaceShiftX;
                float zWShift = (i / terraPeaces) * spaceShiftY;

                tgo.transform.position = new Vector3(tgo.transform.position.x + zWShift,
                                                     tgo.transform.position.y,
                                                     tgo.transform.position.z + xWShift);

                // Shift last position
                tgo.transform.position = new Vector3(tgo.transform.position.x + parentPosition.x,
                                                     tgo.transform.position.y + parentPosition.y,
                                                     tgo.transform.position.z + parentPosition.z
                                                     );



                #endregion

                // Split height
                #region split height

                Debug.Log("Split height");

                //Copy heightmap
                td.heightmapResolution = parentTerrain.terrainData.heightmapResolution / terraPeaces;

                //Keep y same
                td.size = new Vector3(parentTerrain.terrainData.size.x / terraPeaces,
                                      parentTerrain.terrainData.size.y,
                                      parentTerrain.terrainData.size.z / terraPeaces
                                      );

                float[,] parentHeight = parentTerrain.terrainData.GetHeights(0, 0, parentTerrain.terrainData.heightmapResolution, parentTerrain.terrainData.heightmapResolution);

                float[,] peaceHeight = new float[parentTerrain.terrainData.heightmapResolution / terraPeaces + 1,
                                                 parentTerrain.terrainData.heightmapResolution / terraPeaces + 1
                                       ];

                // Shift calc
                int heightShift = parentTerrain.terrainData.heightmapResolution / terraPeaces;

                int startX = 0;
                int startY = 0;

                int endX = 0;
                int endY = 0;

                if (i == 0)
                {
                    startX = startY = 0;
                    endX   = endY = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1;
                }

                if (i == 1)
                {
                    startX = startY = 0;
                    endX   = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1;
                    endY   = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1;
                }

                if (i == 2)
                {
                    startX = startY = 0;
                    endX   = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1;
                    endY   = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1;
                }

                if (i == 3)
                {
                    startX = startY = 0;
                    endX   = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1;
                    endY   = parentTerrain.terrainData.heightmapResolution / terraPeaces + 1;
                }

                // iterate
                for (int x = startX; x < endX; x++)
                {
                    EditorUtility.DisplayProgressBar(progressCaption, "Split height", (float)x / (endX - startX));

                    for (int y = startY; y < endY; y++)
                    {
                        int xShift = 0;
                        int yShift = 0;

                        //
                        if (i == 0)
                        {
                            xShift = 0;
                            yShift = 0;
                        }

                        //
                        if (i == 1)
                        {
                            xShift = heightShift;
                            yShift = 0;
                        }

                        //
                        if (i == 2)
                        {
                            xShift = 0;
                            yShift = heightShift;
                        }

                        if (i == 3)
                        {
                            xShift = heightShift;
                            yShift = heightShift;
                        }

                        float ph = parentHeight[x + xShift, y + yShift];

                        peaceHeight[x, y] = ph;
                    }
                }

                EditorUtility.ClearProgressBar();

                // Set heightmap to child
                genTer.terrainData.SetHeights(0, 0, peaceHeight);
                #endregion

                // Split splat map
                #region split splat map

                td.alphamapResolution = parentTerrain.terrainData.alphamapResolution / terraPeaces;

                float[,,] parentSplat = parentTerrain.terrainData.GetAlphamaps(0, 0, parentTerrain.terrainData.alphamapResolution, parentTerrain.terrainData.alphamapResolution);

                float[,,] peaceSplat = new float[parentTerrain.terrainData.alphamapResolution / terraPeaces,
                                                 parentTerrain.terrainData.alphamapResolution / terraPeaces,
                                                 parentTerrain.terrainData.alphamapLayers
                                       ];

                // Shift calc
                int splatShift = parentTerrain.terrainData.alphamapResolution / terraPeaces;

                if (i == 0)
                {
                    startX = startY = 0;
                    endX   = endY = parentTerrain.terrainData.alphamapResolution / terraPeaces;
                }

                if (i == 1)
                {
                    startX = startY = 0;
                    endX   = parentTerrain.terrainData.alphamapResolution / terraPeaces;
                    endY   = parentTerrain.terrainData.alphamapResolution / terraPeaces;
                }

                if (i == 2)
                {
                    startX = startY = 0;
                    endX   = parentTerrain.terrainData.alphamapResolution / terraPeaces;
                    endY   = parentTerrain.terrainData.alphamapResolution / terraPeaces;
                }

                if (i == 3)
                {
                    startX = startY = 0;
                    endX   = parentTerrain.terrainData.alphamapResolution / terraPeaces;
                    endY   = parentTerrain.terrainData.alphamapResolution / terraPeaces;
                }

                // iterate
                for (int s = 0; s < parentTerrain.terrainData.alphamapLayers; s++)
                {
                    for (int x = startX; x < endX; x++)
                    {
                        EditorUtility.DisplayProgressBar(progressCaption, "Processing splat...", (float)x / (endX - startX));

                        for (int y = startY; y < endY; y++)
                        {
                            int xShift = 0;
                            int yShift = 0;

                            //
                            if (i == 0)
                            {
                                xShift = 0;
                                yShift = 0;
                            }

                            //
                            if (i == 1)
                            {
                                xShift = splatShift;
                                yShift = 0;
                            }

                            //
                            if (i == 2)
                            {
                                xShift = 0;
                                yShift = splatShift;
                            }

                            if (i == 3)
                            {
                                xShift = splatShift;
                                yShift = splatShift;
                            }

                            float ph = parentSplat[x + xShift, y + yShift, s];
                            peaceSplat[x, y, s] = ph;
                        }
                    }
                }

                EditorUtility.ClearProgressBar();

                // Set heightmap to child
                genTer.terrainData.SetAlphamaps(0, 0, peaceSplat);
                #endregion

                // Split detail map
                #region split detail map

                td.SetDetailResolution(parentTerrain.terrainData.detailResolution / terraPeaces, 8);

                for (int detLay = 0; detLay < parentTerrain.terrainData.detailPrototypes.Length; detLay++)
                {
                    int[,] parentDetail = parentTerrain.terrainData.GetDetailLayer(0, 0, parentTerrain.terrainData.detailResolution, parentTerrain.terrainData.detailResolution, detLay);

                    int[,] peaceDetail = new int[parentTerrain.terrainData.detailResolution / terraPeaces,
                                                 parentTerrain.terrainData.detailResolution / terraPeaces
                                         ];

                    // Shift calc
                    int detailShift = parentTerrain.terrainData.detailResolution / terraPeaces;

                    if (i == 0)
                    {
                        startX = startY = 0;
                        endX   = endY = parentTerrain.terrainData.detailResolution / terraPeaces;
                    }

                    if (i == 1)
                    {
                        startX = startY = 0;
                        endX   = parentTerrain.terrainData.detailResolution / terraPeaces;
                        endY   = parentTerrain.terrainData.detailResolution / terraPeaces;
                    }

                    if (i == 2)
                    {
                        startX = startY = 0;
                        endX   = parentTerrain.terrainData.detailResolution / terraPeaces;
                        endY   = parentTerrain.terrainData.detailResolution / terraPeaces;
                    }

                    if (i == 3)
                    {
                        startX = startY = 0;
                        endX   = parentTerrain.terrainData.detailResolution / terraPeaces;
                        endY   = parentTerrain.terrainData.detailResolution / terraPeaces;
                    }

                    // iterate
                    for (int x = startX; x < endX; x++)
                    {
                        EditorUtility.DisplayProgressBar(progressCaption, "Processing detail...", (float)x / (endX - startX));

                        for (int y = startY; y < endY; y++)
                        {
                            int xShift = 0;
                            int yShift = 0;

                            //
                            if (i == 0)
                            {
                                xShift = 0;
                                yShift = 0;
                            }

                            //
                            if (i == 1)
                            {
                                xShift = detailShift;
                                yShift = 0;
                            }

                            //
                            if (i == 2)
                            {
                                xShift = 0;
                                yShift = detailShift;
                            }

                            if (i == 3)
                            {
                                xShift = detailShift;
                                yShift = detailShift;
                            }

                            int ph = parentDetail[x + xShift, y + yShift];
                            peaceDetail[x, y] = ph;
                        }
                    }
                    EditorUtility.ClearProgressBar();

                    // Set heightmap to child
                    genTer.terrainData.SetDetailLayer(0, 0, detLay, peaceDetail);
                }
                #endregion

                // Split tree data
                #region  split tree data

                for (int t = 0; t < parentTerrain.terrainData.treeInstances.Length; t++)
                {
                    EditorUtility.DisplayProgressBar(progressCaption, "Processing trees...", (float)t / parentTerrain.terrainData.treeInstances.Length);

                    // Get tree instance
                    TreeInstance ti = parentTerrain.terrainData.treeInstances[t];

                    // First section
                    if (i == 0 &&
                        ti.position.x > 0f && ti.position.x < 0.5f &&
                        ti.position.z > 0f && ti.position.z < 0.5f
                        )
                    {
                        // Recalculate new tree position
                        ti.position = new Vector3(ti.position.x * 2f, ti.position.y, ti.position.z * 2f);

                        // Add tree instance
                        genTer.AddTreeInstance(ti);
                    }

                    // Second section
                    if (i == 1 &&
                        ti.position.x > 0.0f && ti.position.x < 0.5f &&
                        ti.position.z >= 0.5f && ti.position.z <= 1.0f
                        )
                    {
                        // Recalculate new tree position
                        ti.position = new Vector3((ti.position.x) * 2f, ti.position.y, (ti.position.z - 0.5f) * 2f);

                        // Add tree instance
                        genTer.AddTreeInstance(ti);
                    }

                    // Third section
                    if (i == 2 &&
                        ti.position.x >= 0.5f && ti.position.x <= 1.0f &&
                        ti.position.z > 0.0f && ti.position.z < 0.5f
                        )
                    {
                        // Recalculate new tree position
                        ti.position = new Vector3((ti.position.x - 0.5f) * 2f, ti.position.y, (ti.position.z) * 2f);

                        // Add tree instance
                        genTer.AddTreeInstance(ti);
                    }

                    // Fourth section
                    if (i == 3 &&
                        ti.position.x >= 0.5f && ti.position.x <= 1.0f &&
                        ti.position.z >= 0.5f && ti.position.z <= 1.0f
                        )
                    {
                        // Recalculate new tree position
                        ti.position = new Vector3((ti.position.x - 0.5f) * 2f, ti.position.y, (ti.position.z - 0.5f) * 2f);

                        // Add tree instance
                        genTer.AddTreeInstance(ti);
                    }
                }
                #endregion

                AssetDatabase.SaveAssets();
            }

            EditorUtility.ClearProgressBar();
        }
    }
Example #7
0
    public GameObject CloneTerrain(Terrain sourceTerrain, TerrainData workData, string desiredObjectName)
    {
        // READONLY: TODO: Heightmap Width
        // READONLY: TODO: Heightmap Height
        // Heightmap Resolution
        workData.heightmapResolution = sourceTerrain.terrainData.heightmapResolution;
        // Heightmap Scale TODO: READ ONLY :(
        // workData.heightmapScale = sourceTerrain.terrainData.heightmapScale;
        // Size
        workData.size = sourceTerrain.terrainData.size;
        // Waving Grass Strength
        workData.wavingGrassStrength = sourceTerrain.terrainData.wavingGrassStrength;
        // Waving Grass Amount
        workData.wavingGrassAmount = sourceTerrain.terrainData.wavingGrassAmount;
        // Waving Grass Speed
        workData.wavingGrassSpeed = sourceTerrain.terrainData.wavingGrassSpeed;
        // Waving Grass Tint
        workData.wavingGrassTint = sourceTerrain.terrainData.wavingGrassTint;
        // Detail Width TODO: READ ONLY :(
        // workData.detailWidth = sourceTerrain.terrainData.detailWidth;
        // Detail Height TODO: READ ONLY :(
        // workData.detailHeight = sourceTerrain.terrainData.detailHeight;
        // Detail Prototypes = DetailPrototype[]
        DetailPrototype[] workPrototypes = new DetailPrototype[sourceTerrain.terrainData.detailPrototypes.Length];

        for (int dp = 0; dp < workPrototypes.Length; dp++)
        {
            DetailPrototype clonedPrototype = new DetailPrototype();

            // prototype
            clonedPrototype.prototype = sourceTerrain.terrainData.detailPrototypes[dp].prototype;
            // prototypeTexture
            clonedPrototype.prototypeTexture = sourceTerrain.terrainData.detailPrototypes[dp].prototypeTexture;
            // minWidth
            clonedPrototype.minWidth = sourceTerrain.terrainData.detailPrototypes[dp].minWidth;
            // maxWidth
            clonedPrototype.maxWidth = sourceTerrain.terrainData.detailPrototypes[dp].maxWidth;
            // minHeight
            clonedPrototype.minHeight = sourceTerrain.terrainData.detailPrototypes[dp].minHeight;
            // maxHeight
            clonedPrototype.maxHeight = sourceTerrain.terrainData.detailPrototypes[dp].maxHeight;
            // noiseSpread
            clonedPrototype.noiseSpread = sourceTerrain.terrainData.detailPrototypes[dp].noiseSpread;
            // bendFactor
            clonedPrototype.bendFactor = sourceTerrain.terrainData.detailPrototypes[dp].bendFactor;
            // healthyColor
            clonedPrototype.healthyColor = sourceTerrain.terrainData.detailPrototypes[dp].healthyColor;
            // dryColor
            clonedPrototype.dryColor = sourceTerrain.terrainData.detailPrototypes[dp].dryColor;
            // renderMode
            clonedPrototype.renderMode = sourceTerrain.terrainData.detailPrototypes[dp].renderMode;

            workPrototypes[dp] = clonedPrototype;
        }

        workData.detailPrototypes = workPrototypes;

        // Tree Instances = TreeInstance[]
        TreeInstance[] workTrees = new TreeInstance[sourceTerrain.terrainData.treeInstances.Length];

        for (int ti = 0; ti < workTrees.Length; ti++)
        {
            TreeInstance clonedTree = new TreeInstance();

            // position
            clonedTree.position = sourceTerrain.terrainData.treeInstances[ti].position;
            // widthScale
            clonedTree.widthScale = sourceTerrain.terrainData.treeInstances[ti].widthScale;
            // heightScale
            clonedTree.heightScale = sourceTerrain.terrainData.treeInstances[ti].heightScale;
            // color
            clonedTree.color = sourceTerrain.terrainData.treeInstances[ti].color;
            // lightmapColor
            clonedTree.lightmapColor = sourceTerrain.terrainData.treeInstances[ti].lightmapColor;
            // prototypeIndex
            clonedTree.prototypeIndex = sourceTerrain.terrainData.treeInstances[ti].prototypeIndex;

            workTrees[ti] = clonedTree;
        }

        workData.treeInstances = workTrees;

        // Tree Prototypes = TreePrototype[]
        TreePrototype[] workTreePrototypes = new TreePrototype[sourceTerrain.terrainData.treePrototypes.Length];

        for (int tp = 0; tp < workTreePrototypes.Length; tp++)
        {
            TreePrototype clonedTreePrototype = new TreePrototype();

            // prefab
            clonedTreePrototype.prefab = sourceTerrain.terrainData.treePrototypes[tp].prefab;
            // bendFactor
            clonedTreePrototype.bendFactor = sourceTerrain.terrainData.treePrototypes[tp].bendFactor;

            workTreePrototypes[tp] = clonedTreePrototype;
        }

        workData.treePrototypes = workTreePrototypes;

        // Alphamap Layers TODO: READ ONLY :(
        // workData.alphamapLayers = sourceTerrain.terrainData.alphamapLayers;
        // Alphamap Resolution
        workData.alphamapResolution = sourceTerrain.terrainData.alphamapResolution;
        // Alphamap Width TODO: READ ONLY :(
        // workData.alphamapWidth = sourceTerrain.terrainData.alphamapWidth;
        // Alphamap Height TODO: READ ONLY :(
        // workData.alphamapHeight = sourceTerrain.terrainData.alphamapHeight;
        // Base Map Resolution
        workData.baseMapResolution = sourceTerrain.terrainData.baseMapResolution;
        // Splat Prototypes = SplatPrototype[]
        SplatPrototype[] workSplatPrototypes = new SplatPrototype[sourceTerrain.terrainData.splatPrototypes.Length];

        for (int sp = 0; sp < workSplatPrototypes.Length; sp++)
        {
            SplatPrototype clonedSplatPrototype = new SplatPrototype();
            // texture
            clonedSplatPrototype.texture = sourceTerrain.terrainData.splatPrototypes[sp].texture;
            // tileSize
            clonedSplatPrototype.tileSize = sourceTerrain.terrainData.splatPrototypes[sp].tileSize;
            // tileOffset
            clonedSplatPrototype.tileOffset = sourceTerrain.terrainData.splatPrototypes[sp].tileOffset;

            workSplatPrototypes[sp] = clonedSplatPrototype;
        }

        workData.splatPrototypes = workSplatPrototypes;

        // TODO: Figure out how to copy the resolutionPerPatch - currently hard coded to 16
        workData.SetDetailResolution(sourceTerrain.terrainData.detailResolution, 16);

        float[,] sourceHeights = sourceTerrain.terrainData.GetHeights(0, 0, sourceTerrain.terrainData.heightmapResolution, sourceTerrain.terrainData.heightmapResolution);
        workData.SetHeights(0, 0, sourceHeights);

        float[,,] sourceAlphamaps = sourceTerrain.terrainData.GetAlphamaps(0, 0, sourceTerrain.terrainData.alphamapWidth, sourceTerrain.terrainData.alphamapHeight);
        workData.SetAlphamaps(0, 0, sourceAlphamaps);

        float[,,] newAlphamaps = workData.GetAlphamaps(0, 0, workData.alphamapWidth, workData.alphamapHeight);
        // Detail Layers

        int numDetailLayers = sourceTerrain.terrainData.detailPrototypes.Length;

        for (int layNum = 0; layNum < numDetailLayers; layNum++)
        {
            int[,] thisDetailLayer = sourceTerrain.terrainData.GetDetailLayer(0, 0, sourceTerrain.terrainData.detailWidth, sourceTerrain.terrainData.detailHeight, layNum);
            workData.SetDetailLayer(0, 0, layNum, thisDetailLayer);
        }

        // FUNCTIONS:::
        for (int dli = 0; dli < sourceTerrain.terrainData.detailPrototypes.Length; dli++)
        {
            int[,] curDetailLayer = sourceTerrain.terrainData.GetDetailLayer(0, 0, sourceTerrain.terrainData.detailResolution, sourceTerrain.terrainData.detailResolution, dli);

            workData.SetDetailLayer(0, 0, dli, curDetailLayer);
        }
        // Get Detail Layer
        // Set Detail Layer
        // Get Alphamaps
        // Set Alphamaps
        // Refresh Prototypes
        // Set Detail Resolution
        // Set Heights


        // Step 2: Terrain.CreateTerrainGameObject()
        // TODO: See if I really need this...
        Terrain workTerrain = Terrain.CreateTerrainGameObject(workData).GetComponent <Terrain>();

        workTerrain.gameObject.name = desiredObjectName;
        // Step 3: Copy remaining settings

        // Terrain Data
        // DONE ABOVE
        // Tree Distance
        workTerrain.treeDistance = sourceTerrain.treeDistance;
        // Tree Billboard Distance
        workTerrain.treeBillboardDistance = sourceTerrain.treeBillboardDistance;
        // Tree Cros Fade Length
        workTerrain.treeCrossFadeLength = sourceTerrain.treeCrossFadeLength;
        // Tree Maximum Full LOD Count
        workTerrain.treeMaximumFullLODCount = sourceTerrain.treeMaximumFullLODCount;
        // Detail Object Distance
        workTerrain.detailObjectDistance = sourceTerrain.detailObjectDistance;
        // Detail Object Density
        workTerrain.detailObjectDensity = sourceTerrain.detailObjectDensity;
        // Heightmap Pixel Error
        workTerrain.heightmapPixelError = sourceTerrain.heightmapPixelError;
        // Heightmap Maximum LOD
        workTerrain.heightmapMaximumLOD = sourceTerrain.heightmapMaximumLOD;
        // Baseman Distance
        workTerrain.basemapDistance = sourceTerrain.basemapDistance;
        // Lightmap Index
        workTerrain.lightmapIndex = sourceTerrain.lightmapIndex;
        // Cast Shadows
        workTerrain.castShadows = sourceTerrain.castShadows;
        // Editor Render Flags

        // Step 4: Flush
        workData.RefreshPrototypes();
        workTerrain.Flush();

        // Step 5: Duplicate children
        for (int i = 0; i < sourceTerrain.transform.childCount; i++)
        {
            Transform child = sourceTerrain.transform.GetChild(i);

            GameObject newChild = Instantiate(child.gameObject) as GameObject;
            newChild.gameObject.name  = child.gameObject.name;
            newChild.transform.parent = workTerrain.transform;
        }

        return(workTerrain.gameObject);
    }
Example #8
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 probabilty 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;

                    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
            }
        }
Example #9
0
    void AddTree()
    {
        TreePrototype[] trees = new TreePrototype[treeDataList.Count];

        for (int i = 0; i < treeDataList.Count; i++)
        {
            trees[i]        = new TreePrototype();
            trees[i].prefab = treeDataList[i].treeMesh;
        }

        terrainData.treePrototypes = trees;

        List <TreeInstance> treeInstanceList = new List <TreeInstance>();

        if (addTree)
        {
            for (int z = 0; z < terrainData.size.z; z += treeSpacing)
            {
                for (int x = 0; x < terrainData.size.x; x += treeSpacing)
                {
                    for (int treePrototypeIndex = 0; treePrototypeIndex < trees.Length; treePrototypeIndex++)
                    {
                        if (treeInstanceList.Count < maxTrees)
                        {
                            float currentHeight = terrainData.GetHeight(x, z) / terrainData.size.y;

                            if (currentHeight >= treeDataList[treePrototypeIndex].minHeight &&
                                currentHeight <= treeDataList[treePrototypeIndex].maxHeight)
                            {
                                float randomX = (x + Random.Range(-randomXRange, randomXRange)) / terrainData.size.x;
                                float randomZ = (z + Random.Range(-randomZRange, randomZRange)) / terrainData.size.z;

                                TreeInstance treeInstance = new TreeInstance();

                                treeInstance.position = new Vector3(randomX, currentHeight, randomZ);

                                Vector3 treePosition = new Vector3(treeInstance.position.x * terrainData.size.x,
                                                                   treeInstance.position.y * terrainData.size.y,
                                                                   treeInstance.position.z * terrainData.size.z) + this.transform.position;



                                RaycastHit raycastHit;
                                int        layerMask = 1 << terrainLayerIndex;

                                if (Physics.Raycast(treePosition, Vector3.down, out raycastHit, 100, layerMask) ||
                                    Physics.Raycast(treePosition, Vector3.up, out raycastHit, 100, layerMask))
                                {
                                    float treeHeight = (raycastHit.point.y - this.transform.position.y) / terrainData.size.y;

                                    treeInstance.position = new Vector3(treeInstance.position.x, treeHeight, treeInstance.position.z);

                                    treeInstance.rotation       = Random.Range(0, 360);
                                    treeInstance.prototypeIndex = treePrototypeIndex;
                                    treeInstance.color          = Color.white;
                                    treeInstance.lightmapColor  = Color.white;
                                    treeInstance.heightScale    = 0.95f;
                                    treeInstance.widthScale     = 0.95f;

                                    treeInstanceList.Add(treeInstance);
                                }
                            }
                        }
                    }
                }
            }
        }

        terrainData.treeInstances = treeInstanceList.ToArray();
    }
Example #10
0
    private IEnumerator RefreshRegion()
    {
        bProcessing = true;

        #region PREPARE_DATA
        yield return(0);

        m_allTreesInLayer.Clear();
        m_mapPrototype.Clear();
        m_listPrototype.Clear();

        List <int> cnk_list_to_render = RSubTerrainMgr.Instance.ChunkListToRender();
        int        cnk_count          = cnk_list_to_render.Count;
        for (int i = 0; i < cnk_count; ++i)
        {
            int             idx           = cnk_list_to_render[i];
            List <TreeInfo> trees_in_zone = RSubTerrainMgr.ReadChunk(idx).TreeList;
            foreach (TreeInfo ti in trees_in_zone)
            {
                // Add tree
                float height = RSubTerrainMgr.Instance.GlobalPrototypeBounds[ti.m_protoTypeIdx].extents.y * 2F;
                // Trees in this layer
                if (RSubTerrainMgr.Instance.Layers[LayerIndex].MinTreeHeight <= height &&
                    height < RSubTerrainMgr.Instance.Layers[LayerIndex].MaxTreeHeight)
                {
                    m_allTreesInLayer.Add(ti);
                    // New prototype ?
                    if (!m_mapPrototype.ContainsKey(ti.m_protoTypeIdx))
                    {
                        int next_index = m_listPrototype.Count;
                        m_mapPrototype.Add(ti.m_protoTypeIdx, next_index);
                        m_listPrototype.Add(ti.m_protoTypeIdx);
                    }
                }
            }
        }

        TreePrototype [] FinalPrototypeArray = new TreePrototype [m_listPrototype.Count];
        for (int i = 0; i < m_listPrototype.Count; ++i)
        {
            FinalPrototypeArray[i]            = new TreePrototype();
            FinalPrototypeArray[i].bendFactor = RSubTerrainMgr.Instance.GlobalPrototypeBendFactorList[m_listPrototype[i]];
            FinalPrototypeArray[i].prefab     = RSubTerrainMgr.Instance.GlobalPrototypePrefabList[m_listPrototype[i]];
        }

        yield return(0);

        int             tree_cnt = m_allTreesInLayer.Count;
        TreeInstance [] FinalTreeInstanceArray = new TreeInstance [tree_cnt];

        for (int t = 0; t < tree_cnt; ++t)
        {
            TreeInfo ti      = m_allTreesInLayer[t];
            Vector3  new_pos = ti.m_pos - _TargetPos;
            new_pos.x /= RSubTerrConstant.TerrainSize.x;
            new_pos.y /= RSubTerrConstant.TerrainSize.y;
            new_pos.z /= RSubTerrConstant.TerrainSize.z;

#if false
            if (new_pos.x < 0 || new_pos.y < 0 || new_pos.z < 0 ||
                new_pos.x > 1 || new_pos.y > 1 || new_pos.z > 1)
            {
                Debug.LogError("a tree was out of terrain bound, error!");
                continue;
            }
#endif
            if (m_mapPrototype.ContainsKey(ti.m_protoTypeIdx))                  // Add key present check
            {
                FinalTreeInstanceArray[t].color          = ti.m_clr;
                FinalTreeInstanceArray[t].heightScale    = ti.m_heightScale;
                FinalTreeInstanceArray[t].widthScale     = ti.m_widthScale;
                FinalTreeInstanceArray[t].lightmapColor  = ti.m_lightMapClr;
                FinalTreeInstanceArray[t].position       = new_pos;
                FinalTreeInstanceArray[t].prototypeIndex = m_mapPrototype[ti.m_protoTypeIdx];
            }
        }

        yield return(0);

        #endregion

        #region ASSIGN_DATA
        gameObject.SetActive(false);
        m_TerrData.treeInstances  = new TreeInstance[0];
        m_TerrData.treePrototypes = FinalPrototypeArray;
        m_TerrData.treeInstances  = FinalTreeInstanceArray;

        if (Application.isEditor)
        {
            _TreePrototypeCount = m_TerrData.treePrototypes.Length;
            _TreeInstanceCount  = m_TerrData.treeInstances.Length;
        }
        transform.position = _TargetPos;
        gameObject.SetActive(true);
        #endregion

        bProcessing = false;
    }
Example #11
0
    private void DoRotate(float angle, Terrain newTerrain)
    {
        if (terrainTmp == null || origHeightMap == null)
        {
            grabOriginal = false;
            Debug.LogWarning("No terrain to rotate");
            return;
        }

        isRotating = true;

        //Terrain terrain = o.GetComponent<Terrain>();

        int   nx, ny;
        float cs, sn;

        // heightmap rotation
        int tw = terrainTmp.terrainData.heightmapWidth;
        int th = terrainTmp.terrainData.heightmapHeight;

        float[,] newHeightMap = new float[tw, th];
        float angleRad     = angle * Mathf.Deg2Rad;
        float heightMiddle = (terrainTmp.terrainData.heightmapResolution) / 2.0f; // pivot at middle

        for (int y = 0; y < th; y++)
        {
            for (int x = 0; x < tw; x++)
            {
                cs = Mathf.Cos(angleRad);
                sn = Mathf.Sin(angleRad);

                nx = (int)((x - heightMiddle) * cs - (y - heightMiddle) * sn + heightMiddle);
                ny = (int)((x - heightMiddle) * sn + (y - heightMiddle) * cs + heightMiddle);

                if (nx < 0)
                {
                    nx = 0;
                }
                if (nx > tw - 1)
                {
                    nx = tw - 1;
                }
                if (ny < 0)
                {
                    ny = 0;
                }
                if (ny > th - 1)
                {
                    ny = th - 1;
                }

                newHeightMap[x, y] = origHeightMap[nx, ny];
            } // for x
        }     // for y



        // detail layer (grass, meshes)
        int   dw           = terrainTmp.terrainData.detailWidth;
        int   dh           = terrainTmp.terrainData.detailHeight;
        float detailMiddle = (terrainTmp.terrainData.detailResolution) / 2.0f; // pivot at middle
        int   numDetails   = terrainTmp.terrainData.detailPrototypes.Length;

        int[][,] newDetailLayer = new int[numDetails][, ];

        // build new layer arrays
        for (int n = 0; n < numDetails; n++)
        {
            newDetailLayer[n] = new int[dw, dh];
        }

        for (int z = 0; z < numDetails; z++)
        {
            for (int y = 0; y < dh; y++)
            {
                for (int x = 0; x < dw; x++)
                {
                    cs = Mathf.Cos(angleRad);
                    sn = Mathf.Sin(angleRad);

                    nx = (int)((x - detailMiddle) * cs - (y - detailMiddle) * sn + detailMiddle);
                    ny = (int)((x - detailMiddle) * sn + (y - detailMiddle) * cs + detailMiddle);


                    if (nx < 0)
                    {
                        nx = 0;
                    }
                    if (nx > dw - 1)
                    {
                        nx = dw - 1;
                    }
                    if (ny < 0)
                    {
                        ny = 0;
                    }
                    if (ny > dh - 1)
                    {
                        ny = dh - 1;
                    }

                    newDetailLayer[z][x, y] = origDetailLayer[z][nx, ny];
                } // for x
            }     // for y
        }         // for z


        // alpha layer (texture splatmap) rotation
        dw = terrainTmp.terrainData.alphamapWidth;
        dh = terrainTmp.terrainData.alphamapHeight;
        int   dz          = terrainTmp.terrainData.alphamapLayers;
        float alphaMiddle = (terrainTmp.terrainData.alphamapResolution) / 2.0f; // pivot at middle

        float[,,] newAlphaMap = new float[dw, dh, dz];
        float[,,] origAlphaMapCopy;
        origAlphaMapCopy = origAlphaMap.Clone() as float[, , ];

        for (int z = 0; z < dz; z++)
        {
            for (int y = 0; y < dh; y++)
            {
                for (int x = 0; x < dw; x++)
                {
                    cs = Mathf.Cos(angleRad);
                    sn = Mathf.Sin(angleRad);

                    nx = (int)((x - alphaMiddle) * cs - (y - alphaMiddle) * sn + alphaMiddle);
                    ny = (int)((x - alphaMiddle) * sn + (y - alphaMiddle) * cs + alphaMiddle);

                    if (nx < 0)
                    {
                        nx = 0;
                    }
                    if (nx > dw - 1)
                    {
                        nx = dw - 1;
                    }
                    if (ny < 0)
                    {
                        ny = 0;
                    }
                    if (ny > dh - 1)
                    {
                        ny = dh - 1;
                    }

                    newAlphaMap[x, y, z] = origAlphaMapCopy[nx, ny, z];
                } // for x
            }     // for y
        }         // for z



        // trees rotation, one by one..
        // TODO: use list instead, then can remove trees outside the terrain
        int treeCount = terrainTmp.terrainData.treeInstances.Length;

        TreeInstance[] newTrees = new TreeInstance[treeCount];
        Vector3        newTreePos = Vector3.zero;
        float          tx, tz;

        for (int n = 0; n < treeCount; n++)
        {
            cs = Mathf.Cos(angleRad);
            sn = Mathf.Sin(angleRad);

            tx = origTrees[n].position.x - 0.5f;
            tz = origTrees[n].position.z - 0.5f;

            newTrees[n] = origTrees[n];

            newTreePos.x = (cs * tx) - (sn * tz) + 0.5f;
            newTreePos.y = origTrees[n].position.y;
            newTreePos.z = (cs * tz) + (sn * tx) + 0.5f;

            newTrees[n].position = newTreePos;
        } // for treeCount

        // this is too slow in unity..
        //Undo.RecordObject(terrain.terrainData,"Rotate terrain ("+angle+")");

        // Apply new data to terrain
        //newTerrain.terrainData.treeInstances = newTrees;
        newTerrain.terrainData.treeInstances = new TreeInstance[] { /*newTrees[0]*/ }; //Just a test to delete tree colliders
        newTerrain.terrainData.SetHeightsDelayLOD(0, 0, newHeightMap);                 // splitting up SetHeights part1
        newTerrain.ApplyDelayedHeightmapModification();                                //part2
        //newTerrain.terrainData.treeInstances = newTrees;
        newTerrain.terrainData.SetAlphamaps(0, 0, newAlphaMap);
        for (int n = 0; n < terrainTmp.terrainData.detailPrototypes.Length; n++)
        {
            newTerrain.terrainData.SetDetailLayer(0, 0, n, newDetailLayer[n]);
        }

        // we are done..
        isRotating = false;
    } //TerrainRotate
        public void TerrainToolboxUtilites_WhenSplitTerrain_MissingTrees(int amountOfTreesX, int amountOfTreesZ, int tileXAxis, int tileZAxis)
        {
            //Setup tree prefab (Needs to be persistent)
            GameObject treePrefab = GameObject.CreatePrimitive(PrimitiveType.Cube);

            treePrefab.GetComponent <Renderer>().sharedMaterial.shader = Shader.Find("Nature/Tree Soft Occlusion Bark");
            string localPath = $"Assets/{treePrefab.name}.prefab";

            localPath = AssetDatabase.GenerateUniqueAssetPath(localPath);
            PrefabUtility.SaveAsPrefabAsset(treePrefab, localPath);
            treePrefab = AssetDatabase.LoadAssetAtPath(localPath, typeof(GameObject)) as GameObject;

            //Setup terrain object with trees
            TerrainData   terrainData = m_TerrainComponent.terrainData;
            TreePrototype prototype   = new TreePrototype();

            prototype.prefab = treePrefab;

            terrainData.treePrototypes = new TreePrototype[]
            {
                prototype
            };

            TreeInstance[] treeInstancesArray = new TreeInstance[amountOfTreesX * amountOfTreesZ];
            for (int z = 0; z < amountOfTreesZ; z++)
            {
                for (int x = 0; x < amountOfTreesX; x++)
                {
                    TreeInstance treeInstance = new TreeInstance();
                    treeInstance.prototypeIndex = 0;
                    treeInstance.position       = new Vector3(x / (float)amountOfTreesX, 0, z / (float)amountOfTreesZ);
                    treeInstancesArray[(z * amountOfTreesZ) + x] = treeInstance;
                }
            }
            terrainData.treeInstances = treeInstancesArray;


            // Set up parent object so we can locate the split tiles for cleanup after testing
            int groupingId = 12345;
            var parent     = new GameObject().AddComponent <TerrainGroup>();

            parent.GroupID = groupingId;
            m_TerrainComponent.transform.SetParent(parent.transform);

            //Execute the repro steps checking to make sure split terrains have trees
            Selection.activeGameObject = m_TerrainGO;
            TerrainToolboxWindow toolboxWindow = EditorWindow.GetWindow(typeof(TerrainToolboxWindow)) as TerrainToolboxWindow;

            toolboxWindow.m_TerrainUtilitiesMode.m_Settings.KeepOldTerrains = true;
            toolboxWindow.m_TerrainUtilitiesMode.m_Settings.TileXAxis       = tileXAxis;
            toolboxWindow.m_TerrainUtilitiesMode.m_Settings.TileZAxis       = tileZAxis;
            toolboxWindow.m_TerrainUtilitiesMode.SplitTerrains(true);

            Terrain[] objs          = GameObject.FindObjectsOfType <Terrain>();
            Terrain[] splitTerrains = objs.Where(
                obj => obj.terrainData?.treeInstanceCount > 0
                ).ToArray();
            Assert.IsNotEmpty(splitTerrains);

            //Cleanup
            toolboxWindow.Close();
            FileUtil.DeleteFileOrDirectory("Assets/Terrain");
            File.Delete("Assets/Terrain.meta");
            File.Delete(localPath);
            File.Delete(localPath + ".meta");
            UnityEditor.AssetDatabase.Refresh();
        }
Example #13
0
    void Setup()
    {
        if (target.terrainTemplate == null)
        {
            throw new UnityException("No terrain template assigned.");
        }
        if (target.terrainTemplate.terrainData == null)
        {
            throw new UnityException("Terrain template has no terrain data.");
        }
        if (target.terrainTemplate.materialTemplate == null)
        {
            throw new UnityException("Terrain template has no base material template data.");
        }

        var ooBoundsSize    = target.transform.localScale;
        var ooBoundsExtents = ooBoundsSize * 0.5f;

        var targetPos     = target.transform.position;
        var targetRight   = target.transform.right;
        var targetForward = target.transform.forward;

        var ooPlanes = new [] {
            new Plane(targetRight, targetPos + targetRight * ooBoundsExtents.x),
            new Plane(-targetRight, targetPos - targetRight * ooBoundsExtents.x),
            new Plane(targetForward, targetPos + targetForward * ooBoundsExtents.z),
            new Plane(-targetForward, targetPos - targetForward * ooBoundsExtents.z),
        };

        var aaBounds = new Bounds(Vector3.zero, Vector3.one);

        aaBounds.Encapsulate(targetRight * ooBoundsExtents.x + Vector3.up * ooBoundsExtents.y + targetForward * ooBoundsExtents.z);
        aaBounds.Encapsulate(-targetRight * ooBoundsExtents.x + -Vector3.up * ooBoundsExtents.y + -targetForward * ooBoundsExtents.z);
        aaBounds.Encapsulate(-targetRight * ooBoundsExtents.x + Vector3.up * ooBoundsExtents.y + targetForward * ooBoundsExtents.z);
        aaBounds.Encapsulate(targetRight * ooBoundsExtents.x + -Vector3.up * ooBoundsExtents.y + -targetForward * ooBoundsExtents.z);

        var aaBoundsSize    = aaBounds.size;
        var aaBoundsExtents = aaBounds.extents;

        if (target.autoColliders)
        {
            // GeometryUtility.TestPlanesAABB won't accept my OO planes, so
            // let's just use a world space AABB test instead.
            var aaBoundsWorld = new Bounds(targetPos + aaBounds.center, aaBounds.size);

            foreach (var mr in Object.FindObjectsOfType <MeshRenderer>())
            {
                if (mr.GetComponent <Collider>() == null)
                {
                    if (aaBoundsWorld.Intersects(mr.bounds))
                    {
                        target.autoColliderList.Add(mr.gameObject.AddComponent <MeshCollider>());
                    }
                }
            }
        }

        var terrainCorner = targetPos - aaBoundsExtents;

        var xStepCount = Mathf.NextPowerOfTwo(Mathf.CeilToInt(aaBoundsSize.x * target.density));
        var zStepCount = Mathf.NextPowerOfTwo(Mathf.CeilToInt(aaBoundsSize.z * target.density));

        int ZM  = zStepCount;
        int XM  = xStepCount;
        int XZM = Mathf.Max(XM, ZM);

        var xStep = (float)XM / (float)XZM * aaBoundsSize.x / (float)xStepCount;
        var zStep = (float)ZM / (float)XZM * aaBoundsSize.z / (float)zStepCount;

        GameObject[] paintingObjects  = target.paintingObjects;
        GameObject[] blockingObjects  = target.blockingObjects;
        bool         hasExplicitPaint = paintingObjects != null && paintingObjects.Length > 0;
        bool         hasExplicitBlock = blockingObjects != null && blockingObjects.Length > 0;

        LayerMask paintingLayers = hasExplicitPaint ? (LayerMask) ~0 : target.paintingLayers;
        LayerMask blockingLayers = hasExplicitBlock ? (LayerMask) ~0 : target.blockingLayers;

        float rayLength   = aaBoundsSize.y;
        float heightScale = 1f / rayLength;

        var castRadius = target.castRadius;

        var heightmap = new float[XZM, XZM];
        var maskmap   = new float[XZM, XZM];

        var oldSelfTerrainCollider = target.workingObject ? target.workingObject.GetComponent <TerrainCollider>() : null;

        for (int z = 0; z < XZM; ++z)
        {
            for (int x = 0; x < XZM; ++x)
            {
                var pos = terrainCorner + new Vector3(x * xStep, aaBoundsSize.y, z * zStep);

                if (ooPlanes[0].GetSide(pos) || ooPlanes[1].GetSide(pos) || ooPlanes[2].GetSide(pos) || ooPlanes[3].GetSide(pos))
                {
                    heightmap[z, x] = 0f;
                    maskmap[z, x]   = 0f;
                    continue;
                }

                float targetDist = rayLength;
                float targetMask = 1f;

                var rhisDown = Physics.SphereCastAll(pos, castRadius, Vector3.down, rayLength, paintingLayers);
                if (rhisDown.Length > 0)
                {
                    for (int i = 0, n = rhisDown.Length; i < n; ++i)
                    {
                        var rhiDown = rhisDown[i];

                        var validTerrain = !(rhiDown.collider is TerrainCollider) ||
                                           (target.allowTerrainColliders && (oldSelfTerrainCollider == null || rhiDown.collider != oldSelfTerrainCollider));
                        if (
                            validTerrain &&
                            (!hasExplicitPaint || System.Array.IndexOf(paintingObjects, rhiDown.collider.gameObject) != -1) &&
                            System.Array.IndexOf(blockingObjects, rhiDown.collider.gameObject) == -1
                            )
                        {
                            var curDist = pos.y - rhiDown.point.y;                            // rhiDown.distance + castRadius;
                            if (curDist < targetDist)
                            {
                                targetMask = MaskSlope(rhiDown.normal.y);
                                targetDist = curDist;
                            }
                        }
                    }
                }

                bool hasClearance = true;
                if (targetDist < rayLength && (hasExplicitBlock || blockingLayers.value != 0))
                {
                    float blockedDist = rayLength;

                    var rhisDownBlockers = Physics.SphereCastAll(pos, castRadius, Vector3.down, rayLength, blockingLayers);
                    for (int i = 0, n = rhisDownBlockers.Length; i < n; ++i)
                    {
                        var rhiDown = rhisDownBlockers[i];

                        if (!(rhiDown.collider is TerrainCollider))
                        {
                            if (!hasExplicitBlock || System.Array.IndexOf(blockingObjects, rhiDown.collider.gameObject) != -1)
                            {
                                if (!hasExplicitPaint || System.Array.IndexOf(paintingObjects, rhiDown.collider.gameObject) == -1)
                                {
                                    blockedDist = Mathf.Min(blockedDist, pos.y - rhiDown.point.y /*rhiDown.distance + castRadius*/);
                                }
                            }
                        }
                    }

                    if (blockedDist < targetDist)
                    {
                        const float cBelow = 25f;

                        var          upPos          = pos + Vector3.down * (targetDist + cBelow);
                        RaycastHit[] rhisUpBlockers = Physics.SphereCastAll(upPos, castRadius, Vector3.up, targetDist + cBelow, blockingLayers);
                        for (int i = 0, n = rhisUpBlockers.Length; i < n && hasClearance; ++i)
                        {
                            var rhiUp = rhisUpBlockers[i];

                            if (!(rhiUp.collider is TerrainCollider))
                            {
                                if (!hasExplicitBlock || System.Array.IndexOf(blockingObjects, rhiUp.collider.gameObject) != -1)
                                {
                                    if (!hasExplicitPaint || System.Array.IndexOf(paintingObjects, rhiUp.collider.gameObject) == -1)
                                    {
                                        hasClearance = rhiUp.point.y - upPos.y /*rhiUp.distance + castRadius*/ - cBelow > target.heightClearance;
                                    }
                                }
                            }
                        }
                    }
                }

                bool hasValidSample = hasClearance && targetDist != rayLength;
                heightmap[z, x] = hasValidSample ? Mathf.Clamp01(1f - targetDist * heightScale) : 0f;
                maskmap[z, x]   = hasValidSample ? targetMask : 0f;
            }
        }

        target.heightData = new float[XZM * XZM];
        System.Buffer.BlockCopy(heightmap, 0, target.heightData, 0, target.heightData.Length * sizeof(float));

        target.maskData = new float[XZM * XZM];
        System.Buffer.BlockCopy(maskmap, 0, target.maskData, 0, target.maskData.Length * sizeof(float));

        var ttc = target.terrainTemplate;
        var ttd = ttc.terrainData;

        if (target.workingObject)
        {
            target.workingObject.transform.position += Vector3.up * target.pickingHackFixBias;
        }

        var oldTC = target.workingObject ? target.workingObject.GetComponent <Terrain>() : null;
        //if(oldTC && oldTC.GetComponent<TerrainCollider>())
        //	oldTC.gameObject.AddComponent<TerrainCollider>();
        var td = oldTC ? oldTC.terrainData : new TerrainData();

        td.SetDetailResolution(XZM, 32);
        td.heightmapResolution = XZM;
        td.SetHeights(0, 0, heightmap);
        td.size = aaBoundsSize;

        td.splatPrototypes  = ttd.splatPrototypes;
        td.detailPrototypes = ttd.detailPrototypes;
        td.treePrototypes   = ttd.treePrototypes;

        for (int i = 0, offset = 0, step = target.detailLayerElements * sizeof(int), n = td.detailPrototypes.Length, m = target.detailLayerCount; i < n && i < m; ++i, offset += step)
        {
            var details = td.GetDetailLayer(0, 0, td.detailWidth, td.detailHeight, i);
            System.Buffer.BlockCopy(target.detailData, offset, details, 0, step);
            td.SetDetailLayer(0, 0, i, details);
        }

        if (target.treeInstances != null)
        {
            var tdi = new TreeInstance[target.treeInstances.Length];
            for (int i = 0, n = target.treeInstances.Length; i < n; ++i)
            {
                tdi[i] = (TreeInstance)target.treeInstances[i];
            }
            td.treeInstances = tdi;
        }

        var terrain = oldTC ? oldTC.gameObject : Terrain.CreateTerrainGameObject(td);

        if (oldTC == null)
        {
            var helper = terrain.AddComponent <PaintJobProxy>();
            while (UnityEditorInternal.ComponentUtility.MoveComponentUp(helper))
            {
                ;
            }
        }
        var tc = terrain.GetComponent <Terrain>();

        tc.detailObjectDistance = 1000f;        //ttc.detailObjectDistance;
        tc.detailObjectDensity  = ttc.detailObjectDensity;
        target.materialInstance = tc.materialTemplate = new Material(ttc.materialTemplate);
        tc.castShadows          = false;

        terrain.transform.parent        = target.transform;
        terrain.transform.position      = terrainCorner;
        terrain.transform.localRotation = Quaternion.identity;
        terrain.transform.localScale    = Vector3.one;
        target.workingObject            = terrain;

        target.isPainting  = true;
        target.alignedSize = aaBoundsSize;
        target.materialInstance.SetFloat("_HackCullScale", 1f);
        tc.drawHeightmap = true;

        tc.terrainData.wavingGrassAmount   = 0f;
        tc.terrainData.wavingGrassSpeed    = 0f;
        tc.terrainData.wavingGrassStrength = 0f;
        tc.terrainData.wavingGrassTint     = Color.white;
    }
Example #14
0
 /// <summary>
 /// Return a rotation of a tree instance
 /// </summary>
 /// <param name="treeInstance">the tree instance</param>
 /// <returns>A world space rotation from the tree instance</returns>
 public static Quaternion GetWorldRotation(this TreeInstance treeInstance)
 {
     return(Quaternion.AngleAxis(treeInstance.rotation * Mathf.Rad2Deg, Vector3.up));
 }
Example #15
0
 /// <summary>
 /// Return a scale of a tree instance
 /// </summary>
 /// <param name="treeInstance">the tree instance</param>
 /// <returns>A world space scale from the tree instance</returns>
 public static Vector3 GetWorldScale(this TreeInstance treeInstance)
 {
     return(new Vector3(treeInstance.widthScale, treeInstance.heightScale, treeInstance.widthScale));
 }
Example #16
0
    static void RegenerateForest()
    {
        Forest forest = GameObject.FindObjectOfType(typeof(Forest)) as Forest;

        Selection.activeGameObject = forest.gameObject;

        int layerMask          = ~0;
        int progressUpdateRate = forest.m_instanceCount / 200;

        foreach (var mask in forest.m_ignoreLayers)
        {
            layerMask &= ~(1 << mask);
            Debug.Log("Layer Mask: " + layerMask);
        }

        while (forest.transform.childCount > 0)
        {
            GameObject.DestroyImmediate(forest.transform.GetChild(0).gameObject);
        }

        forest.RebuildSections();
        bool cancel       = false;
        int  treesPlanted = 0;


        // TODO: This won't ever reach the target tree count as it gives up following a collision.
        for (int treeCount = 0; treeCount < forest.m_instanceCount && !cancel; ++treeCount)
        {
            bool succeeded = false;
            int  counter   = 0;

            while (!succeeded && counter < forest.m_retryBailout)
            {
                float x = Random.Range(forest.m_startX, forest.m_endX);
                float z = Random.Range(forest.m_startZ, forest.m_endZ);

                Vector3 position = new Vector3(x, 0.0f, z);

                bool overlap      = Physics.CheckCapsule((Vector3)position + new Vector3(0.0f, -50.0f, 0.0f), (Vector3)position + new Vector3(0.0f, 50.0f, 0.0f), forest.m_treeRadius, layerMask);
                bool terrainValid = true;

                RaycastHit hitInfo;
                if (Physics.Raycast(new Vector3(x, 1.0f, z), new Vector3(0.0f, -1.0f, 0.0f), out hitInfo, 50.0f, ~LayerMask.NameToLayer("WorldCollision")))
                {
                    if (hitInfo.point.y < -0.01f)
                    {
                        terrainValid = false;
                    }
                }

                if (!overlap && terrainValid)
                {
                    try
                    {
                        TreeInstance instance = new TreeInstance();

                        instance.position = position;
                        instance.radius   = UnityEngine.Random.Range(1.0f, 3.5f);

                        succeeded = !forest.AddInstance(instance);

                        if (succeeded)
                        {
                            treesPlanted++;
                        }
                    }
                    catch (System.Exception e)
                    {
                        Debug.Log("Instance out of bound at " + position.x + ", " + position.z);
                        Debug.Log(e);
                        Debug.Break();
                    }

                    counter++;

                    if (treeCount % progressUpdateRate == 0)
                    {
                        cancel = EditorUtility.DisplayCancelableProgressBar("Generating Forest", "Creating trees (" + treeCount + ", " + forest.m_instanceCount + ")", (float)treeCount / (float)forest.m_instanceCount);
                    }
                }
            }
        }

        EditorUtility.ClearProgressBar();

        Debug.Log("Planted " + treesPlanted + " trees");
    }
    public void SerializeTerrainData(List <byte> bytes, TerrainData terrainData)
    {
        R_SerializationHelper.SerializeString(bytes, terrainData.name);

        int heightmapResolution = terrainData.heightmapResolution;
        int detailResolution    = terrainData.detailResolution;

        R_SerializationHelper.SerializeInt(bytes, heightmapResolution);
        R_SerializationHelper.SerializeInt(bytes, terrainData.baseMapResolution);
        R_SerializationHelper.SerializeInt(bytes, terrainData.alphamapResolution);
        R_SerializationHelper.SerializeInt(bytes, detailResolution);
        R_SerializationHelper.SerializeVector3(bytes, terrainData.size);

        R_SerializationHelper.SerializeFloat(bytes, terrainData.thickness);
        R_SerializationHelper.SerializeFloat(bytes, terrainData.wavingGrassAmount);
        R_SerializationHelper.SerializeFloat(bytes, terrainData.wavingGrassSpeed);
        R_SerializationHelper.SerializeFloat(bytes, terrainData.wavingGrassStrength);
        R_SerializationHelper.SerializeColor(bytes, terrainData.wavingGrassTint);


        // Splat textures
        SplatPrototype[] splatPrototypes = terrainData.splatPrototypes;
        R_SerializationHelper.SerializeInt(bytes, splatPrototypes.Length);
        for (int i = 0; i < splatPrototypes.Length; i++)
        {
            SplatPrototype splat = splatPrototypes[i];
            R_SerializationHelper.SerializeFloat(bytes, splat.metallic);
            if (splat.normalMap != null)
            {
                bytes.Add(1);
                R_SerializationHelper.SerializeString(bytes, splat.normalMap.name);
            }
            else
            {
                bytes.Add(0);
            }

            R_SerializationHelper.SerializeFloat(bytes, splat.smoothness);
            R_SerializationHelper.SerializeString(bytes, splat.texture.name);
            R_SerializationHelper.SerializeVector2(bytes, splat.tileOffset);
            R_SerializationHelper.SerializeVector2(bytes, splat.tileSize);
        }

        // Tree Prototypes
        TreePrototype[] treePrototypes = terrainData.treePrototypes;
        R_SerializationHelper.SerializeInt(bytes, treePrototypes.Length);
        for (int i = 0; i < treePrototypes.Length; i++)
        {
            TreePrototype tree = treePrototypes[i];
            R_SerializationHelper.SerializeFloat(bytes, tree.bendFactor);
            R_SerializationHelper.SerializeString(bytes, tree.prefab.name);
        }

        // Grass
        DetailPrototype[] detailPrototypes = terrainData.detailPrototypes;
        int detailPrototypesLength         = detailPrototypes.Length;

        R_SerializationHelper.SerializeInt(bytes, detailPrototypes.Length);
        for (int i = 0; i < detailPrototypes.Length; i++)
        {
            DetailPrototype detail = detailPrototypes[i];
            R_SerializationHelper.SerializeFloat(bytes, detail.bendFactor);
            R_SerializationHelper.SerializeColor(bytes, detail.dryColor);
            R_SerializationHelper.SerializeColor(bytes, detail.healthyColor);
            R_SerializationHelper.SerializeFloat(bytes, detail.maxHeight);
            R_SerializationHelper.SerializeFloat(bytes, detail.maxWidth);
            R_SerializationHelper.SerializeFloat(bytes, detail.minHeight);
            R_SerializationHelper.SerializeFloat(bytes, detail.minWidth);
            R_SerializationHelper.SerializeFloat(bytes, detail.noiseSpread);
            if (detail.prototype != null)
            {
                bytes.Add(1);
                R_SerializationHelper.SerializeString(bytes, detail.prototype.name);
            }
            else
            {
                bytes.Add(0);
            }

            if (detail.prototypeTexture != null)
            {
                bytes.Add(1);
                R_SerializationHelper.SerializeString(bytes, detail.prototypeTexture.name);
            }
            else
            {
                bytes.Add(0);
            }

            R_SerializationHelper.SerializeInt(bytes, (int)detail.renderMode);
        }

        // Heights
        float[,] heights = terrainData.GetHeights(0, 0, heightmapResolution, heightmapResolution);
        R_SerializationHelper.Serialize2DFloatArray(bytes, heights);

        // Splat maps
        R_SerializationHelper.SerializeInt(bytes, terrainData.alphamapTextures.Length);
        for (int i = 0; i < terrainData.alphamapTextures.Length; i++)
        {
            Texture2D tex      = terrainData.alphamapTextures[i];
            byte[]    texBytes = tex.EncodeToPNG();
            R_SerializationHelper.SerializeInt(bytes, texBytes.Length);
            bytes.AddRange(texBytes);
        }

        // Trees
        TreeInstance[] treeInstances = terrainData.treeInstances;
        R_SerializationHelper.SerializeInt(bytes, treeInstances.Length);
        for (int i = 0; i < treeInstances.Length; i++)
        {
            TreeInstance tree = treeInstances[i];
            R_SerializationHelper.SerializeColor(bytes, tree.color);
            R_SerializationHelper.SerializeFloat(bytes, tree.heightScale);
            R_SerializationHelper.SerializeColor(bytes, tree.lightmapColor);
            R_SerializationHelper.SerializeVector3(bytes, tree.position);
            R_SerializationHelper.SerializeInt(bytes, tree.prototypeIndex);
            R_SerializationHelper.SerializeFloat(bytes, tree.rotation);
            R_SerializationHelper.SerializeFloat(bytes, tree.widthScale);
        }

        // Grass
        for (int i = 0; i < detailPrototypesLength; i++)
        {
            int[,] detailMap = terrainData.GetDetailLayer(0, 0, detailResolution, detailResolution, i);
            R_SerializationHelper.Serialize2DIntArrayToBytes(bytes, detailMap);
        }
    }
    public TerrainData DeserializeTerrainData(byte[] bytes, ref int index)
    {
        TerrainData terrainData = new TerrainData();

        terrainData.name = R_SerializationHelper.DeserializeString(bytes, ref index);
        // Debug.Log(terrainData.name);

        int heightmapResolution = R_SerializationHelper.DeserializeInt(bytes, ref index);

        terrainData.heightmapResolution = heightmapResolution;
        terrainData.baseMapResolution   = R_SerializationHelper.DeserializeInt(bytes, ref index);
        terrainData.alphamapResolution  = R_SerializationHelper.DeserializeInt(bytes, ref index);
        int detailResolution = R_SerializationHelper.DeserializeInt(bytes, ref index);

        terrainData.SetDetailResolution(detailResolution, 16);

        terrainData.size = R_SerializationHelper.DeserializeVector3(bytes, ref index);

        terrainData.thickness           = R_SerializationHelper.DeserializeFloat(bytes, ref index);
        terrainData.wavingGrassAmount   = R_SerializationHelper.DeserializeFloat(bytes, ref index);
        terrainData.wavingGrassSpeed    = R_SerializationHelper.DeserializeFloat(bytes, ref index);
        terrainData.wavingGrassStrength = R_SerializationHelper.DeserializeFloat(bytes, ref index);
        terrainData.wavingGrassTint     = R_SerializationHelper.DeserializeColor(bytes, ref index);

        // Splat Textures
        int splatLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        SplatPrototype[] splatPrototypes = new SplatPrototype[splatLength];
        for (int i = 0; i < splatLength; i++)
        {
            SplatPrototype splat = new SplatPrototype();
            splat.metallic = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            if (bytes[index++] == 1)
            {
                string normalName = R_SerializationHelper.DeserializeString(bytes, ref index);
                splat.normalMap = (Texture2D)Resources.Load(normalName);
            }
            splat.smoothness = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            string splatName = R_SerializationHelper.DeserializeString(bytes, ref index);
            splat.texture      = (Texture2D)Resources.Load(splatName);
            splat.tileOffset   = R_SerializationHelper.DeserializeVector2(bytes, ref index);
            splat.tileSize     = R_SerializationHelper.DeserializeVector2(bytes, ref index);
            splatPrototypes[i] = splat;
        }
        terrainData.splatPrototypes = splatPrototypes;

        // Tree Prototypes
        int treeLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        TreePrototype[] treePrototypes = new TreePrototype[treeLength];
        for (int i = 0; i < treeLength; i++)
        {
            TreePrototype tree = new TreePrototype();
            tree.bendFactor = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            string prefabName = R_SerializationHelper.DeserializeString(bytes, ref index);
            tree.prefab       = (GameObject)Resources.Load(prefabName);
            treePrototypes[i] = tree;
        }
        terrainData.treePrototypes = treePrototypes;

        // Grass Prototypes
        int grassLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        DetailPrototype[] detailPrototypes = new DetailPrototype[grassLength];
        for (int i = 0; i < grassLength; i++)
        {
            DetailPrototype grass = new DetailPrototype();
            grass.bendFactor   = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.dryColor     = R_SerializationHelper.DeserializeColor(bytes, ref index);
            grass.healthyColor = R_SerializationHelper.DeserializeColor(bytes, ref index);
            grass.maxHeight    = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.maxWidth     = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.minHeight    = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.minWidth     = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.noiseSpread  = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            if (bytes[index++] == 1)
            {
                R_SerializationHelper.DeserializeString(bytes, ref index);
            }
            if (bytes[index++] == 1)
            {
                string textureName = R_SerializationHelper.DeserializeString(bytes, ref index);
                grass.prototypeTexture = (Texture2D)Resources.Load(textureName);
            }
            grass.renderMode    = (DetailRenderMode)R_SerializationHelper.DeserializeInt(bytes, ref index);
            detailPrototypes[i] = grass;
        }
        terrainData.detailPrototypes = detailPrototypes;

        float[,] heights = R_SerializationHelper.Deserialize2DFloatArray(bytes, ref index);
        terrainData.SetHeights(0, 0, heights);

        int splatmapLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        Texture2D[] alphamapTextures = terrainData.alphamapTextures;

        for (int i = 0; i < splatmapLength; i++)
        {
            int    length   = R_SerializationHelper.DeserializeInt(bytes, ref index);
            byte[] texBytes = new byte[length];
            Array.Copy(bytes, index, texBytes, 0, length);
            index += length;
            alphamapTextures[i].LoadImage(texBytes);
            alphamapTextures[i].Apply();
        }

        int treeInstancesLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        TreeInstance[] trees = new TreeInstance[treeInstancesLength];

        for (int i = 0; i < trees.Length; i++)
        {
            TreeInstance tree = new TreeInstance();
            tree.color          = R_SerializationHelper.DeserializeColor(bytes, ref index);
            tree.heightScale    = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            tree.lightmapColor  = R_SerializationHelper.DeserializeColor(bytes, ref index);
            tree.position       = R_SerializationHelper.DeserializeVector3(bytes, ref index);
            tree.prototypeIndex = R_SerializationHelper.DeserializeInt(bytes, ref index);
            tree.rotation       = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            tree.widthScale     = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            trees[i]            = tree;
        }
        terrainData.treeInstances = trees;

        for (int i = 0; i < grassLength; i++)
        {
            int[,] grassMap = R_SerializationHelper.Deserialize2DByteArrayToInt(bytes, ref index);
            terrainData.SetDetailLayer(0, 0, i, grassMap);
        }

        return(terrainData);
    }
Example #19
0
    public void PlantVegetation()
    {
        TreePrototype[] newTreePrototypes;
        newTreePrototypes = new TreePrototype[vegetation.Count];
        int tindex = 0;

        foreach (Vegetation t in vegetation)
        {
            newTreePrototypes[tindex]        = new TreePrototype();
            newTreePrototypes[tindex].prefab = t.treeMesh;
            tindex++;
        }
        terrainData.treePrototypes = newTreePrototypes;
        List <TreeInstance> allVegetation = new List <TreeInstance>();

        for (int z = 0; z < terrainData.size.z; z += (vegTreeSpacing))
        {
            for (int x = 0; x < terrainData.size.x; x += vegTreeSpacing)
            {
                for (int tp = 0; tp < terrainData.treePrototypes.Length; tp++)
                {
                    if (Random.Range(0.0f, 1.0f) > vegetation[tp].density)
                    {
                        break;
                    }

                    float thisHeight      = terrainData.GetHeight(x, z) / terrainData.size.y;
                    float thisHeightStart = vegetation[tp].minHeight;
                    float thisHeightEnd   = vegetation[tp].maxHeight;
                    float steepness       = terrainData.GetSteepness(x / (float)terrainData.size.x, z / (float)terrainData.size.z);

                    if ((thisHeightEnd >= thisHeight && thisHeightStart <= thisHeight) && (steepness >= vegetation[tp].minSlope && steepness <= vegetation[tp].maxSlope))
                    {
                        TreeInstance instance = new TreeInstance();
                        instance.position = new Vector3((x + Random.Range(-vegRandom, vegRandom)) / terrainData.size.x,
                                                        thisHeight,
                                                        (z + Random.Range(-vegRandom, vegRandom)) / terrainData.size.z);
                        Vector3 treeWorldPos = new Vector3(instance.position.x * terrainData.size.x,
                                                           instance.position.y * terrainData.size.y,
                                                           instance.position.z * terrainData.size.z)
                                               + transform.position;
                        RaycastHit hit;
                        int        layerMask = 1 << terrainLayer;
                        if (Physics.Raycast(treeWorldPos + new Vector3(0, 10, 0), -Vector3.up, out hit, 100, layerMask) || Physics.Raycast(treeWorldPos - new Vector3(0, 10, 0), Vector3.up, out hit, 100, layerMask))
                        {
                            float treeHeight = (hit.point.y - this.transform.position.y) / terrainData.size.y;
                            instance.position = new Vector3(instance.position.x,
                                                            treeHeight,
                                                            instance.position.z);

                            instance.rotation       = Random.Range(vegetation[tp].minRotation, vegetation[tp].maxRotation);
                            instance.prototypeIndex = tp;
                            instance.color          = Color.Lerp(vegetation[tp].colour1,
                                                                 vegetation[tp].colour2,
                                                                 Random.Range(0.0f, 1.0f));
                            instance.lightmapColor = vegetation[tp].lightColour;
                            float scale = Random.Range(vegetation[tp].minScale, vegetation[tp].maxScale);
                            instance.heightScale = scale + Random.Range(-0.6f, 0.6f);
                            instance.widthScale  = scale + Random.Range(-0.6f, 0.6f);
                            allVegetation.Add(instance);
                            if (allVegetation.Count >= vegTreeMax)
                            {
                                goto TREESDONE;
                            }
                        }
                    }
                }
            }
        }

TREESDONE:
        terrainData.treeInstances = allVegetation.ToArray();
    }
Example #20
0
        /// <summary>
        /// Populates the target list with a list of map trees or props.
        /// </summary>
        protected override void TargetList()
        {
            // List of prefabs that have passed filtering.
            List <PropListItem> itemList = new List <PropListItem>();

            // Local references.
            TreeManager treeManager = Singleton <TreeManager> .instance;

            TreeInstance[] trees       = treeManager.m_trees.m_buffer;
            PropManager    propManager = Singleton <PropManager> .instance;

            PropInstance[] props = propManager.m_props.m_buffer;

            // Iterate through each tree instance map.
            for (int index = 0; index < (IsTree ? trees.Length : props.Length); ++index)
            {
                // Create new list item, hiding probabilities.
                PropListItem propListItem = new PropListItem {
                    showProbs = false
                };

                if (IsTree)
                {
                    // Local reference.
                    TreeInstance tree = trees[index];

                    // Skip non-existent trees (those with no flags).
                    if (tree.m_flags == (ushort)TreeInstance.Flags.None)
                    {
                        continue;
                    }

                    // Try to get any tree replacement.
                    propListItem.originalPrefab = MapTreeReplacement.instance.GetOriginal(tree.Info);

                    // DId we find a current replacment?
                    if (propListItem.originalPrefab == null)
                    {
                        // No - set current item as the original tree.
                        propListItem.originalPrefab = tree.Info;
                    }
                    else
                    {
                        // Yes - record current item as replacement.
                        propListItem.replacementPrefab = tree.Info;
                    }
                }
                else
                {
                    // Props.
                    PropInstance prop = props[index];

                    // Skip non-existent props (those with no flags).
                    if (prop.m_flags == (ushort)PropInstance.Flags.None)
                    {
                        continue;
                    }

                    // Try to get any prop replacement.
                    propListItem.originalPrefab = MapPropReplacement.instance.GetOriginal(prop.Info);

                    // DId we find a current replacment?
                    if (propListItem.originalPrefab == null)
                    {
                        // No - set current item as the original prop.
                        propListItem.originalPrefab = prop.Info;
                    }
                    else
                    {
                        // Yes - record current item as replacement.
                        propListItem.replacementPrefab = prop.Info;
                    }
                }

                // Check to see if we were succesful - if not (e.g. we only want trees and this is a prop), continue on to next instance.
                if (propListItem.originalPrefab?.name == null)
                {
                    continue;
                }

                // Map instances are always grouped, and we don't have lists of indexes - too many trees!
                propListItem.index = -1;

                // Are we grouping?
                if (propListItem.index == -1)
                {
                    // Yes, grouping - initialise a flag to show if we've matched.
                    bool matched = false;

                    // Iterate through each item in our existing list of props.
                    foreach (PropListItem item in itemList)
                    {
                        // Check to see if we already have this in the list - matching original prefab.
                        if (item.originalPrefab == propListItem.originalPrefab)
                        {
                            // We've already got an identical grouped instance of this item - set the flag to indicate that we've match it.
                            matched = true;

                            // No point going any further through the list, since we've already found our match.
                            break;
                        }
                    }

                    // Did we get a match?
                    if (matched)
                    {
                        // Yes - continue on to next tree (without adding this item separately to the list).
                        continue;
                    }
                }

                // Add this item to our list.
                itemList.Add(propListItem);
            }

            // Create return fastlist from our filtered list, ordering by name.
            targetList.m_rowsData = new FastList <object>
            {
                m_buffer = targetSearchStatus == (int)OrderBy.NameDescending ? itemList.OrderByDescending(item => item.DisplayName).ToArray() : itemList.OrderBy(item => item.DisplayName).ToArray(),
                m_size   = itemList.Count
            };
            targetList.Refresh();

            // If the list is empty, show the 'no props' label; otherwise, hide it.
            if (targetList.m_rowsData.m_size == 0)
            {
                noPropsLabel.Show();
            }
            else
            {
                noPropsLabel.Hide();
            }
        }
Example #21
0
/*		public static void ExportOBJ(){
 *                      TerrainData terrain = Selection.activeGameObject.GetComponent<Terrain>().terrainData;
 *                      Vector3 terrainPos = Selection.activeGameObject.transform.position;
 *                      string fileName = EditorUtility.SaveFilePanel("Export .obj file", "", "Terrain", "obj");
 *                      int w = terrain.heightmapWidth;
 *                      int h = terrain.heightmapHeight;
 *                      Vector3 meshScale = terrain.size;
 *                      int tRes = (int)Mathf.Pow(2, (int)saveResolution );
 *                      meshScale = new Vector3(meshScale.x / (w - 1) * tRes, meshScale.y, meshScale.z / (h - 1) * tRes);
 *                      Vector2 uvScale = new Vector2(1.0f / (w - 1), 1.0f / (h - 1));
 *                      float[,] tData = terrain.GetHeights(0, 0, w, h);
 *
 *                      w = (w - 1) / tRes + 1;
 *                      h = (h - 1) / tRes + 1;
 *                      Vector3[] tVertices = new Vector3[w * h];
 *                      Vector2[] tUV = new Vector2[w * h];
 *
 *                      int[] tPolys;
 *
 *                      if (saveFormat == SaveFormat.Triangles)
 *                      {
 *                       tPolys = new int[(w - 1) * (h - 1) * 6];
 *                      }
 *                      else
 *                      {
 *                       tPolys = new int[(w - 1) * (h - 1) * 4];
 *                      }
 *
 *                      // Build vertices and UVs
 *                      for (int y = 0; y < h; y++)
 *                      {
 *                       for (int x = 0; x < w; x++)
 *                       {
 *                          tVertices[y * w + x] = Vector3.Scale(meshScale, new Vector3(x, tData[x * tRes, y * tRes], y)) + terrainPos;
 *                          tUV[y * w + x] = Vector2.Scale( new Vector2(x * tRes, y * tRes), uvScale);
 *                       }
 *                      }
 *
 *                      int  index = 0;
 *                      if (saveFormat == SaveFormat.Triangles)
 *                      {
 *                       // Build triangle indices: 3 indices into vertex array for each triangle
 *                       for (int y = 0; y < h - 1; y++)
 *                       {
 *                          for (int x = 0; x < w - 1; x++)
 *                          {
 *                             // For each grid cell output two triangles
 *                             tPolys[index++] = (y * w) + x;
 *                             tPolys[index++] = ((y + 1) * w) + x;
 *                             tPolys[index++] = (y * w) + x + 1;
 *
 *                             tPolys[index++] = ((y + 1) * w) + x;
 *                             tPolys[index++] = ((y + 1) * w) + x + 1;
 *                             tPolys[index++] = (y * w) + x + 1;
 *                          }
 *                       }
 *                      }
 *                      else
 *                      {
 *                       // Build quad indices: 4 indices into vertex array for each quad
 *                       for (int y = 0; y < h - 1; y++)
 *                       {
 *                          for (int x = 0; x < w - 1; x++)
 *                          {
 *                             // For each grid cell output one quad
 *                             tPolys[index++] = (y * w) + x;
 *                             tPolys[index++] = ((y + 1) * w) + x;
 *                             tPolys[index++] = ((y + 1) * w) + x + 1;
 *                             tPolys[index++] = (y * w) + x + 1;
 *                          }
 *                       }
 *                      }
 *
 *                      // Export to .obj
 *                      StreamWriter sw = new StreamWriter(fileName);
 *                      EditorUtility.DisplayProgressBar("Exporting","Exporting to OBJ file",0.5f);
 *
 *                       sw.WriteLine("# Unity terrain OBJ File");
 *
 *                       // Write vertices
 *                       System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
 *                       for (int i = 0; i < tVertices.Length; i++)
 *                       {
 *                          StringBuilder sb = new StringBuilder("v ", 20);
 *                          // StringBuilder stuff is done this way because it's faster than using the "{0} {1} {2}"etc. format
 *                          // Which is important when you're exporting huge terrains.
 *                          sb.Append(tVertices[i].x.ToString()).Append(" ").
 *                             Append(tVertices[i].y.ToString()).Append(" ").
 *                             Append(tVertices[i].z.ToString());
 *                          sw.WriteLine(sb);
 *                       }
 *                       // Write UVs
 *                       for (int i = 0; i < tUV.Length; i++)
 *                       {
 *                          StringBuilder sb = new StringBuilder("vt ", 22);
 *                          sb.Append(tUV[i].x.ToString()).Append(" ").
 *                             Append(tUV[i].y.ToString());
 *                          sw.WriteLine(sb);
 *                       }
 *                       if (saveFormat == SaveFormat.Triangles)
 *                       {
 *                          // Write triangles
 *                          for (int i = 0; i < tPolys.Length; i += 3)
 *                          {
 *                             StringBuilder sb = new StringBuilder("f ", 43);
 *                             sb.Append(tPolys[i] + 1).Append("/").Append(tPolys[i] + 1).Append(" ").
 *                                Append(tPolys[i + 1] + 1).Append("/").Append(tPolys[i + 1] + 1).Append(" ").
 *                                Append(tPolys[i + 2] + 1).Append("/").Append(tPolys[i + 2] + 1);
 *                             sw.WriteLine(sb);
 *                          }
 *                       }
 *                       else
 *                       {
 *                          // Write quads
 *                          for (int i = 0; i < tPolys.Length; i += 4)
 *                          {
 *                             StringBuilder sb = new StringBuilder("f ", 57);
 *                             sb.Append(tPolys[i] + 1).Append("/").Append(tPolys[i] + 1).Append(" ").
 *                                Append(tPolys[i + 1] + 1).Append("/").Append(tPolys[i + 1] + 1).Append(" ").
 *                                Append(tPolys[i + 2] + 1).Append("/").Append(tPolys[i + 2] + 1).Append(" ").
 *                                Append(tPolys[i + 3] + 1).Append("/").Append(tPolys[i + 3] + 1);
 *                             sw.WriteLine(sb);
 *                          }
 *                       }
 *                      sw.Close();
 *                      terrain = null;
 *                      EditorUtility.ClearProgressBar();
 *              }
 */

        public static Texture2D ToTexture(GameObject go, int mapType, int layer = 0)
        {
            TerrainData terdata    = go.GetComponent <Terrain>().terrainData;
            int         res        = 0;
            Texture2D   tmpTexture = new Texture2D(terdata.heightmapResolution, terdata.heightmapResolution);
            Color       tmpColor   = Color.black;

            switch (mapType)
            {
            case 0:             // -- Render Heightmap --
                float[,] tmpHeights = terdata.GetHeights(0, 0, terdata.heightmapResolution, terdata.heightmapResolution);
                for (int hY = 0; hY < terdata.heightmapResolution; hY++)
                {
                    for (int hX = 0; hX < terdata.heightmapResolution; hX++)
                    {
                        tmpTexture.SetPixel(hX, hY, new Color(tmpHeights[hX, hY], tmpHeights[hX, hY], tmpHeights[hX, hY]));
                    }
                }
                break;

            case 1:             // -- Render Splatmap --
                res                 = terdata.alphamapResolution;
                tmpTexture          = new Texture2D(res, res);
                float[,,] alphadata = terdata.GetAlphamaps(0, 0, res, res);
                for (int y = 0; y < res; y++)
                {
                    for (int x = 0; x < res; x++)
                    {
                        if (terdata.splatPrototypes.Length > 1)
                        {
                            tmpColor.r = alphadata[x, y, 1];
                        }
                        if (terdata.splatPrototypes.Length > 2)
                        {
                            tmpColor.g = alphadata[x, y, 2];
                        }
                        else
                        {
                            tmpColor.g = 0.0f;
                        }
                        if (terdata.splatPrototypes.Length > 3)
                        {
                            tmpColor.b = alphadata[x, y, 3];
                        }
                        else
                        {
                            tmpColor.b = 0.0f;
                        }
                        tmpTexture.SetPixel(x, y, tmpColor);
                    }
                }
                break;

            case 2:             // -- Detail Layer --
                res = terdata.detailResolution;
                int[,] detaildata = terdata.GetDetailLayer(0, 0, res, res, layer);
                tmpTexture        = new Texture2D(res, res);
                for (int y = 0; y < res; y++)
                {
                    for (int x = 0; x < res; x++)
                    {
                        tmpColor.r = (1.0f / 16) * detaildata[x, y];
                        tmpTexture.SetPixel(x, y, tmpColor);
                    }
                }
                break;

            case 3:             // -- Tree Layer --
                res        = 256;
                tmpTexture = new Texture2D(res, res);
                for (int y = 0; y < res; y++)
                {
                    for (int x = 0; x < res; x++)
                    {
                        tmpTexture.SetPixel(x, y, Color.black);
                    }
                }
                for (int tI = 0; tI < terdata.treeInstances.Length; tI++)
                {
                    TreeInstance treeInst = terdata.treeInstances[tI];
                    if (treeInst.prototypeIndex == layer)
                    {
                        tmpTexture.SetPixel((int)(treeInst.position.x * res), (int)(treeInst.position.z * res), Color.white);
                    }
                }
                break;
            }
            tmpTexture.Apply();
            return(tmpTexture);
        }
Example #22
0
    private void Update()
    {
        if (startBushGrowth) // && counter%60 == 0)
        {
            float maxDiff = 0;
            for (int i = 0; i < myTerrain.terrainData.treeInstances.Length; i++)
            {
                TreeInstance t = myTerrain.terrainData.GetTreeInstance(i);

                // if it's a resprouter, compute from resprouters, otherwise read from reseeders
                float percentage = (t.prototypeIndex == 0) ? (ResprouterSizes[index] - ResprouterSizes[index - 1]) / ResprouterSizes[index - 1] : (ReseederSizes[index] - ReseederSizes[index - 1]) / ReseederSizes[index - 1];
                if ((ReseederSizes[index] - ReseederSizes[index - 1]) > maxDiff)
                {
                    maxDiff = Mathf.Abs(ReseederSizes[index] - ReseederSizes[index - 1]);
                }
                float x = t.heightScale * (1 + percentage);

                //if scale is dropped drastically and there hasn't been a fire yet
                if (x < 0.65f && !fireOccurred)
                {
                    fireOccurred = true;
                    if (climate.Equals("dry"))
                    {
                        StartSun();
                    }
                    else if (climate.Equals("wet"))
                    {
                        StartRain(new Vector3(0, 50, 0));
                    }
                    else if (climate.Equals("dryandwet"))
                    {
                        StartSun();
                        StartRain(new Vector3(30, 50, 0));
                    }
                    StartFire(5);
                    break;  // break out of the for loop so rest of the bushes are not read
                }
                else
                {
                    if (fireOccurred && (x > 1f)) //reset Fire Occured status to be false
                    {
                        fireOccurred = false;
                    }
                    t.heightScale = x;
                    t.widthScale  = x;
                    myTerrain.terrainData.SetTreeInstance(i, t);
                }
            }
            index++;

            //read until there are no more Biomasses to read
            if (index >= 10 * 365)//15 * 365)//ResprouterSizes.Count - 1)
            {
                //Debug.Log("maxDiff is: " + maxDiff);
                myTerrain.GetComponent <TestGenerator>().DestroyBushes();
                startBushGrowth = false;
                SceneMontroller.Instance.ActivateNextButton(scenario);
                scenario++;
            }
        }
    }
Example #23
0
 internal void AddTreeToTile(TerrainTile tile, TreeInstance tree, int rand)
 {
     tree.position = new Vector3(tile.floatPos.x + Random.Range(0, tilePosJitter), 0f, tile.floatPos.y + Random.Range(0, tilePosJitter));
     terrain.AddTreeInstance(tree);
     tile.TreeInstanceIndex = terrainData.treeInstanceCount - 1;
 }
Example #24
0
    void copyTerrain(Terrain origTerrain, string newName, float xMin, float xMax, float zMin, float zMax, int heightmapResolution, int detailResolution, int alphamapResolution)
    {
        if (xMin < 0 || xMin > xMax || xMax > origTerrain.terrainData.size.x || zMin < 0 || zMin > zMax || zMax > origTerrain.terrainData.size.z)
        {
            return;
        }

        TerrainData td             = new TerrainData();
        GameObject  TerGameObeject = Terrain.CreateTerrainGameObject(td);
        Terrain     newTerrain     = TerGameObeject.GetComponent <Terrain>();

        // Copy over all values
        newTerrain.bakeLightProbesForTrees     = origTerrain.bakeLightProbesForTrees;
        newTerrain.basemapDistance             = origTerrain.basemapDistance;
        newTerrain.castShadows                 = origTerrain.castShadows;
        newTerrain.collectDetailPatches        = origTerrain.collectDetailPatches;
        newTerrain.detailObjectDensity         = origTerrain.detailObjectDensity;
        newTerrain.detailObjectDistance        = origTerrain.detailObjectDistance;
        newTerrain.drawHeightmap               = origTerrain.drawHeightmap;
        newTerrain.drawTreesAndFoliage         = origTerrain.drawTreesAndFoliage;
        newTerrain.editorRenderFlags           = origTerrain.editorRenderFlags;
        newTerrain.heightmapMaximumLOD         = origTerrain.heightmapMaximumLOD;
        newTerrain.heightmapPixelError         = origTerrain.heightmapPixelError;
        newTerrain.legacyShininess             = origTerrain.legacyShininess;
        newTerrain.legacySpecular              = origTerrain.legacySpecular;
        newTerrain.lightmapIndex               = origTerrain.lightmapIndex;
        newTerrain.lightmapScaleOffset         = origTerrain.lightmapScaleOffset;
        newTerrain.materialTemplate            = origTerrain.materialTemplate;
        newTerrain.materialType                = origTerrain.materialType;
        newTerrain.realtimeLightmapIndex       = origTerrain.realtimeLightmapIndex;
        newTerrain.realtimeLightmapScaleOffset = origTerrain.realtimeLightmapScaleOffset;
        newTerrain.reflectionProbeUsage        = origTerrain.reflectionProbeUsage;
        newTerrain.treeBillboardDistance       = origTerrain.treeBillboardDistance;
        newTerrain.treeCrossFadeLength         = origTerrain.treeCrossFadeLength;
        newTerrain.treeDistance                = origTerrain.treeDistance;
        newTerrain.treeMaximumFullLODCount     = origTerrain.treeMaximumFullLODCount;

        td.splatPrototypes  = origTerrain.terrainData.splatPrototypes;
        td.treePrototypes   = origTerrain.terrainData.treePrototypes;
        td.detailPrototypes = origTerrain.terrainData.detailPrototypes;

        float xMinNorm = xMin / origTerrain.terrainData.size.x;
        float xMaxNorm = xMax / origTerrain.terrainData.size.x;
        float zMinNorm = zMin / origTerrain.terrainData.size.z;
        float zMaxNorm = zMax / origTerrain.terrainData.size.z;
        float dimRatio1, dimRatio2;

        //Set height for split terrain part
        td.heightmapResolution = heightmapResolution;
        float[,] newHeights    = new float[heightmapResolution, heightmapResolution];
        dimRatio1 = (xMax - xMin) / heightmapResolution;
        dimRatio2 = (zMax - zMin) / heightmapResolution;
        for (int i = 0; i < heightmapResolution; i++)
        {
            for (int j = 0; j < heightmapResolution; j++)
            {
                newHeights[j, i] = origTerrain.SampleHeight(new Vector3(xMin + (i * dimRatio1), 0, zMin + (j * dimRatio2))) / origTerrain.terrainData.size.y;
            }
        }
        td.SetHeightsDelayLOD(0, 0, newHeights);

        td.SetDetailResolution(detailResolution, 8);

        td.alphamapResolution = alphamapResolution;


        // Set tree for split terrain part
        for (int i = 0; i < origTerrain.terrainData.treeInstanceCount; i++)
        {
            TreeInstance ti = origTerrain.terrainData.treeInstances[i];
            if (ti.position.x < xMinNorm || ti.position.x >= xMaxNorm)
            {
                continue;
            }
            if (ti.position.z < zMinNorm || ti.position.z >= zMaxNorm)
            {
                continue;
            }
            ti.position = new Vector3(((ti.position.x * origTerrain.terrainData.size.x) - xMin) / (xMax - xMin), ti.position.y, ((ti.position.z * origTerrain.terrainData.size.z) - zMin) / (zMax - zMin));
            newTerrain.AddTreeInstance(ti);
        }
        //Set grass for split terrain part
        for (int layer = 0; layer < origTerrain.terrainData.detailPrototypes.Length; layer++)
        {
            int[,] detailLayer = origTerrain.terrainData.GetDetailLayer(
                Mathf.FloorToInt(xMinNorm * origTerrain.terrainData.detailWidth),
                Mathf.FloorToInt(zMinNorm * origTerrain.terrainData.detailHeight),
                Mathf.FloorToInt((xMaxNorm - xMinNorm) * origTerrain.terrainData.detailWidth),
                Mathf.FloorToInt((zMaxNorm - zMinNorm) * origTerrain.terrainData.detailHeight),
                layer);
            int[,] newDetailLayer = new int[detailResolution, detailResolution];
            dimRatio1             = (float)detailLayer.GetLength(0) / detailResolution;
            dimRatio2             = (float)detailLayer.GetLength(1) / detailResolution;
            for (int i = 0; i < newDetailLayer.GetLength(0); i++)
            {
                for (int j = 0; j < newDetailLayer.GetLength(1); j++)
                {
                    newDetailLayer[i, j] = detailLayer[Mathf.FloorToInt(i * dimRatio1), Mathf.FloorToInt(j * dimRatio2)];
                }
            }
            td.SetDetailLayer(0, 0, layer, newDetailLayer);
        }

        TerGameObeject.transform.position = new Vector3(origTerrain.transform.position.x + xMin, origTerrain.transform.position.y, origTerrain.transform.position.z + zMin);
        TerGameObeject.name             = newName;
        TerGameObeject.transform.parent = _terGen.transform;
        td.size = new Vector3(xMax - xMin, origTerrain.terrainData.size.y, zMax - zMin);
    }
        protected override void Init()
        {
            if (splatSettings == null || splatSettings.Length == 0)
            {
                splatSettings = new TerrainVoxelDefinitionMapping[64];
            }
            if (detailSettings == null || detailSettings.Length == 0)
            {
                detailSettings = new VegetationVoxelDefinitionMapping[64];
            }
            if (treeSettings == null || treeSettings.Length == 0)
            {
                treeSettings = new TerrainModelDefinitionMapping[32];
            }
            if (detailLayers == null || detailLayers.Length < 32)
            {
                detailLayers = new DetailLayerInfo[32];
            }
            if (waterVoxel == null)
            {
                waterVoxel = Resources.Load <VoxelDefinition> ("VoxelPlay/Defaults/Water/VoxelWaterSea");
            }
            env.AddVoxelDefinition(bedrockVoxel);

                        #if UNITY_EDITOR
            if (world != null && world.terrainGenerator == null)
            {
                world.terrainGenerator = this;
            }
            if (terrainData == null)
            {
                Terrain activeTerrain = Terrain.activeTerrain;
                if (activeTerrain != null)
                {
                    terrainData = activeTerrain.terrainData;
                    ExamineTerrainData();
                }
            }
#endif

            if (terrainData == null)
            {
                return;
            }

            if (lastTerrainDataLoaded != null && lastTerrainDataLoaded == terrainData && heights != null && heights.Length > 0)
            {
                return;
            }

            lastTerrainDataLoaded = terrainData;
            maxHeight             = terrainData.size.y;

            int th  = terrainData.heightmapHeight;
            int tw  = terrainData.heightmapWidth;
            int len = tw * th;
            if (heights == null || heights.Length != len)
            {
                heights = new TerrainHeightInfo[len];
            }

            float[,,] heightInfo = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);
            int detailLayerCount = terrainData.detailPrototypes.Length;
            for (int d = 0; d < detailLayerCount; d++)
            {
                detailLayers [d].detailLayer = terrainData.GetDetailLayer(0, 0, terrainData.detailWidth, terrainData.detailHeight, d);
            }
            int i = 0;
            int alphaMapsLayerCount = heightInfo.GetUpperBound(2);
            int currentDetailLayer  = 0;
            int vegDensity          = (int)(16 * (1f - vegetationDensity));
            for (int y = 0; y < th; y++)
            {
                int alphamapY = y * terrainData.alphamapHeight / th;
                int detailY   = y * terrainData.detailHeight / th;
                for (int x = 0; x < tw; x++, i++)
                {
                    int alphamapX = x * terrainData.alphamapWidth / tw;
                    heights [i].altitude = terrainData.GetHeight(x, y) / maxHeight;
                    float maxBlend = -1;
                    for (int a = 0; a <= alphaMapsLayerCount; a++)
                    {
                        float alphamapValue = heightInfo [alphamapY, alphamapX, a];
                        if (alphamapValue > maxBlend)
                        {
                            maxBlend = alphamapValue;
                            heights [i].terrainVoxelTop  = splatSettings [a].top;
                            heights [i].terrainVoxelDirt = splatSettings [a].dirt;
                            if (maxBlend >= 1f)
                            {
                                break;
                            }
                        }
                    }

                    if (detailLayerCount > 0)
                    {
                        for (int v = 0; v < detailLayerCount; v++)
                        {
                            currentDetailLayer++;
                            if (currentDetailLayer >= detailLayerCount)
                            {
                                currentDetailLayer = 0;
                            }
                            if (detailSettings [currentDetailLayer].vd != null)
                            {
                                int detailX = x * terrainData.detailWidth / tw;
                                int o       = detailLayers [currentDetailLayer].detailLayer [detailY, detailX];
                                if (o > vegDensity)
                                {
                                    heights [i].vegetationVoxel = detailSettings [currentDetailLayer].vd;
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            float sx = terrainData.size.x;
            float sz = terrainData.size.z;
            for (int t = 0; t < terrainData.treeInstances.Length; t++)
            {
                TreeInstance ti     = terrainData.treeInstances [t];
                int          hindex = GetHeightIndex(ti.position.x * sx - sx / 2, ti.position.z * sz - sz / 2);
                heights [hindex].treeModel = treeSettings [ti.prototypeIndex].md;
            }
        }
Example #26
0
    public static void SectorizeTerrain(Terrain terrain, int sectorsWidth, int sectorsLength, int sectorsHeight, bool splitTerrain, bool createPortalGeo, bool includeStatic, bool includeDynamic)
    {
        if (!terrain)
        {
            Debug.LogWarning("Cannot sectorize null terrain.");
            return;
        }

        if (terrain.transform.root.GetComponentsInChildren <SECTR_Sector>().Length > 0)
        {
            Debug.LogWarning("Cannot sectorize terrain that is already part of a Sector.");
        }

        string undoString = "Sectorized " + terrain.name;

        if (sectorsWidth == 1 && sectorsLength == 1)
        {
            SECTR_Sector newSector = terrain.gameObject.AddComponent <SECTR_Sector>();
            SECTR_Undo.Created(newSector, undoString);
            newSector.ForceUpdate(true);
            return;
        }

        if (splitTerrain && (!Mathf.IsPowerOfTwo(sectorsWidth) || !Mathf.IsPowerOfTwo(sectorsLength)))
        {
            Debug.LogWarning("Splitting terrain requires power of two sectors in width and length.");
            splitTerrain = false;
        }
        else if (splitTerrain && sectorsWidth != sectorsLength)
        {
            Debug.LogWarning("Splitting terrain requires same number of sectors in width and length.");
            splitTerrain = false;
        }

        int     terrainLayer = terrain.gameObject.layer;
        Vector3 terrainSize  = terrain.terrainData.size;
        float   sectorWidth  = terrainSize.x / sectorsWidth;
        float   sectorHeight = terrainSize.y / sectorsHeight;
        float   sectorLength = terrainSize.z / sectorsLength;

        int heightmapWidth  = (terrain.terrainData.heightmapWidth / sectorsWidth);
        int heightmapLength = (terrain.terrainData.heightmapHeight / sectorsLength);
        int alphaWidth      = terrain.terrainData.alphamapWidth / sectorsWidth;
        int alphaLength     = terrain.terrainData.alphamapHeight / sectorsLength;
        int detailWidth     = terrain.terrainData.detailWidth / sectorsWidth;
        int detailLength    = terrain.terrainData.detailHeight / sectorsLength;

        string sceneDir     = "";
        string sceneName    = "";
        string exportFolder = splitTerrain ? SECTR_Asset.MakeExportFolder("TerrainSplits", false, out sceneDir, out sceneName) : "";

        Transform baseTransform = null;

        if (splitTerrain)
        {
            GameObject baseObject = new GameObject(terrain.name);
            baseTransform = baseObject.transform;
            SECTR_Undo.Created(baseObject, undoString);
        }

        List <Transform> rootTransforms = new List <Transform>();
        List <Bounds>    rootBounds     = new List <Bounds>();

        _GetRoots(includeStatic, includeDynamic, rootTransforms, rootBounds);

        // Create Sectors
        string progressTitle   = "Sectorizing Terrain";
        int    progressCounter = 0;

        EditorUtility.DisplayProgressBar(progressTitle, "Preparing", 0);

        SECTR_Sector[,,] newSectors = new SECTR_Sector[sectorsWidth, sectorsLength, sectorsHeight];
        Terrain[,] newTerrains      = splitTerrain ? new Terrain[sectorsWidth, sectorsLength] : null;
        for (int widthIndex = 0; widthIndex < sectorsWidth; ++widthIndex)
        {
            for (int lengthIndex = 0; lengthIndex < sectorsLength; ++lengthIndex)
            {
                for (int heightIndex = 0; heightIndex < sectorsHeight; ++heightIndex)
                {
                    string newName = terrain.name + " " + widthIndex + "-" + lengthIndex + "-" + heightIndex;

                    EditorUtility.DisplayProgressBar(progressTitle, "Creating sector " + newName, progressCounter++ / (float)(sectorsWidth * sectorsLength * sectorsHeight));

                    GameObject newSectorObject = new GameObject("SECTR " + newName + " Sector");
                    newSectorObject.transform.parent = baseTransform;
                    Vector3 sectorCorner = new Vector3(widthIndex * sectorWidth,
                                                       heightIndex * sectorHeight,
                                                       lengthIndex * sectorLength) + terrain.transform.position;
                    newSectorObject.transform.position = sectorCorner;
                    newSectorObject.isStatic           = true;
                    SECTR_Sector newSector = newSectorObject.AddComponent <SECTR_Sector>();
                    newSector.OverrideBounds = !splitTerrain && (sectorsWidth > 1 || sectorsLength > 1);
                    newSector.BoundsOverride = new Bounds(sectorCorner + new Vector3(sectorWidth * 0.5f, sectorHeight * 0.5f, sectorLength * 0.5f),
                                                          new Vector3(sectorWidth, sectorHeight, sectorLength));
                    newSectors[widthIndex, lengthIndex, heightIndex] = newSector;

                    if (splitTerrain && heightIndex == 0)
                    {
                        GameObject newTerrainObject = new GameObject(newName + " Terrain");
                        newTerrainObject.layer                   = terrainLayer;
                        newTerrainObject.tag                     = terrain.tag;
                        newTerrainObject.transform.parent        = newSectorObject.transform;
                        newTerrainObject.transform.localPosition = Vector3.zero;
                        newTerrainObject.transform.localRotation = Quaternion.identity;
                        newTerrainObject.transform.localScale    = Vector3.one;
                        newTerrainObject.isStatic                = true;
                        Terrain newTerrain = newTerrainObject.AddComponent <Terrain>();
                        newTerrain.terrainData = SECTR_Asset.Create <TerrainData>(exportFolder, newName, new TerrainData());
                        EditorUtility.SetDirty(newTerrain.terrainData);
                        SECTR_VC.WaitForVC();

                        // Copy properties
                        // Basic terrain properties
                        newTerrain.editorRenderFlags   = terrain.editorRenderFlags;
                        newTerrain.castShadows         = terrain.castShadows;
                        newTerrain.heightmapMaximumLOD = terrain.heightmapMaximumLOD;
                        newTerrain.heightmapPixelError = terrain.heightmapPixelError;
                        newTerrain.lightmapIndex       = -1;                   // Can't set lightmap UVs on terrain.
                        newTerrain.materialTemplate    = terrain.materialTemplate;
                                                #if !UNITY_4
                        newTerrain.bakeLightProbesForTrees = terrain.bakeLightProbesForTrees;
                        newTerrain.legacyShininess         = terrain.legacyShininess;
                        newTerrain.legacySpecular          = terrain.legacySpecular;
                                                #endif

                        // Copy geometric data
                        int heightmapBaseX  = widthIndex * heightmapWidth;
                        int heightmapBaseY  = lengthIndex * heightmapLength;
                        int heightmapWidthX = heightmapWidth + (sectorsWidth > 1 ? 1 : 0);
                        int heightmapWidthY = heightmapLength + (sectorsLength > 1 ? 1 : 0);
                        newTerrain.terrainData.heightmapResolution = terrain.terrainData.heightmapResolution / sectorsWidth;
                        newTerrain.terrainData.size = new Vector3(sectorWidth, terrainSize.y, sectorLength);
                        newTerrain.terrainData.SetHeights(0, 0, terrain.terrainData.GetHeights(heightmapBaseX, heightmapBaseY, heightmapWidthX, heightmapWidthY));
                                                #if !UNITY_4
                        newTerrain.terrainData.thickness = terrain.terrainData.thickness;
                                                #endif

                        // Copy alpha maps
                        int alphaBaseX = alphaWidth * widthIndex;
                        int alphaBaseY = alphaLength * lengthIndex;
                        newTerrain.terrainData.splatPrototypes    = terrain.terrainData.splatPrototypes;
                        newTerrain.basemapDistance                = terrain.basemapDistance;
                        newTerrain.terrainData.baseMapResolution  = terrain.terrainData.baseMapResolution / sectorsWidth;
                        newTerrain.terrainData.alphamapResolution = terrain.terrainData.alphamapResolution / sectorsWidth;
                        newTerrain.terrainData.SetAlphamaps(0, 0, terrain.terrainData.GetAlphamaps(alphaBaseX, alphaBaseY, alphaWidth, alphaLength));

                        // Copy detail info
                        newTerrain.detailObjectDensity          = terrain.detailObjectDensity;
                        newTerrain.detailObjectDistance         = terrain.detailObjectDistance;
                        newTerrain.terrainData.detailPrototypes = terrain.terrainData.detailPrototypes;
                        newTerrain.terrainData.SetDetailResolution(terrain.terrainData.detailResolution / sectorsWidth, 8);                         // TODO: extract detailResolutionPerPatch
                                                #if !UNITY_4
                        newTerrain.collectDetailPatches = terrain.collectDetailPatches;
                                                #endif

                        int detailBaseX = detailWidth * widthIndex;
                        int detailBaseY = detailLength * lengthIndex;
                        int numLayers   = terrain.terrainData.detailPrototypes.Length;
                        for (int layer = 0; layer < numLayers; ++layer)
                        {
                            newTerrain.terrainData.SetDetailLayer(0, 0, layer, terrain.terrainData.GetDetailLayer(detailBaseX, detailBaseY, detailWidth, detailLength, layer));
                        }

                        // Copy grass and trees
                        newTerrain.terrainData.wavingGrassAmount   = terrain.terrainData.wavingGrassAmount;
                        newTerrain.terrainData.wavingGrassSpeed    = terrain.terrainData.wavingGrassSpeed;
                        newTerrain.terrainData.wavingGrassStrength = terrain.terrainData.wavingGrassStrength;
                        newTerrain.terrainData.wavingGrassTint     = terrain.terrainData.wavingGrassTint;
                        newTerrain.treeBillboardDistance           = terrain.treeBillboardDistance;
                        newTerrain.treeCrossFadeLength             = terrain.treeCrossFadeLength;
                        newTerrain.treeDistance               = terrain.treeDistance;
                        newTerrain.treeMaximumFullLODCount    = terrain.treeMaximumFullLODCount;
                        newTerrain.terrainData.treePrototypes = terrain.terrainData.treePrototypes;
                        newTerrain.terrainData.RefreshPrototypes();

                        foreach (TreeInstance treeInstace in terrain.terrainData.treeInstances)
                        {
                            if (treeInstace.prototypeIndex >= 0 && treeInstace.prototypeIndex < newTerrain.terrainData.treePrototypes.Length &&
                                newTerrain.terrainData.treePrototypes[treeInstace.prototypeIndex].prefab)
                            {
                                Vector3 worldSpaceTreePos = Vector3.Scale(treeInstace.position, terrainSize) + terrain.transform.position;
                                if (newSector.BoundsOverride.Contains(worldSpaceTreePos))
                                {
                                    Vector3 localSpaceTreePos = new Vector3((worldSpaceTreePos.x - newTerrain.transform.position.x) / sectorWidth,
                                                                            treeInstace.position.y,
                                                                            (worldSpaceTreePos.z - newTerrain.transform.position.z) / sectorLength);
                                    TreeInstance newInstance = treeInstace;
                                    newInstance.position = localSpaceTreePos;
                                    newTerrain.AddTreeInstance(newInstance);
                                }
                            }
                        }

                        // Copy physics
                                                #if UNITY_4_LATE
                        newTerrain.terrainData.physicMaterial = terrain.terrainData.physicMaterial;
                                                #endif

                        // Force terrain to rebuild
                        newTerrain.Flush();

                        UnityEditor.EditorUtility.SetDirty(newTerrain.terrainData);
                        SECTR_VC.WaitForVC();
                        newTerrain.enabled = false;
                        newTerrain.enabled = true;

                        TerrainCollider terrainCollider = terrain.GetComponent <TerrainCollider>();
                        if (terrainCollider)
                        {
                            TerrainCollider newCollider = newTerrainObject.AddComponent <TerrainCollider>();
                                                        #if !UNITY_4_LATE
                            newCollider.sharedMaterial = terrainCollider.sharedMaterial;
                                                        #endif
                            newCollider.terrainData = newTerrain.terrainData;
                        }

                        newTerrains[widthIndex, lengthIndex] = newTerrain;
                        SECTR_Undo.Created(newTerrainObject, undoString);
                    }
                    newSector.ForceUpdate(true);
                    SECTR_Undo.Created(newSectorObject, undoString);

                    _Encapsulate(newSector, rootTransforms, rootBounds, undoString);
                }
            }
        }

        // Create portals and neighbors
        progressCounter = 0;
        for (int widthIndex = 0; widthIndex < sectorsWidth; ++widthIndex)
        {
            for (int lengthIndex = 0; lengthIndex < sectorsLength; ++lengthIndex)
            {
                for (int heightIndex = 0; heightIndex < sectorsHeight; ++heightIndex)
                {
                    EditorUtility.DisplayProgressBar(progressTitle, "Creating portals...", progressCounter++ / (float)(sectorsWidth * sectorsLength * sectorsHeight));

                    if (widthIndex < sectorsWidth - 1)
                    {
                        _CreatePortal(createPortalGeo, newSectors[widthIndex + 1, lengthIndex, heightIndex], newSectors[widthIndex, lengthIndex, heightIndex], baseTransform, undoString);
                    }

                    if (lengthIndex < sectorsLength - 1)
                    {
                        _CreatePortal(createPortalGeo, newSectors[widthIndex, lengthIndex + 1, heightIndex], newSectors[widthIndex, lengthIndex, heightIndex], baseTransform, undoString);
                    }

                    if (heightIndex > 0)
                    {
                        _CreatePortal(createPortalGeo, newSectors[widthIndex, lengthIndex, heightIndex], newSectors[widthIndex, lengthIndex, heightIndex - 1], baseTransform, undoString);
                    }
                }
            }
        }

        if (splitTerrain)
        {
            progressCounter = 0;
            for (int widthIndex = 0; widthIndex < sectorsWidth; ++widthIndex)
            {
                for (int lengthIndex = 0; lengthIndex < sectorsLength; ++lengthIndex)
                {
                    EditorUtility.DisplayProgressBar(progressTitle, "Smoothing split terrain...", progressCounter++ / (float)(sectorsWidth * sectorsLength * sectorsHeight));

                    // Blend together the seams of the alpha maps, which requires
                    // going through all of the mip maps of all of the layer textures.
                    // We have to blend here rather than when we set the alpha data (above)
                    // because Unity computes mips and we need to blend all of the mips.
                    Terrain newTerrain = newTerrains[widthIndex, lengthIndex];

                    SECTR_Sector terrainSector = newSectors[widthIndex, lengthIndex, 0];
                    terrainSector.LeftTerrain   = widthIndex > 0 ? newSectors[widthIndex - 1, lengthIndex, 0] : null;
                    terrainSector.RightTerrain  = widthIndex < sectorsWidth - 1 ? newSectors[widthIndex + 1, lengthIndex, 0] : null;
                    terrainSector.BottomTerrain = lengthIndex > 0 ? newSectors[widthIndex, lengthIndex - 1, 0] : null;
                    terrainSector.TopTerrain    = lengthIndex < sectorsLength - 1 ? newSectors[widthIndex, lengthIndex + 1, 0] : null;
                    terrainSector.ConnectTerrainNeighbors();

                    // Use reflection trickery to get at the raw texture values.
                    System.Reflection.PropertyInfo alphamapProperty = newTerrain.terrainData.GetType().GetProperty("alphamapTextures",
                                                                                                                   System.Reflection.BindingFlags.NonPublic |
                                                                                                                   System.Reflection.BindingFlags.Public |
                                                                                                                   System.Reflection.BindingFlags.Instance |
                                                                                                                   System.Reflection.BindingFlags.Static);
                    // Get the texture we'll write into
                    Texture2D[] alphaTextures = (Texture2D[])alphamapProperty.GetValue(newTerrain.terrainData, null);
                    int         numTextures   = alphaTextures.Length;

                    // Get the textures we'll read from
                    Texture2D[] leftNeighborTextures   = terrainSector.LeftTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex - 1, lengthIndex].terrainData, null) : null;
                    Texture2D[] rightNeighborTextures  = terrainSector.RightTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex + 1, lengthIndex].terrainData, null) : null;
                    Texture2D[] topNeighborTextures    = terrainSector.TopTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex, lengthIndex + 1].terrainData, null) : null;
                    Texture2D[] bottomNeighborTextures = terrainSector.BottomTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex, lengthIndex - 1].terrainData, null) : null;

                    for (int textureIndex = 0; textureIndex < numTextures; ++textureIndex)
                    {
                        Texture2D alphaTexture  = alphaTextures[textureIndex];
                        Texture2D leftTexture   = leftNeighborTextures != null ? leftNeighborTextures[textureIndex] : null;
                        Texture2D rightTexture  = rightNeighborTextures != null ? rightNeighborTextures[textureIndex] : null;
                        Texture2D topTexture    = topNeighborTextures != null ? topNeighborTextures[textureIndex] : null;
                        Texture2D bottomTexture = bottomNeighborTextures != null ? bottomNeighborTextures[textureIndex] : null;
                        int       numMips       = alphaTexture.mipmapCount;
                        for (int mipIndex = 0; mipIndex < numMips; ++mipIndex)
                        {
                            Color[] alphaTexels = alphaTexture.GetPixels(mipIndex);
                            int     width       = (int)Mathf.Sqrt(alphaTexels.Length);
                            int     height      = width;
                            for (int texelWidthIndex = 0; texelWidthIndex < width; ++texelWidthIndex)
                            {
                                for (int texelHeightIndex = 0; texelHeightIndex < height; ++texelHeightIndex)
                                {
                                    // We can take advantage of the build order to average on the leading edges (right and top)
                                    // and then copy form the trailing edges (left and bottom)
                                    if (texelWidthIndex == 0 && leftTexture)
                                    {
                                        Color[] neighborTexels = leftTexture.GetPixels(mipIndex);
                                        alphaTexels[texelWidthIndex + texelHeightIndex * width] = neighborTexels[(width - 1) + (texelHeightIndex * width)];
                                    }
                                    else if (texelWidthIndex == width - 1 && rightTexture)
                                    {
                                        Color[] neighborTexels = rightTexture.GetPixels(mipIndex);
                                        alphaTexels[texelWidthIndex + texelHeightIndex * width] += neighborTexels[0 + (texelHeightIndex * width)];
                                        alphaTexels[texelWidthIndex + texelHeightIndex * width] *= 0.5f;
                                    }
                                    else if (texelHeightIndex == 0 && bottomTexture)
                                    {
                                        Color[] neighborTexels = bottomTexture.GetPixels(mipIndex);
                                        alphaTexels[texelWidthIndex + texelHeightIndex * width] = neighborTexels[texelWidthIndex + ((height - 1) * width)];
                                    }
                                    else if (texelHeightIndex == height - 1 && topTexture)
                                    {
                                        Color[] neighborTexels = topTexture.GetPixels(mipIndex);
                                        alphaTexels[texelWidthIndex + texelHeightIndex * width] += neighborTexels[texelWidthIndex + (0 * width)];
                                        alphaTexels[texelWidthIndex + texelHeightIndex * width] *= 0.5f;
                                    }
                                }
                            }
                            alphaTexture.SetPixels(alphaTexels, mipIndex);
                        }
                        alphaTexture.wrapMode = TextureWrapMode.Clamp;
                        alphaTexture.Apply(false);
                    }

                    newTerrain.Flush();
                }
            }
        }

        EditorUtility.ClearProgressBar();

        // destroy original terrain
        if (splitTerrain)
        {
            SECTR_Undo.Destroy(terrain.gameObject, undoString);
        }
    }
		internal void AddTree(out TreeInstance tree){}
Example #28
0
        public void GenerateTrees(Terrain terrain)
        {
            var data = terrain.terrainData;

            var num = data.treePrototypes.Length;

            if (num == 0)
            {
                Debug.LogWarning("Can't place trees because no prototypes are defined. Process aborted.");
                return;
            }

            //Undo.RegisterCompleteObjectUndo (data, "Mass Place Trees");

            float timeElapsed = 0;

            var array = new TreeInstance[count];
            var i     = 0;

            while (i < array.Length)
            {
                //stop if process have run for over X seconds
                timeElapsed += Time.deltaTime;
                if (timeElapsed >= maxTime)
                {
                    Debug.LogWarning("Process was taking too much time to run");
                    return;
                }

                var position = new Vector3(Random.value, 0.0f, Random.value);

                // don't allow placement of trees below minWorldY and above maxWorldY
                var y      = data.GetInterpolatedHeight(position.x, position.z);
                var worldY = y + terrain.transform.position.y;
                if (worldY < minWorldY || worldY > maxWorldY)
                {
                    continue;
                }

                // don't allow placement of trees on surfaces flatter than minSlope and steeper than maxSlope
                var steepness = data.GetSteepness(position.x, position.z);
                if (steepness < minSlope || steepness > maxSlope)
                {
                    continue;
                }

                var color = Color.Lerp(Color.white, Color.gray * 0.7f, Random.value);
                color.a = 1f;

                var treeInstance = default(TreeInstance);
                treeInstance.position       = position;
                treeInstance.color          = color;
                treeInstance.lightmapColor  = Color.white;
                treeInstance.prototypeIndex = Random.Range(0, num);
                treeInstance.widthScale     = Random.Range(minWidthScale, maxWidthScale);
                treeInstance.heightScale    = Random.Range(minHeightScale, maxHeightScale);
                array [i] = treeInstance;
                i++;
            }
            data.treeInstances = array;
            //RecalculateTreePositions(data);
            terrain.Flush();
        }
Example #29
0
    private static void Slicing()
    {
        Terrain terrain = GameObject.FindObjectOfType <Terrain>();

        if (terrain == null)
        {
            Debug.LogError("找不到地形!");
            return;
        }
        string savepath = "Assets/Resources/" + terrain.name + "/";

        if (Directory.Exists(savepath))
        {
            Directory.Delete(savepath, true);
        }
        Directory.CreateDirectory(savepath);
        TerrainData terrainData = terrain.terrainData;

        Vector3 oldSize = terrainData.size;
        Vector3 oldPos  = terrain.transform.position;

        oldPos = new Vector3(oldPos.x - oldSize.x, oldPos.y, oldPos.z);

        //得到新地图分辨率
        int newAlphamapResolution = terrainData.alphamapResolution / trnconst.SLICE;

        SplatPrototype[] splatProtos = terrainData.splatPrototypes;


        var detailProtos  = terrainData.detailPrototypes;
        var treeProtos    = terrainData.treePrototypes;
        var treeInst      = terrainData.treeInstances;
        var grassStrength = terrainData.wavingGrassStrength;
        var grassAmount   = terrainData.wavingGrassAmount;
        var grassSpeed    = terrainData.wavingGrassSpeed;
        var grassTint     = terrainData.wavingGrassTint;

        int terrainsWide = trnconst.SLICE;
        int terrainsLong = trnconst.SLICE;

        int newDetailResolution = terrainData.detailResolution / trnconst.SLICE;
        int resolutionPerPatch  = 8;
        //设置高度
        int xBase = terrainData.heightmapWidth / terrainsWide;
        int yBase = terrainData.heightmapHeight / terrainsLong;

        TerrainData[] data = new TerrainData[terrainsWide * terrainsLong];
        Dictionary <int, List <TreeInstance> > map = new Dictionary <int, List <TreeInstance> >();
        int arrayPos = 0;

        try
        {
            //循环宽和长,生成小块地形
            for (int x = 0; x < terrainsWide; ++x)
            {
                for (int y = 0; y < terrainsLong; ++y)
                {
                    //创建资源
                    TerrainData newData = new TerrainData();
                    map[arrayPos]    = new List <TreeInstance>();
                    data[arrayPos++] = newData;
                    string terrainName = terrain.name + trnconst.sep + y + trnconst.sep + x + ".asset";
                    AssetDatabase.CreateAsset(newData, savepath + terrainName);

                    EditorUtility.DisplayProgressBar("正在分割地形", terrainName, (float)(x * terrainsWide + y) / (float)(terrainsWide * terrainsLong));

                    //设置分辨率参数
                    newData.heightmapResolution = (terrainData.heightmapResolution - 1) / trnconst.SLICE;
                    newData.alphamapResolution  = terrainData.alphamapResolution / trnconst.SLICE;
                    newData.baseMapResolution   = terrainData.baseMapResolution / trnconst.SLICE;

                    //设置大小
                    newData.size = new Vector3(oldSize.x / terrainsWide, oldSize.y, oldSize.z / terrainsLong);

                    //设置地形原型
                    SplatPrototype[] newSplats = new SplatPrototype[splatProtos.Length];
                    for (int i = 0; i < splatProtos.Length; ++i)
                    {
                        newSplats[i]          = new SplatPrototype();
                        newSplats[i].texture  = splatProtos[i].texture;
                        newSplats[i].tileSize = splatProtos[i].tileSize;

                        float offsetX = (newData.size.x * x) % splatProtos[i].tileSize.x + splatProtos[i].tileOffset.x;
                        float offsetY = (newData.size.z * y) % splatProtos[i].tileSize.y + splatProtos[i].tileOffset.y;
                        newSplats[i].tileOffset = new Vector2(offsetX, offsetY);
                    }
                    newData.splatPrototypes = newSplats;

                    //设置混合贴图
                    float[,,] alphamap = new float[newAlphamapResolution, newAlphamapResolution, splatProtos.Length];
                    alphamap           = terrainData.GetAlphamaps(x * newData.alphamapWidth, y * newData.alphamapHeight, newData.alphamapWidth, newData.alphamapHeight);
                    newData.SetAlphamaps(0, 0, alphamap);

                    float[,] height = terrainData.GetHeights(xBase * x, yBase * y, xBase + 1, yBase + 1);
                    newData.SetHeights(0, 0, height);

                    newData.SetDetailResolution(newDetailResolution, resolutionPerPatch);

                    int[] layers      = terrainData.GetSupportedLayers(x * newData.detailWidth - 1, y * newData.detailHeight - 1, newData.detailWidth, newData.detailHeight);
                    int   layerLength = layers.Length;

                    DetailPrototype[] tempDetailProtos = new DetailPrototype[layerLength];
                    for (int i = 0; i < layerLength; i++)
                    {
                        tempDetailProtos[i] = detailProtos[layers[i]];
                    }
                    newData.detailPrototypes = tempDetailProtos;

                    for (int i = 0; i < layerLength; i++)
                    {
                        newData.SetDetailLayer(0, 0, i, terrainData.GetDetailLayer(x * newData.detailWidth, y * newData.detailHeight, newData.detailWidth, newData.detailHeight, layers[i]));
                    }

                    newData.wavingGrassStrength = grassStrength;
                    newData.wavingGrassAmount   = grassAmount;
                    newData.wavingGrassSpeed    = grassSpeed;
                    newData.wavingGrassTint     = grassTint;
                    newData.treePrototypes      = treeProtos;
                }
            }

            int newWidth  = (int)oldSize.x / terrainsWide;
            int newLength = (int)oldSize.z / terrainsLong;
            for (int i = 0; i < treeInst.Length; i++)
            {
                Vector3 origPos  = Vector3.Scale(new Vector3(oldSize.x, 1, oldSize.z), new Vector3(treeInst[i].position.x, treeInst[i].position.y, treeInst[i].position.z));
                int     column   = Mathf.FloorToInt(origPos.x / newWidth);
                int     row      = Mathf.FloorToInt(origPos.z / newLength);
                Vector3 tempVect = new Vector3((origPos.x - newWidth * column) / newWidth, origPos.y, (origPos.z - newLength * row) / newWidth);

                TreeInstance tempTree = new TreeInstance();
                tempTree.position      = tempVect;
                tempTree.widthScale    = treeInst[i].widthScale;
                tempTree.heightScale   = treeInst[i].heightScale;
                tempTree.color         = treeInst[i].color;
                tempTree.rotation      = treeInst[i].rotation;
                tempTree.lightmapColor = treeInst[i].lightmapColor;
                int indx = (column * terrainsWide) + row;
                tempTree.prototypeIndex = 0;
                map[indx].Add(tempTree);
            }
            for (int i = 0; i < terrainsWide * terrainsLong; i++)
            {
                data[i].treeInstances = map[i].ToArray();
                data[i].RefreshPrototypes();
            }
            WriteTerrainInfo(terrain, savepath + terrain.name + ".bytes");
        }
        catch (System.Exception e)
        {
            Debug.LogError(e.Message);
            Debug.LogError(e.StackTrace);
        }
        finally
        {
            EditorUtility.ClearProgressBar();
            AssetDatabase.Refresh();
        }
    }
 public Vector3 getObjectLoc(TreeInstance obj)
 {
     return(new Vector3(obj.position.x * heightmap_width,
                        obj.position.y * terrain_data.heightmapScale.y,
                        obj.position.z * heightmap_height));
 }
Example #31
0
        #pragma warning restore 414

        /// <summary>
        /// Load the trees in from the terrain
        /// </summary>
        public void LoadTreesFromTerrain()
        {
            //Destroy previous contents
            m_terrainTrees         = null;
            m_terrainTreeLocations = null;

            //Work out the bounds of the environment
            float   minY          = float.NaN;
            float   minX          = float.NaN;
            float   maxX          = float.NaN;
            float   minZ          = float.NaN;
            float   maxZ          = float.NaN;
            Terrain sampleTerrain = null;

            foreach (Terrain terrain in Terrain.activeTerrains)
            {
                if (float.IsNaN(minY))
                {
                    sampleTerrain = terrain;
                    minY          = terrain.transform.position.y;
                    minX          = terrain.transform.position.x;
                    minZ          = terrain.transform.position.z;
                    maxX          = minX + terrain.terrainData.size.x;
                    maxZ          = minZ + terrain.terrainData.size.z;
                }
                else
                {
                    if (terrain.transform.position.x < minX)
                    {
                        minX = terrain.transform.position.x;
                    }
                    if (terrain.transform.position.z < minZ)
                    {
                        minZ = terrain.transform.position.z;
                    }
                    if ((terrain.transform.position.x + terrain.terrainData.size.x) > maxX)
                    {
                        maxX = terrain.transform.position.x + terrain.terrainData.size.x;
                    }
                    if ((terrain.transform.position.z + terrain.terrainData.size.z) > maxZ)
                    {
                        maxZ = terrain.transform.position.z + terrain.terrainData.size.z;
                    }
                }
            }

            if (sampleTerrain != null)
            {
                Rect terrainBounds = new Rect(minX, minZ, maxX - minX, maxZ - minZ);

                m_terrainTreeLocations = new Quadtree <TreeStruct>(terrainBounds, 32);
                m_terrainTrees         = new List <TreePrototype>(sampleTerrain.terrainData.treePrototypes);

                foreach (Terrain terrain in Terrain.activeTerrains)
                {
                    float          terrainOffsetX       = terrain.transform.position.x;
                    float          terrainOffsetY       = terrain.transform.position.y;
                    float          terrainOffsetZ       = terrain.transform.position.z;
                    float          terrainWidth         = terrain.terrainData.size.x;
                    float          terrainHeight        = terrain.terrainData.size.y;
                    float          terrainDepth         = terrain.terrainData.size.z;
                    TreeInstance[] terrainTreeInstances = terrain.terrainData.treeInstances;
                    for (int treeIdx = 0; treeIdx < terrainTreeInstances.Length; treeIdx++)
                    {
                        TreeInstance treeInstance = terrainTreeInstances[treeIdx];
                        TreeStruct   newTree      = new TreeStruct();
                        newTree.position    = new Vector3(terrainOffsetX + (treeInstance.position.x * terrainWidth), terrainOffsetY + (treeInstance.position.y * terrainHeight), terrainOffsetZ + (treeInstance.position.z * terrainDepth));
                        newTree.prototypeID = terrainTreeInstances[treeIdx].prototypeIndex;
                        m_terrainTreeLocations.Insert(newTree.position.x, newTree.position.z, newTree);
                    }
                }
            }
        }
Example #32
0
        public static void Process(MapMagic.CoordRect rect, Chunk.Results results, GeneratorsAsset gens, Chunk.Size terrainSize, Func <float, bool> stop = null)
        {
            if (stop != null && stop(0))
            {
                return;
            }

            Noise noise = new Noise(12345, permutationCount: 128);            //to pick objects based on biome

            List <TreeInstance>  instancesList  = new List <TreeInstance>();
            List <TreePrototype> prototypesList = new List <TreePrototype>();

            //find all of the biome masks - they will be used to determine object probability
            List <TupleSet <MadMapsTreeOutput, Matrix> > allGensMasks = new List <TupleSet <MadMapsTreeOutput, Matrix> >();

            foreach (MadMapsTreeOutput gen in gens.GeneratorsOfType <MadMapsTreeOutput>(onlyEnabled: true, checkBiomes: true))
            {
                Matrix biomeMask = null;
                if (gen.biome != null)
                {
                    object biomeMaskObj = gen.biome.mask.GetObject(results);
                    if (biomeMaskObj == null)
                    {
                        continue;                                           //adding nothing if biome has no mask
                    }
                    biomeMask = (Matrix)biomeMaskObj;
                    if (biomeMask == null)
                    {
                        continue;
                    }
                    if (biomeMask.IsEmpty())
                    {
                        continue;                                          //optimizing empty biomes
                    }
                }

                allGensMasks.Add(new TupleSet <MadMapsTreeOutput, Matrix>(gen, biomeMask));
            }
            int allGensMasksCount = allGensMasks.Count;

            //biome rect to find array pos faster
            MapMagic.CoordRect biomeRect = new MapMagic.CoordRect();
            for (int g = 0; g < allGensMasksCount; g++)
            {
                if (allGensMasks[g].item2 != null)
                {
                    biomeRect = allGensMasks[g].item2.rect; break;
                }
            }

            //prepare biome mask values stack to re-use it to find per-coord biome
            float[] biomeVals = new float[allGensMasksCount];             //+1 for not using any object at all

            //iterating all gens
            for (int g = 0; g < allGensMasksCount; g++)
            {
                MadMapsTreeOutput gen = allGensMasks[g].item1;

                //iterating in layers
                for (int b = 0; b < gen.baseLayers.Length; b++)
                {
                    if (stop != null && stop(0))
                    {
                        return;                                            //checking stop before reading output
                    }
                    Layer layer = gen.baseLayers[b];
//					if (layer.prefab == null) continue;

                    //loading objects from input
                    SpatialHash hash = (SpatialHash)gen.baseLayers[b].input.GetObject(results);
                    if (hash == null)
                    {
                        continue;
                    }

                    //adding prototype
//					if (layer.prefab == null) continue;
                    TreePrototype prototype = new TreePrototype()
                    {
                        prefab = layer.prefab, bendFactor = layer.bendFactor
                    };
                    prototypesList.Add(prototype);
                    int prototypeNum = prototypesList.Count - 1;

                    //filling instances (no need to check/add key in multidict)
                    foreach (SpatialObject obj in hash.AllObjs())
                    {
                        //blend biomes - calling continue if improper biome
                        if (biomeBlendType == BiomeBlendType.Sharp)
                        {
                            float biomeVal = 1;
                            if (allGensMasks[g].item2 != null)
                            {
                                biomeVal = allGensMasks[g].item2[obj.pos];
                            }
                            if (biomeVal < 0.5f)
                            {
                                continue;
                            }
                        }
                        else if (biomeBlendType == BiomeBlendType.AdditiveRandom)
                        {
                            float biomeVal = 1;
                            if (allGensMasks[g].item2 != null)
                            {
                                biomeVal = allGensMasks[g].item2[obj.pos];
                            }

                            float rnd = noise.Random((int)obj.pos.x, (int)obj.pos.y);

                            if (biomeVal > 0.5f)
                            {
                                rnd = 1 - rnd;
                            }

                            if (biomeVal < rnd)
                            {
                                continue;
                            }
                        }
                        else if (biomeBlendType == BiomeBlendType.NormalizedRandom)
                        {
                            //filling biome masks values
                            int pos = biomeRect.GetPos(obj.pos);

                            for (int i = 0; i < allGensMasksCount; i++)
                            {
                                if (allGensMasks[i].item2 != null)
                                {
                                    biomeVals[i] = allGensMasks[i].item2.array[pos];
                                }
                                else
                                {
                                    biomeVals[i] = 1;
                                }
                            }

                            //calculate normalized sum
                            float sum = 0;
                            for (int i = 0; i < biomeVals.Length; i++)
                            {
                                sum += biomeVals[i];
                            }
                            if (sum > 1)                             //note that if sum is <1 usedBiomeNum can exceed total number of biomes - it means that none object is used here
                            {
                                for (int i = 0; i < biomeVals.Length; i++)
                                {
                                    biomeVals[i] = biomeVals[i] / sum;
                                }
                            }

                            //finding used biome num
                            float rnd          = noise.Random((int)obj.pos.x, (int)obj.pos.y);
                            int   usedBiomeNum = biomeVals.Length;                           //none biome by default
                            sum = 0;
                            for (int i = 0; i < biomeVals.Length; i++)
                            {
                                sum += biomeVals[i];
                                if (sum > rnd)
                                {
                                    usedBiomeNum = i; break;
                                }
                            }

                            //disable object using biome mask
                            if (usedBiomeNum != g)
                            {
                                continue;
                            }
                        }
                        //scale mode is applied a bit later

                        //flooring
                        float terrainHeight = 0;
                        if (layer.relativeHeight && results.heights != null)                         //if checbox enabled and heights exist (at least one height generator is in the graph)
                        {
                            terrainHeight = results.heights.GetInterpolated(obj.pos.x, obj.pos.y);
                        }
                        if (terrainHeight > 1)
                        {
                            terrainHeight = 1;
                        }

                        TreeInstance tree = new TreeInstance();
                        tree.position = new Vector3(
                            (obj.pos.x - hash.offset.x) / hash.size,
                            obj.height + terrainHeight,
                            (obj.pos.y - hash.offset.y) / hash.size);
                        tree.rotation       = layer.rotate ? obj.rotation % 360 : 0;
                        tree.widthScale     = layer.widthScale ? obj.size : 1;
                        tree.heightScale    = layer.heightScale ? obj.size : 1;
                        tree.prototypeIndex = prototypeNum;
                        tree.color          = layer.color;
                        tree.lightmapColor  = layer.color;

                        if (biomeBlendType == BiomeBlendType.Scale)
                        {
                            float biomeVal = 1;
                            if (allGensMasks[g].item2 != null)
                            {
                                biomeVal = allGensMasks[g].item2[obj.pos];
                            }
                            if (biomeVal < 0.001f)
                            {
                                continue;
                            }
                            tree.widthScale  *= biomeVal;
                            tree.heightScale *= biomeVal;
                        }

                        instancesList.Add(tree);
                    }
                }
            }

            //setting output
            if (stop != null && stop(0))
            {
                return;
            }
            if (instancesList.Count == 0 && prototypesList.Count == 0)
            {
                return;                                                                    //empty, process is caused by height change
            }
            TupleSet <TreeInstance[], TreePrototype[]> treesTuple = new TupleSet <TreeInstance[], TreePrototype[]>(instancesList.ToArray(), prototypesList.ToArray());

            results.apply.CheckAdd(typeof(MadMapsTreeOutput), treesTuple, replace: true);
        }
    public override void draw(float x, float z)
    {
        var random = new System.Random();
        int tot    = terrain.getObjectCount();
        List <TreeInstance> curr  = new List <TreeInstance>();
        List <Vector3>      currp = new List <Vector3>();

        for (int i = 0; i < tot; i++)
        {
            TreeInstance o = terrain.getObject(i);
            Vector3      v = terrain.getObjectLoc(i);
            if (v.x <= x + radius && v.x >= x - radius && v.z <= z + radius && v.z >= z - radius)
            {
                curr.Add(o);
                currp.Add(v);
            }
        }

        int left = maxObjects - curr.Count;

        left = maxObjects;
        if (left > 0)
        {
            Array values = Enum.GetValues(typeof(TreeTextures));
            for (int i = 0; i < left; i++)
            {
                float xi = ((float)random.NextDouble()) * 2.0f - 1;
                float zi = ((float)random.NextDouble()) * 2.0f - 1;
                xi = xi * radius;
                zi = zi * radius;
                Vector3 p = givePos(x, z);
                for (int j = 0; j < currp.Count; j++)
                {
                    Vector3 d = (p - currp[j]);
                    float   D = d.sqrMagnitude;
                    if (D <= min_distance)
                    {
                        p = p + (d * (D + 0.01f));
                    }
                }

                if (p.x <= x + radius && p.x >= x - radius && p.z <= z + radius && p.z >= z - radius)
                {
                    if (zone == Zone.Random)
                    {
                        Zone obs = ((Zone)values.GetValue(random.Next(values.Length)));
                        if (obs == Zone.Random)
                        {
                            obs = Zone.FootHill;
                        }
                        zone = obs;
                    }
                    VegetationConstraint v = terrain.getVegetationFromZone(zone);
                    int index = random.Next(0, v.objects.Length);
                    if (v.objects == null || v.objects.Length == 0)
                    {
                        return;
                    }
                    terrain.object_prefab = v.objects[index];
                    setPrefab(terrain.registerPrefab(terrain.object_prefab));
                    if (v.place(p.x, p.z, ref terrain, true))
                    {
                        currp.Add(p);
                        spawnObject(p.x, p.z);
                    }
                }
                //print("---" + i + 'p'+GetType());
                //terrain.object_prefab;
                //getPrefable, terrain.getObject, terrain.countexistingObejects, check current object index
            }
        }
    }
 public OverwatchTreeWrapper(ushort treeInstanceId, TreeInstance treeInstance)
 {
     TreeId = treeInstanceId;
     SourcePackageId = ParsePackageId(treeInstance);
     TechnicalName = treeInstance.Info.name;
 }