//apply terrain area info if it exist protected void SetTerrainArea(Volume volume, TerrainColliderInfoAbstract info, Area defaultArea) { if (info.alphaMap != null) { var areaLibrary = PathFinder.settings.areaLibrary; int[][] areaMap = ProcessAlphaMap(info); for (int x = 0; x < template.lengthX_extra; x++) { for (int z = 0; z < template.lengthZ_extra; z++) { int a = areaMap[x][z]; volume.SetArea(x, z, areaLibrary[a]); if (a == 1) { volume.SetPassability(x, z, Passability.Unwalkable); } } } } else { volume.SetArea(defaultArea); } }
//add some values to target TerrainColliderInfoAbstract so later on we can process maps protected void SetTerrainSettings( TerrainColliderInfoAbstract info, Terrain terrain, int startXClamp, int startZClamp, int endXClamp, int endZClamp, int terrainStartX, int terrainStartZ, float terrainSizeX, float terrainSizeZ, Vector3 position) { 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 { TerrainData data = terrain.terrainData; 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.settings.gridSize + template.properties.radius - position.x) / size.x); float terNormEndZ = Mathf.Clamp01((template.chunkData.realZ + PathFinder.settings.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 = Math.Min(Mathf.RoundToInt((terNormEndX - terNormStartX) * info.alphaWidth) + 1, info.alphaWidth - info.alphaStartX); info.alphaSizeZ = Math.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 } }
//make area map from raw data. as input alpha map, as output int[][] where int is index of area in area library //used in threads splited to separate function cause it's just unreadable in other case //changes "areaMap" and "passabilityMap" variables inside terrainInfo protected int[][] ProcessAlphaMap(TerrainColliderInfoAbstract terrainInfo) { float[,,] alpha = terrainInfo.alphaMap; int alphaCount = alpha.GetLength(2); int[] alphaToArea = terrainInfo.settings.data; //shome stored values int startXClamp = terrainInfo.startXClamp; int startZClamp = terrainInfo.startZClamp; int endXClamp = terrainInfo.endXClamp; int endZClamp = terrainInfo.endZClamp; int terrainStartX = terrainInfo.terrainStartX; int terrainStartZ = terrainInfo.terrainStartZ; float terrainSizeX = terrainInfo.terrainSizeX; float terrainSizeZ = terrainInfo.terrainSizeZ; int alphaWidth = terrainInfo.alphaWidth; int alphaHeight = terrainInfo.alphaHeight; int alphaStartX = terrainInfo.alphaStartX; int alphaStartZ = terrainInfo.alphaStartZ; int alphaSizeXIndexLimit = terrainInfo.alphaSizeX - 1; int alphaSizeZIndexLimit = terrainInfo.alphaSizeZ - 1; int[][] areaMap = new int[template.lengthX_extra][]; for (int x = 0; x < template.lengthX_extra; x++) { areaMap[x] = new int[template.lengthZ_extra]; } terrainInfo.areaMap = areaMap; //this done this way to take into account that a alpha map not aligned with chunk start for (int x = startXClamp; x < endXClamp; x++) { int curX = Mathf.Clamp(Mathf.RoundToInt((x - terrainStartX) / terrainSizeX * alphaWidth) - alphaStartX, 0, alphaSizeXIndexLimit); for (int z = startZClamp; z < endZClamp; z++) { int curZ = Mathf.Clamp(Mathf.RoundToInt((z - terrainStartZ) / terrainSizeZ * alphaHeight) - alphaStartZ, 0, alphaSizeZIndexLimit); int highest = 0; for (int i = 0; i < alphaCount; i++) { if (alpha[curZ, curX, i] > alpha[curZ, curX, highest]) { highest = i; } } areaMap[x - template.startX_extra][z - template.startZ_extra] = alphaToArea[highest]; } } return(areaMap); }
protected Volume CollectTrees(TerrainColliderInfoAbstract terrain) { List <Bounds> treeBounds = terrain.treeData; if (treeBounds == null || treeBounds.Count == 0) { return(null); } //Vector3[] trs; //int[] ind; //GenerateTreesMesh(treeBounds, out trs, out ind); //Debuger_K.AddMesh(trs, ind, new Color(1, 0, 0, 0.1f)); Area defaultArea = PathFinder.getDefaultArea; Volume treeVolume = new Volume(template.lengthX_extra, template.lengthZ_extra, defaultArea); treeVolume.terrain = true; treeVolume.trees = true; Bounds chunkBounds = template.chunkOffsetedBounds; int l = fancyVerts.Length; Vector3[] treeBuffer = new Vector3[l]; foreach (var bound in treeBounds) { if (!chunkBounds.Intersects(bound)) { continue; } Matrix4x4 m = Matrix4x4.TRS(bound.center, Quaternion.identity, new Vector3(bound.size.x, bound.size.y * 0.5f, bound.size.z)); for (int i = 0; i < l; i++) { treeBuffer[i] = m.MultiplyPoint3x4(fancyVerts[i]); } #if UNITY_EDITOR if (Debuger_K.doDebug && Debuger_K.debugOnlyNavMesh == false) { Debuger_K.AddTreeCollider(template.gridPosX, template.gridPosZ, template.properties, new Bounds(bound.center, bound.extents), treeBuffer, fancyTris); } #endif for (int tris = 0; tris < fancyTris.Length; tris += 3) { base.RasterizeTriangle( treeVolume, treeBuffer[fancyTris[tris]], treeBuffer[fancyTris[tris + 1]], treeBuffer[fancyTris[tris + 2]], template.voxelSize, template.startX_extra, template.endX_extra, template.startZ_extra, template.endZ_extra, defaultArea, Passability.Unwalkable, VoxelState.Terrain, VoxelState.Tree); } } treeVolume.SetVolumeMinimum(-1000f); treeVolume.dead = true; return(treeVolume); }