Beispiel #1
0
        //main thread
        public ColliderCollectorTerrainUnityWay(NavMeshTemplateRecast template, Collider[] colliders) : base(template, colliders)
        {
            var   allTerrains  = (from collider in validColliders select collider.GetComponent <Terrain>());
            float fragmentSize = template.voxelSize;
            float halfFragment = fragmentSize * 0.5f;


            foreach (var curTerrain in allTerrains)
            {
                TerrainData          data            = curTerrain.terrainData;
                Vector3              position        = curTerrain.transform.position;
                VectorInt.Vector3Int terrainStartInt = new VectorInt.Vector3Int((position / fragmentSize) + template.halfFragmentOffset);
                VectorInt.Vector3Int terrainEndInt   = new VectorInt.Vector3Int((position + data.size) / fragmentSize + template.halfFragmentOffset);

                int startXClamp = Mathf.Clamp(terrainStartInt.x, template.startX_extra, template.endX_extra);
                int startZClamp = Mathf.Clamp(terrainStartInt.z, template.startZ_extra, template.endZ_extra);

                int endXClamp = Mathf.Clamp(terrainEndInt.x, template.startX_extra, template.endX_extra);
                int endZClamp = Mathf.Clamp(terrainEndInt.z, template.startZ_extra, template.endZ_extra);

                int terrainStartX = terrainStartInt.x;
                int terrainStartZ = terrainStartInt.z;

                int offset = terrainStartInt.y;

                float terrainSizeX = terrainEndInt.x - terrainStartX;
                float terrainSizeZ = terrainEndInt.z - terrainStartZ;

                float[][] heightMap      = new float[template.lengthX_extra][];
                int[][]   passabilityMap = new int[template.lengthX_extra][]; //angle map

                for (int x = 0; x < template.lengthX_extra; x++)
                {
                    heightMap[x]      = new float[template.lengthZ_extra];
                    passabilityMap[x] = new int[template.lengthZ_extra];
                }

                //some cashed values
                int   startX_extra = template.startX_extra;
                int   startZ_extra = template.startZ_extra;
                float maxSlope     = template.maxSlope;

                //lets do bazzilion times Terrain.SampleHeight and TerrainData.GetSteepness!
                //it cant be done in thread cause terrain API is "threadsafe"!
                //actualy it can be done. but in order to do this we need to recreate this part of terrain mesh in thread but no. i dont want to do this. no.
                //maybe later


                for (int x = startXClamp; x < endXClamp; x++)
                {
                    for (int z = startZClamp; z < endZClamp; z++)
                    {
                        heightMap[x - startX_extra][z - startZ_extra]      = curTerrain.SampleHeight(new Vector3(x * fragmentSize + halfFragment, 0, z * fragmentSize + halfFragment)) + offset;
                        passabilityMap[x - startX_extra][z - startZ_extra] = data.GetSteepness((x - terrainStartX) / terrainSizeX, (z - terrainStartZ) / terrainSizeZ) < maxSlope ? (int)Passability.Walkable : (int)Passability.Slope;
                    }
                }

                TerrainColliderInfoPrecise info = new TerrainColliderInfoPrecise(curTerrain, heightMap, passabilityMap);

                if (template.profiler != null)
                {
                    template.profiler.AddLog("start collecting tree bounds");
                }

                info.treeData = GenerateTreeBounds(curTerrain);

                if (template.profiler != null)
                {
                    template.profiler.AddLog("end collecting tree bounds. collected bounds: " + info.treeData.Count);
                }

                SetTerrainSettings(info, curTerrain,
                                   startXClamp, startZClamp,
                                   endXClamp, endZClamp,
                                   terrainStartX, terrainStartZ,
                                   terrainSizeX, terrainSizeZ,
                                   position);

                _terrainsInfo.Add(info);
            }
        }
        public ColliderCollectorTerrainMeshAbstract(NavMeshTemplateRecast template, Collider[] colliders) : base(template, colliders)
        {
            List <Terrain> allTerrains = new List <Terrain>();

            for (int i = 0; i < validColliders.Count; i++)
            {
                allTerrains.Add(validColliders[i].GetComponent <Terrain>());
            }

            if (template.profiler != null)
            {
                template.profiler.AddLog("collecting terrain using fast collector. valid colliders:" + validColliders.Count);
            }

            float   voxelSize      = template.voxelSize;
            Bounds  offsetedBounds = template.chunkOffsetedBounds;
            Vector3 boundsMin      = offsetedBounds.min;
            Vector3 boundsMax      = offsetedBounds.max;

            float minSize = PathFinder.settings.terrainFastMinimalSize;

            foreach (var curTerrain in allTerrains)
            {
                TerrainColliderInfoMesh info = new TerrainColliderInfoMesh(curTerrain);

                if (template.profiler != null)
                {
                    template.profiler.AddLog("start collecting tree bounds");
                }

                info.treeData = GenerateTreeBounds(curTerrain);

                if (template.profiler != null)
                {
                    template.profiler.AddLog("end collecting tree bounds. collected bounds: " + info.treeData.Count);
                }

                TerrainData data     = curTerrain.terrainData;
                Vector3     position = curTerrain.transform.position;
                Vector3     scale    = data.size;

                //height map
                int resolution = 1;

                int heightMapSizeX = data.heightmapWidth;
                int heightMapSizeZ = data.heightmapHeight;

                float hScaleX = scale.x / (heightMapSizeX - 1);
                float hScaleZ = scale.z / (heightMapSizeZ - 1);

                for (int i = 0; i < 4; i++)
                {
                    if (minSize > hScaleX * resolution)
                    {
                        resolution = (int)Mathf.Pow(2, i);
                    }
                    else
                    {
                        break;
                    }
                }

                int hTargetMinX = Mathf.Clamp(((Mathf.RoundToInt((boundsMin.x - position.x) / hScaleX) / resolution) - 1) * resolution, 0, heightMapSizeX);
                int hTargetMinZ = Mathf.Clamp(((Mathf.RoundToInt((boundsMin.z - position.z) / hScaleZ) / resolution) - 1) * resolution, 0, heightMapSizeX);

                int hTargetMaxX = Mathf.Clamp(((Mathf.RoundToInt((boundsMax.x - position.x) / hScaleX) / resolution) + 1) * resolution + 1, 0, heightMapSizeX);
                int hTargetMaxZ = Mathf.Clamp(((Mathf.RoundToInt((boundsMax.z - position.z) / hScaleZ) / resolution) + 1) * resolution + 1, 0, heightMapSizeX);

                int hSizeX = hTargetMaxX - hTargetMinX;
                int hSizeZ = hTargetMaxZ - hTargetMinZ;

                int hTargetSizeX = hSizeX / resolution + 1;
                int hTargetSizeZ = hSizeZ / resolution + 1;

                if (resolution == 1)
                {
                    hTargetSizeX = hSizeX;
                    hTargetSizeZ = hSizeZ;
                }

                info.heightMap = data.GetHeights(hTargetMinX, hTargetMinZ, hSizeX, hSizeZ);

                info.heightMatrix = Matrix4x4.TRS(
                    position + new Vector3(hScaleX * hTargetMinX, 0, hScaleZ * hTargetMinZ),
                    Quaternion.identity,
                    new Vector3(hScaleX * resolution, scale.y, hScaleZ * resolution));

                info.hSizeX     = hTargetSizeX;
                info.hSizeZ     = hTargetSizeZ;
                info.resolution = resolution;

                //rest
                VectorInt.Vector3Int terrainStartInt = new VectorInt.Vector3Int((position / voxelSize) + template.halfFragmentOffset);
                VectorInt.Vector3Int terrainEndInt   = new VectorInt.Vector3Int((position + data.size) / voxelSize + template.halfFragmentOffset);

                int startXClamp = Mathf.Clamp(terrainStartInt.x, template.startX_extra, template.endX_extra);
                int startZClamp = Mathf.Clamp(terrainStartInt.z, template.startZ_extra, template.endZ_extra);

                int endXClamp = Mathf.Clamp(terrainEndInt.x, template.startX_extra, template.endX_extra);
                int endZClamp = Mathf.Clamp(terrainEndInt.z, template.startZ_extra, template.endZ_extra);

                int terrainStartX = terrainStartInt.x;
                int terrainStartZ = terrainStartInt.z;

                float terrainSizeX = terrainEndInt.x - terrainStartX;
                float terrainSizeZ = terrainEndInt.z - terrainStartZ;

                SetTerrainSettings(info, curTerrain,
                                   startXClamp, startZClamp,
                                   endXClamp, endZClamp,
                                   terrainStartX, terrainStartZ,
                                   terrainSizeX, terrainSizeZ,
                                   position);


                terrainsInfo.Add(info);
            }
        }
Beispiel #3
0
        private void AddColliderTerrain(Collider collider, TerrainCollectorType terrainCollectionType)
        {
            Terrain terrain = collider.GetComponent <Terrain>();

            if (terrain == null | terrain.enabled == false)
            {
                return;
            }

            if (profiler != null)
            {
                profiler.AddLogFormat("collecting terrain {0}", terrain.gameObject.name);
            }

            TerrainColliderInfoMesh info = new TerrainColliderInfoMesh(terrain);

            info.trees = CollectTreeData(terrain);

            //general stuff
            float   voxelSize      = template.voxelSize;
            Bounds  offsetedBounds = template.chunkOffsetedBounds;
            Vector3 boundsMin      = offsetedBounds.min;
            Vector3 boundsMax      = offsetedBounds.max;

            float minSize = PathFinder.settings.terrainFastMinimalSize;

            //terrain stuff
            TerrainData data     = terrain.terrainData;
            Vector3     position = terrain.transform.position;
            Vector3     scale    = data.size;

            //height map
            int resolution = 1;

            int heightMapSizeX = data.heightmapWidth;
            int heightMapSizeZ = data.heightmapHeight;

            float hScaleX = scale.x / (heightMapSizeX - 1);
            float hScaleZ = scale.z / (heightMapSizeZ - 1);

            for (int i = 0; i < 4; i++)
            {
                if (minSize > hScaleX * resolution)
                {
                    resolution = (int)Mathf.Pow(2, i);
                }
                else
                {
                    break;
                }
            }

            int hTargetMinX = Mathf.Clamp(((Mathf.RoundToInt((boundsMin.x - position.x) / hScaleX) / resolution) - 1) * resolution, 0, heightMapSizeX);
            int hTargetMinZ = Mathf.Clamp(((Mathf.RoundToInt((boundsMin.z - position.z) / hScaleZ) / resolution) - 1) * resolution, 0, heightMapSizeX);

            int hTargetMaxX = Mathf.Clamp(((Mathf.RoundToInt((boundsMax.x - position.x) / hScaleX) / resolution) + 1) * resolution + 1, 0, heightMapSizeX);
            int hTargetMaxZ = Mathf.Clamp(((Mathf.RoundToInt((boundsMax.z - position.z) / hScaleZ) / resolution) + 1) * resolution + 1, 0, heightMapSizeX);

            int hSizeX = hTargetMaxX - hTargetMinX;
            int hSizeZ = hTargetMaxZ - hTargetMinZ;

            int hTargetSizeX = hSizeX / resolution + 1;
            int hTargetSizeZ = hSizeZ / resolution + 1;

            if (resolution == 1)
            {
                hTargetSizeX = hSizeX;
                hTargetSizeZ = hSizeZ;
            }


            info.heightMap    = data.GetHeights(hTargetMinX, hTargetMinZ, hSizeX, hSizeZ);
            info.heightMatrix = Matrix4x4.TRS(
                position + new Vector3(hScaleX * hTargetMinX, 0, hScaleZ * hTargetMinZ),
                Quaternion.identity,
                new Vector3(hScaleX * resolution, scale.y, hScaleZ * resolution));

            info.hSizeX     = hTargetSizeX;
            info.hSizeZ     = hTargetSizeZ;
            info.resolution = resolution;

            //rest
            VectorInt.Vector3Int terrainStartInt = new VectorInt.Vector3Int((position / voxelSize) + template.halfVoxelOffset);
            VectorInt.Vector3Int terrainEndInt   = new VectorInt.Vector3Int((position + data.size) / voxelSize + template.halfVoxelOffset);

            int startXClamp = Mathf.Clamp(terrainStartInt.x, template.startX_extra, template.endX_extra);
            int startZClamp = Mathf.Clamp(terrainStartInt.z, template.startZ_extra, template.endZ_extra);

            int endXClamp = Mathf.Clamp(terrainEndInt.x, template.startX_extra, template.endX_extra);
            int endZClamp = Mathf.Clamp(terrainEndInt.z, template.startZ_extra, template.endZ_extra);

            int terrainStartX = terrainStartInt.x;
            int terrainStartZ = terrainStartInt.z;

            float terrainSizeX = terrainEndInt.x - terrainStartX;
            float terrainSizeZ = terrainEndInt.z - terrainStartZ;

            var navmeshSettings = terrain.gameObject.GetComponent <TerrainNavmeshSettings>();

            if (navmeshSettings != null && navmeshSettings.isActiveAndEnabled && navmeshSettings.data.Any(x => x != 0))  //0 is default so if there is settings full of deffault areas then dont need that
            {
                Vector3 size = data.size;
                info.settings    = navmeshSettings;
                info.startXClamp = startXClamp;
                info.startZClamp = startZClamp;

                info.endXClamp = endXClamp;
                info.endZClamp = endZClamp;

                info.terrainStartX = terrainStartX;
                info.terrainStartZ = terrainStartZ;

                info.terrainSizeX = terrainSizeX;
                info.terrainSizeZ = terrainSizeZ;

                //all this values needed in 2 places. here to use data.GetAlphamaps in main thread and later in not main thread
                //so we just store it in terrain collider info
                info.alphaWidth  = data.alphamapWidth;
                info.alphaHeight = data.alphamapHeight;

                //normalized start and end
                //dont needed later
                float terNormStartX = Mathf.Clamp01((template.chunkData.realX - template.properties.radius - position.x) / size.x);
                float terNormStartZ = Mathf.Clamp01((template.chunkData.realZ - template.properties.radius - position.z) / size.z);

                float terNormEndX = Mathf.Clamp01((template.chunkData.realX + PathFinder.gridSize + template.properties.radius - position.x) / size.x);
                float terNormEndZ = Mathf.Clamp01((template.chunkData.realZ + PathFinder.gridSize + template.properties.radius - position.z) / size.z);

                //alpha map position of chunk
                info.alphaStartX = Mathf.RoundToInt(terNormStartX * info.alphaWidth);
                info.alphaStartZ = Mathf.RoundToInt(terNormStartZ * info.alphaHeight);

                //alpha map size of chunk
                //size needed only now
                info.alphaSizeX = Mathf.Min(Mathf.RoundToInt((terNormEndX - terNormStartX) * info.alphaWidth) + 1, info.alphaWidth - info.alphaStartX);
                info.alphaSizeZ = Mathf.Min(Mathf.RoundToInt((terNormEndZ - terNormStartZ) * info.alphaHeight) + 1, info.alphaHeight - info.alphaStartZ);

                info.alphaMap     = data.GetAlphamaps(info.alphaStartX, info.alphaStartZ, info.alphaSizeX, info.alphaSizeZ);
                info.possibleArea = (from areaID in navmeshSettings.data select PathFinder.GetArea(areaID)).ToArray(); //else if doCollectAreaInfo == false than later it became defaul area
            }

            switch (terrainCollectionType)
            {
            case TerrainCollectorType.CPU:
                terrainsInfoForCPU.Add(info);
                break;

            case TerrainCollectorType.ComputeShader:
                CollectTerrainOnGPU(info);
                break;
            }
        }