/// <summary> /// Builds the navigation graph for obstacle. /// If updateObstc is set to true cond., firstly, remove occuranse of obstacle in the graph. /// </summary> /// <param name="obstacleGOToUpdate">GameObject-obstacle, for which you want to update the graph.</param> /// <param name="cancToken">Cancellation token for controll to async handeling</param> /// <param name="entitiesTasksToParallelize">List, you want to put handelling task in (if you want)</param> /// <param name="updateObstc">Is obstc graph updating for, already was handeled once.</param> public void UpdateGraphForObstacle(GameObject obstacleGOToUpdate, CancellationToken cancToken, bool updateObstc = false) { MeshCollider meshColliderInst = obstacleGOToUpdate.GetComponent <MeshCollider>(); MeshFilter meshFilterInst = obstacleGOToUpdate.GetComponent <MeshFilter>(); Terrain terrainInst = obstacleGOToUpdate.GetComponent <Terrain>(); if (updateObstc) { SpaceGraph.ReleaseCellsFromObstcID(obstacleGOToUpdate.transform.GetInstanceID()); } MeshDataContainer mDCInst = new MeshDataContainer() { gameObjectName = obstacleGOToUpdate.name, transformData = obstacleGOToUpdate.transform, instanceID = obstacleGOToUpdate.transform.GetInstanceID(), CTInstance = cancToken }; if (meshColliderInst && meshColliderInst.sharedMesh) { mDCInst.triangles = meshColliderInst.sharedMesh.triangles; mDCInst.vertices = meshColliderInst.sharedMesh.vertices; HandleEntity(mDCInst, EntityType.Mesh); } if (meshFilterInst && meshFilterInst.sharedMesh) { mDCInst.triangles = meshFilterInst.sharedMesh.triangles; mDCInst.vertices = meshFilterInst.sharedMesh.vertices; HandleEntity(mDCInst, EntityType.Mesh); } if (terrainInst) { float[,] hmArr = terrainInst.terrainData.GetHeights(0, 0, terrainInst.terrainData.heightmapResolution, terrainInst.terrainData.heightmapResolution); TerrainDataContainer tDCInst = new TerrainDataContainer() { gameObjectName = obstacleGOToUpdate.name, maxH = terrainInst.terrainData.size.y, hMArray = hmArr, hMWidth = terrainInst.terrainData.heightmapResolution, xStart = 1, xEnd = terrainInst.terrainData.heightmapResolution, zStart = 1, zEnd = terrainInst.terrainData.heightmapResolution, hX = terrainInst.terrainData.size.x, hZ = terrainInst.terrainData.size.z, terrainPos = terrainInst.GetPosition(), hMapScaleX = terrainInst.terrainData.heightmapScale.x, hMapScaleZ = terrainInst.terrainData.heightmapScale.z, instanceID = terrainInst.transform.GetInstanceID(), CTInstance = cancToken }; HandleEntity(tDCInst, EntityType.Terrain); } }
/// <summary> /// Performs the distribution of obstacle handeling into several subtasks for their further asynchronous execution. /// </summary> /// <param name="entityData">MeshDataContainer or TerrainDataContainer, packed as object.</param> /// <param name="entityType">Represent type of the <paramref name="entityData" /> to provide correct unpack from object type.</param> /// <param name="entitiesTasksToParallelize">List in which subtasks puts.</param> void HandleEntity(object entityData, EntityType entityType) { if (entityType == EntityType.Mesh) { MeshDataContainer mDCInst = ((MeshDataContainer)entityData).Clone(); int tripletsNum = Mathf.CeilToInt(((float)mDCInst.triangles.Length / 3) / maxAliveAsyncTasksCount); if (tripletsNum == 0) { tripletsNum = 1; } while (mDCInst.triangles.Length > 0) { int trisIntsNum = Mathf.Min(mDCInst.triangles.Length, tripletsNum * 3); int[] distrTrisArr = mDCInst.triangles.Take(trisIntsNum).ToArray(); mDCInst.triangles = mDCInst.triangles.Skip(trisIntsNum).ToArray(); MeshDataContainer newMDCInst = ((MeshDataContainer)entityData).Clone(); newMDCInst.triangles = distrTrisArr; asyncTasksQueue.Enqueue(new object[] { TaskType.Handling, entityType, newMDCInst }); } } else { int xDelta, n; int hMWidth = ((TerrainDataContainer)entityData).hMWidth; if (maxAliveAsyncTasksCount == 1) { xDelta = hMWidth; n = 1; } else { xDelta = Mathf.CeilToInt((float)hMWidth / maxAliveAsyncTasksCount / 16); n = Mathf.CeilToInt((float)hMWidth / xDelta); } for (var i = 0; i < n; ++i) { TerrainDataContainer tDCInst = ((TerrainDataContainer)entityData).Clone(); tDCInst.xStart = i * xDelta + 1; tDCInst.xEnd = Mathf.Min(i * xDelta + xDelta + 1, hMWidth); asyncTasksQueue.Enqueue(new object[] { TaskType.Handling, entityType, tDCInst }); } } }
public TerrainDataContainer Clone() { TerrainDataContainer cloneInstance = new TerrainDataContainer { maxH = this.maxH, hMArray = this.hMArray, xStart = this.xStart, xEnd = this.xEnd, zStart = this.zStart, zEnd = this.zEnd, hX = this.hX, hZ = this.hZ, hMWidth = this.hMWidth, terrainPos = new Vector3(this.terrainPos.x, this.terrainPos.y, this.terrainPos.z), hMapScaleX = this.hMapScaleX, hMapScaleZ = this.hMapScaleZ, instanceID = this.instanceID, CTInstance = this.CTInstance, gameObjectName = this.gameObjectName }; return(cloneInstance); }
/// <summary> /// Perfoms handeling of the terrain. Must be running asyncronously. /// </summary> /// <param name="inpData">Terrain to handle data, packed from MeshDataContainer instance.</param> void AsyncTerrainMethod(object inpData) { if (agressiveUseMultithreading) { Interlocked.Increment(ref aliveHandelingTasksCount); } TerrainDataContainer tDCInst = (TerrainDataContainer)inpData; int curTaskId = uniqeHandlingTaskID; Interlocked.Increment(ref uniqeHandlingTaskID); AsyncTaskDataContainer aTDCInstance = new AsyncTaskDataContainer { gameObjectName = tDCInst.gameObjectName, threadName = Thread.CurrentThread.Name, uniqeTaskID = curTaskId, trisCount = (tDCInst.xEnd - tDCInst.xStart) * (tDCInst.zEnd - tDCInst.zStart) * 2, verticesCount = tDCInst.hMArray.Length }; aliveTasksDict.TryAdd(curTaskId, aTDCInstance); try { CancellationToken localCancToken = (CancellationToken)tDCInst.CTInstance; Vector3 p0, p1, p2, p3; int step = 1; int hMWidth = tDCInst.hMWidth; Vector3 terrPos = tDCInst.terrainPos; float hZ = tDCInst.hZ; float hX = tDCInst.hX; float[,] hMArray = tDCInst.hMArray; float maxH = tDCInst.maxH; for (var x = tDCInst.xStart; x < tDCInst.xEnd; x += step) { if (broadcastCancToken.IsCancellationRequested || localCancToken.IsCancellationRequested) { return; } for (var z = tDCInst.zStart; z < tDCInst.zEnd; z += step) { p0 = new Vector3(((float)(z - step) / hMWidth) * hZ + terrPos.x, (hMArray[x - step, z - step] * maxH) + terrPos.y, ((float)(x - step) / hMWidth) * hX + terrPos.z); p1 = new Vector3(((float)(z - step) / hMWidth) * hZ + terrPos.x, (hMArray[x, z - step] * maxH) + terrPos.y, ((float)x / hMWidth) * hX + terrPos.z); p2 = new Vector3(((float)z / hMWidth) * hZ + terrPos.x, (hMArray[x - step, z] * maxH) + terrPos.y, ((float)(x - step) / hMWidth) * hX + terrPos.z); p3 = new Vector3(((float)z / hMWidth) * hZ + terrPos.x, (hMArray[x, z] * maxH) + terrPos.y, ((float)x / hMWidth) * hX + terrPos.z); OccupyCellsForATriangle(p0, p1, p2, tDCInst.instanceID); OccupyCellsForATriangle(p1, p2, p3, tDCInst.instanceID); } } aliveTasksDict.TryRemove(curTaskId, out aTDCInstance); Interlocked.Decrement(ref aliveHandelingTasksCount); if (!isPrimaryProcessingCompleted && processedTrisCount >= totalTrisCount && aliveHandelingTasksCount == 0) { NotifyRediness(); } } catch (Exception ex) { UnityEngine.Debug.Log(ex.Message + " " + ex.StackTrace); } }