public IEnumerator ImportFaceMeshData(MeshDataContainer data) { yield return(new WaitForEndOfFrame()); int totalFrames = data.meshDataList.Count; int totalInputs = data.meshDataList[25].pos.Count; //int totalInputs = data.meshDataList[25].pos.Length; int maxValue = 1; for (int graph = 0; graph < totalInputs; graph++) { List <Vector2> GraphData = new List <Vector2>(); for (int frame = 0; frame < data.meshDataList.Count; frame++) { Vector3 tmp = new Vector3((float)data.meshDataList[frame].pos[graph].x, (float)data.meshDataList[frame].pos[graph].y, (float)data.meshDataList[frame].pos[graph].z); float mag = tmp.sqrMagnitude * 100; var offsetFrame = (int)(frame - (totalFrames / 2)); var offsetVector = mag - (0.65f); GraphData.Add(new Vector2(offsetFrame, offsetVector)); } LineRendererHUD lineRenderer = GenerateGraph(); lineRenderer.points = GraphData; lineRenderer.thickness = 5; //grid size = x = frame amout, y max value lineRenderer.gridSize = new Vector2Int(totalFrames, maxValue); lineRenderer.color = new Color(1, 0, 0, 0.15f); } }
/// <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 MeshDataContainer Clone() { MeshDataContainer cloneInstance = new MeshDataContainer { transformData = this.transformData }; cloneInstance.vertices = new Vector3[this.vertices.Length]; this.vertices.CopyTo(cloneInstance.vertices, 0); cloneInstance.triangles = new int[this.triangles.Length]; this.triangles.CopyTo(cloneInstance.triangles, 0); cloneInstance.instanceID = this.instanceID; cloneInstance.CTInstance = this.CTInstance; cloneInstance.gameObjectName = this.gameObjectName; return(cloneInstance); }
/// <summary> /// Perfoms handeling of a mesh. Must be running asyncronously. /// </summary> /// <param name="inpData">Mesh to handle data, packed from MeshDataContainer instance. </param> void AsyncMeshMethod(object inpData) { try { if (agressiveUseMultithreading) { Interlocked.Increment(ref aliveHandelingTasksCount); } MeshDataContainer mDCInstance = (MeshDataContainer)inpData; int curTaskId = uniqeHandlingTaskID; Interlocked.Increment(ref uniqeHandlingTaskID); AsyncTaskDataContainer aTDCInstance = new AsyncTaskDataContainer { gameObjectName = mDCInstance.gameObjectName, threadName = Thread.CurrentThread.Name, uniqeTaskID = curTaskId, trisCount = mDCInstance.triangles.Length / 3, verticesCount = mDCInstance.vertices.Length }; aliveTasksDict.TryAdd(curTaskId, aTDCInstance); int[] triangles = null; int p0i = 0; int p1i = 0; int p2i = 0; Vector3[] vertices = mDCInstance.vertices; triangles = mDCInstance.triangles; CustomTransform meshCTransf = mDCInstance.transformData; int instanceID = mDCInstance.instanceID; for (var i = 1; i <= mDCInstance.triangles.Length / 3; ++i) { try { if ((broadcastCancToken.IsCancellationRequested) || ((CancellationToken)mDCInstance.CTInstance).IsCancellationRequested) { return; } p0i = triangles[(i - 1) * 3]; p1i = triangles[(i - 1) * 3 + 1]; p2i = triangles[(i - 1) * 3 + 2]; Vector3 p0 = vertices[triangles[(i - 1) * 3]]; Vector3 p1 = vertices[triangles[(i - 1) * 3 + 1]]; Vector3 p2 = vertices[triangles[(i - 1) * 3 + 2]]; OccupyCellsForATriangle( meshCTransf.position + meshCTransf.rotation * (Vector3.Scale(meshCTransf.localScale, p0)), meshCTransf.position + meshCTransf.rotation * (Vector3.Scale(meshCTransf.localScale, p1)), meshCTransf.position + meshCTransf.rotation * (Vector3.Scale(meshCTransf.localScale, p2)), instanceID ); } catch (Exception ex) { if (!isPrimaryProcessingCompleted) { Interlocked.Increment(ref processedTrisCount); } throw (ex); } } aliveTasksDict.TryRemove(curTaskId, out aTDCInstance); Interlocked.Decrement(ref aliveHandelingTasksCount); if (!isPrimaryProcessingCompleted && processedTrisCount >= totalTrisCount && aliveHandelingTasksCount == 0) { NotifyRediness(); } } catch (Exception ex) { UnityEngine.Debug.Log(ex.Message); } }
public static void BakeLights() { DateTime bakeStart = DateTime.Now; // current selection GameObject[] selection = Selection.gameObjects; List <MeshFilter> meshes = new List <MeshFilter>(); // gather meshes in selection foreach (GameObject go in selection) { meshes.AddRange(go.GetComponentsInChildren <MeshFilter>()); } if (meshes.Count == 0) { EditorUtility.DisplayDialog("Error", "No meshes in selection", "ok"); return; } // mesh renderers allow access to additional mesh data List <MeshRenderer> meshRenderers = new List <MeshRenderer>(); // gather meshes in selection build 1 to 1 list of mesh filters to mesh renderers foreach (MeshFilter filter in meshes) { MeshRenderer mr = filter.GetComponent <MeshRenderer>(); if (mr != null) { meshRenderers.Add(mr); } } if (meshes.Count != meshRenderers.Count) { EditorUtility.DisplayDialog("Error", "MeshRenderers are not 1 to 1 with Mesh Filters", "ok"); return; } List <Light> lights = new List <Light>(); // Gather lights GameObject[] roots = SceneManager.GetActiveScene().GetRootGameObjects(); foreach (GameObject go in roots) { if (go.activeSelf) { lights.AddRange(go.GetComponentsInChildren <Light>()); } } int workerThreadCount = Math.Max(7, Environment.ProcessorCount - 1); ThreadPool.SetMaxThreads(workerThreadCount, workerThreadCount); ThreadPool.SetMinThreads(1, 1); // create new meshes with lights baked in for (int i = 0, count = meshes.Count; i < count; ++i) { Matrix4x4 worldM = meshes[i].gameObject.transform.localToWorldMatrix; // create new mesh to hold color data for (int c = 0; c < 3; ++c) { m_basisValues[c] = new List <Vector3>(); } ManualResetEvent[] waitHandles = new ManualResetEvent[workerThreadCount]; for (int e = 0; e < workerThreadCount; ++e) { waitHandles[e] = new ManualResetEvent(false); } int itemsPerThread = meshes[i].sharedMesh.vertexCount / workerThreadCount; int remainder = meshes[i].sharedMesh.vertexCount % workerThreadCount; // store basis results here then combine into final result List <List <Vector3>[]> tempBasisValues = new List <List <Vector3>[]>(); for (int t = 0; t < workerThreadCount; ++t) { tempBasisValues.Add(new List <Vector3> [3]); for (int c = 0; c < 3; ++c) { tempBasisValues[t][c] = new List <Vector3>(); } // create cache friendly lists of data SOAVertex verts = new SOAVertex(meshes[i].sharedMesh.vertices.Length); verts.vertices = meshes[i].sharedMesh.vertices; verts.normals = meshes[i].sharedMesh.normals; verts.tangents = meshes[i].sharedMesh.tangents; LightSOA lightsSoa = new LightSOA(lights); object context = new object[] { waitHandles[t], verts, worldM, lightsSoa, tempBasisValues[t], // output list itemsPerThread, // number of verts to process itemsPerThread *t, // vert offset remainder, // last thread will process remainder t == (workerThreadCount - 1), // is last t // id }; ThreadPool.QueueUserWorkItem(ProcessVertex, context); //ProcessVertex(context); } // wait for jobs to finish WaitHandle.WaitAll(waitHandles); // collect basis value results for (int t = 0; t < workerThreadCount; ++t) { m_basisValues[0].AddRange(tempBasisValues[t][0]); m_basisValues[1].AddRange(tempBasisValues[t][1]); m_basisValues[2].AddRange(tempBasisValues[t][2]); } const int uvOffset = 1; // if vertices is not set than we cannot set UVS // these vertices seem to be used then in place of the primary meshes vertices Mesh colorData = new Mesh(); colorData.vertices = meshes[i].sharedMesh.vertices; colorData.SetUVs(uvOffset + 0, m_basisValues[0]); colorData.SetUVs(uvOffset + 1, m_basisValues[1]); colorData.SetUVs(uvOffset + 2, m_basisValues[2]); colorData.UploadMeshData(true); string assetPath = "Assets/BakedLighting"; if (!Directory.Exists(assetPath)) { Directory.CreateDirectory(assetPath); } AssetDatabase.CreateAsset(colorData, assetPath + "/" + meshRenderers[i].GetInstanceID() + ".asset"); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); colorData = AssetDatabase.LoadAssetAtPath <Mesh>(assetPath + "/" + meshRenderers[i].GetInstanceID() + ".asset"); MeshDataContainer meshDataContainer = meshRenderers[i].GetComponent <MeshDataContainer>(); if (meshDataContainer == null) { meshDataContainer = meshRenderers[i].gameObject.AddComponent <MeshDataContainer>(); } meshDataContainer.m_mesh = colorData; meshRenderers[i].additionalVertexStreams = colorData; EditorUtility.SetDirty(meshDataContainer.m_mesh); EditorUtility.SetDirty(meshDataContainer); EditorUtility.SetDirty(meshRenderers[i].gameObject); AssetDatabase.SaveAssets(); } Debug.Log("Bake time: " + (DateTime.Now - bakeStart).TotalSeconds + " seconds"); }