Exemple #1
0
 void StartGenerationThreads()
 {
     if (effectiveMultithreadGeneration)
     {
         generationThreadsRunning = true;
         for (int k = 0; k < meshingThreads.Length; k++)
         {
             MeshingThread thread = meshingThreads [k];
             thread.waitEvent            = new AutoResetEvent(false);
             thread.meshGenerationThread = new Thread(() => GenerateChunkMeshDataInBackgroundThread(thread));
             thread.meshGenerationThread.Start();
         }
     }
 }
Exemple #2
0
        void GenerateChunkMeshDataInMainThread(long endTime)
        {
            long          elapsed;
            MeshingThread thread = meshingThreads [0];

            do
            {
                if (thread.meshJobMeshDataGenerationIndex == thread.meshJobMeshLastIndex)
                {
                    return;
                }
                GenerateChunkMeshDataOneJob(thread);
                thread.meshJobMeshDataGenerationReadyIndex = thread.meshJobMeshDataGenerationIndex;
                elapsed = stopWatch.ElapsedMilliseconds;
            } while (elapsed < endTime);
        }
Exemple #3
0
 void GenerateChunkMeshDataInBackgroundThread(MeshingThread thread)
 {
     try {
         while (generationThreadsRunning)
         {
             bool idle;
             lock (thread.indicesUpdating) {
                 idle = thread.meshJobMeshDataGenerationIndex == thread.meshJobMeshLastIndex;
             }
             if (idle)
             {
                 thread.waitEvent.WaitOne();
                 continue;
             }
             GenerateChunkMeshDataOneJob(thread);
             lock (thread.indicesUpdating) {
                 thread.meshJobMeshDataGenerationReadyIndex = thread.meshJobMeshDataGenerationIndex;
             }
         }
     } catch (Exception ex) {
         ShowExceptionMessage(ex);
     }
 }
Exemple #4
0
 void StopGenerationThreads()
 {
     generationThreadsRunning = false;
     if (meshingThreads == null)
     {
         return;
     }
     for (int k = 0; k < meshingThreads.Length; k++)
     {
         MeshingThread meshingThread = meshingThreads [k];
         if (meshingThread != null && meshingThread.meshGenerationThread != null)
         {
             meshingThread.waitEvent.Set();
         }
     }
     for (int t = 0; t < meshingThreads.Length; t++)
     {
         MeshingThread meshingThread = meshingThreads [t];
         if (meshingThread != null && meshingThread.meshGenerationThread != null)
         {
             for (int k = 0; k < 100; k++)
             {
                 bool wait = false;
                 if (meshingThread.meshGenerationThread.IsAlive)
                 {
                     wait = true;
                 }
                 if (!wait)
                 {
                     break;
                 }
                 Thread.Sleep(10);
             }
         }
     }
 }
        void UpdateAndNotifyChunkChanges(MeshingThread thread)
        {
            // The background thread generation is working... process whatever is ready to be uploaded to the GPU
            bool finishedUploading = false;

            for (int k = 0; k < 100; k++)
            {
                lock (thread.indicesUpdating)
                {
                    if (thread.meshJobMeshUploadIndex == thread.meshJobMeshDataGenerationReadyIndex)
                    {
                        finishedUploading = true;
                        break;
                    }

                    ++thread.meshJobMeshUploadIndex;
                    if (thread.meshJobMeshUploadIndex >= thread.meshJobs.Length)
                    {
                        thread.meshJobMeshUploadIndex = 0;
                    }
                }

                VoxelChunk chunk = thread.meshJobs [thread.meshJobMeshUploadIndex].chunk;
                chunk.needsMeshRebuild = false;
                UploadMeshData(thread, thread.meshJobMeshUploadIndex);
                if (chunk.needsLightmapRebuild)
                {
                    chunk.needsLightmapRebuild = false;
                    RefreshNineChunks(chunk);
                }
                meshingIdle = false;
            }

            if (finishedUploading)
            {
                int updatedChunksCount = updatedChunks.Count;
                if (updatedChunksCount > 0)
                {
                    // Send marked chunks to background thread generation
                    for (int k = 0; k < updatedChunksCount; k++)
                    {
                        VoxelChunk chunk = updatedChunks [k];
                        if (chunk.inqueue)
                        {
                            chunk.needsMeshRebuild = true; // delay mesh update till next frame due to new chunk or nearby chunks lightmap changes or modifications
                        }
                        else
                        {
                            meshingIdle = false;
                            chunk.transform.position = chunk.position;
                            if (!CreateChunkMeshJob(chunk))
                            {
                                // can't create more mesh jobs - remove processed requests from the update list and exit
                                for (int j = 0; j < k; j++)
                                {
                                    updatedChunks.RemoveAt(0);
                                }
                                return;
                            }
                        }
                    }
                    updatedChunks.Clear();
                }
            }
        }
Exemple #6
0
        void UploadMeshData(MeshingThread thread, int jobIndex)
        {
            MeshJobData [] meshJobs = thread.meshJobs;
            VoxelChunk     chunk    = meshJobs [jobIndex].chunk;
            int            diviser  = 10;

            // Update collider?
            if (enableColliders && meshJobs [jobIndex].needsColliderRebuild)
            {
                int  colliderVerticesCount = meshJobs [jobIndex].colliderVertices.Count;
                Mesh colliderMesh          = chunk.mc.sharedMesh;
#if UNITY_EDITOR
                if (!applicationIsPlaying && editorRenderDetail != EditorRenderDetail.StandardPlusColliders)
                {
                    colliderVerticesCount = 0;
                }
#endif
                if (colliderVerticesCount == 0)
                {
                    chunk.mc.enabled = false;
                }
                else
                {
                    if (colliderMesh == null)
                    {
                        colliderMesh = new Mesh();
                    }
                    else
                    {
                        colliderMesh.Clear();
                    }
                    //for(int l = 0; l < meshJobs[jobIndex].colliderVertices.Count; l++)
                    //{
                    //    meshJobs[jobIndex].colliderVertices[l] = new Vector3(meshJobs[jobIndex].colliderVertices[l].x / meshJobs[jobIndex].colliderVertices[l].y / diviser, meshJobs[jobIndex].colliderVertices[l].z / diviser);
                    //}
                    colliderMesh.SetVertices(meshJobs [jobIndex].colliderVertices);
                    colliderMesh.SetTriangles(meshJobs [jobIndex].colliderIndices, 0);
                    chunk.mc.sharedMesh = colliderMesh;
                    chunk.mc.enabled    = true;
                }

                // Update navmesh
                if (enableNavMesh)
                {
                    int  navMeshVerticesCount = meshJobs [jobIndex].navMeshVertices.Count;
                    Mesh navMesh = chunk.navMesh;
                    if (navMesh == null)
                    {
                        navMesh = new Mesh();
                    }
                    else
                    {
                        navMesh.Clear();
                    }
                    navMesh.SetVertices(meshJobs [jobIndex].navMeshVertices);
                    navMesh.SetTriangles(meshJobs [jobIndex].navMeshIndices, 0);

                    chunk.navMesh = navMesh;
                    AddChunkNavMesh(chunk);
                }
            }

            // Update mesh?
            if (meshJobs [jobIndex].totalVoxels == 0)
            {
                if (chunk.mf.sharedMesh != null)
                {
                    chunk.mf.sharedMesh.Clear(false);
                }
                chunk.renderState = ChunkRenderState.RenderingComplete;
                return;
            }

            // Create mesh
            Mesh mesh = chunk.mf.sharedMesh;
#if !UNITY_EDITOR
            if (isMobilePlatform)
            {
                if (mesh != null)
                {
                    DestroyImmediate(mesh);
                }
                mesh = new Mesh();                  // on mobile will be released mesh data upon uploading to the GPU so the mesh is no longer readable; need to recreate it everytime the chunk is rendered
            }
            else
            {
                if (mesh == null)
                {
                    mesh = new Mesh();
                }
                else
                {
                    mesh.Clear();
                }
            }
#else
            if (mesh == null)
            {
                mesh = new Mesh();
                chunksDrawn++;
            }
            else
            {
                voxelsCreatedCount -= chunk.totalVisibleVoxelsCount;
                mesh.Clear();
            }
            chunk.totalVisibleVoxelsCount = meshJobs [jobIndex].totalVoxels;
            voxelsCreatedCount           += chunk.totalVisibleVoxelsCount;
#endif

            // Assign materials and submeshes
            mesh.subMeshCount = meshJobs [jobIndex].subMeshCount;
            if (mesh.subMeshCount > 0)
            {
                //todo: Changing vertices.. correct this

                //for (int l= 0; l< meshJobs[jobIndex].vertices.Count; l++)
                //{
                //    meshJobs[jobIndex].vertices[l] = new Vector3 (meshJobs[jobIndex].vertices[l].x / diviser, meshJobs[jobIndex].vertices[l].y/ diviser, meshJobs[jobIndex].vertices[l].z/ diviser);
                //}
                // Vertices
                mesh.SetVertices(meshJobs [jobIndex].vertices);

                // UVs, normals, colors
                mesh.SetUVs(0, meshJobs [jobIndex].uv0);
                mesh.SetNormals(meshJobs [jobIndex].normals);
                if (enableTinting)
                {
                    mesh.SetColors(meshJobs [jobIndex].colors);
                }

                int subMeshIndex = -1;
                int matIndex     = 0;

                for (int k = 0; k < MAX_MATERIALS_PER_CHUNK; k++)
                {
                    if (meshJobs [jobIndex].buffers [k].indicesCount > 0)
                    {
                        subMeshIndex++;
                        mesh.SetTriangles(meshJobs [jobIndex].buffers [k].indices, subMeshIndex, false);
                        matIndex += 1 << k;
                    }
                }

                // Compute material array
                Material [] matArray;
                if (!materialsDict.TryGetValue(matIndex, out matArray))
                {
                    matArray = new Material [mesh.subMeshCount];
                    for (int k = 0, j = 0; k < MAX_MATERIALS_PER_CHUNK; k++)
                    {
                        if (meshJobs [jobIndex].buffers [k].indicesCount > 0)
                        {
                            matArray [j++] = renderingMaterials [k].material;
                        }
                    }
                    materialsDict [matIndex] = matArray;
                }
                chunk.mr.sharedMaterials = matArray;

                if (chunk.isCloud)
                {
                    mesh.bounds = new Bounds(Misc.vector3zero, new Vector3(CHUNK_SIZE * 4, CHUNK_SIZE * 2, CHUNK_SIZE * 4));
                }
                else if (enableCurvature)
                {
                    mesh.bounds = new Bounds(Misc.vector3zero, new Vector3(CHUNK_SIZE, CHUNK_SIZE + 32, CHUNK_SIZE));
                }
                else
                {
                    mesh.bounds = new Bounds(Misc.vector3zero, new Vector3(CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE));
                }

                chunk.mf.sharedMesh = mesh;

#if !UNITY_EDITOR
                if (isMobilePlatform)
                {
                    mesh.UploadMeshData(true);
                }
#endif
                if (!chunk.mr.enabled)
                {
                    chunk.mr.enabled = true;
                }
            }

            RenderModelsInVoxels(chunk, meshJobs [jobIndex].mivs);

            if (chunk.renderState != ChunkRenderState.RenderingComplete)
            {
                chunk.renderState = ChunkRenderState.RenderingComplete;
                if (OnChunkAfterFirstRender != null)
                {
                    OnChunkAfterFirstRender(chunk);
                }
            }

            if (OnChunkRender != null)
            {
                OnChunkRender(chunk);
            }

            shouldUpdateParticlesLighting = true;
        }
Exemple #7
0
        void GenerateChunkMeshDataOneJob(MeshingThread thread)
        {
            lock (thread.indicesUpdating)
            {
                thread.meshJobMeshDataGenerationIndex++;
                if (thread.meshJobMeshDataGenerationIndex >= thread.meshJobs.Length)
                {
                    thread.meshJobMeshDataGenerationIndex = 0;
                }
            }

            VoxelChunk chunk = thread.meshJobs [thread.meshJobMeshDataGenerationIndex].chunk;

            Voxel [] [] chunk9 = thread.chunk9;
            chunk9 [13] = chunk.voxels;
            Voxel [] emptyChunk = chunk.isAboveSurface ? emptyChunkAboveTerrain : emptyChunkUnderground;
            int      chunkX, chunkY, chunkZ;

            FastMath.FloorToInt(chunk.position.x / CHUNK_SIZE, chunk.position.y / CHUNK_SIZE, chunk.position.z / CHUNK_SIZE, out chunkX, out chunkY, out chunkZ);

            // Reset bit field; inconclusive neighbours are those neighbours which are undefined when an adjacent chunk is rendered. We mark it so then it's finally rendered, we re-render the adjacent chunk. This is required if the new chunk can
            // break holes on the edge of the chunk while no lighting is entering the chunk or global illumination is disabled (yes, it's an edge case but must be addressed to avoid gaps in those cases).
            chunk.inconclusiveNeighbours = 0; //(byte)(chunk.inconclusiveNeighbours & ~CHUNK_IS_INCONCLUSIVE);

            VoxelChunk [] neighbourChunks = thread.neighbourChunks;
            neighbourChunks [13] = chunk;
            thread.allowAO       = enableSmoothLighting && !draftModeActive; // AO is disabled on edges of world to reduce vertex count
            for (int c = 0, y = -1; y <= 1; y++)
            {
                int yy = chunkY + y;
                for (int z = -1; z <= 1; z++)
                {
                    int zz = chunkZ + z;
                    for (int x = -1; x <= 1; x++, c++)
                    {
                        if (y == 0 && z == 0 && x == 0)
                        {
                            continue;
                        }
                        int        xx = chunkX + x;
                        VoxelChunk neighbour;
                        if (GetChunkFast(xx, yy, zz, out neighbour, false) && (neighbour.isPopulated || neighbour.isRendered))
                        {
                            chunk9 [c] = neighbour.voxels;
                        }
                        else
                        {
                            chunk.inconclusiveNeighbours |= inconclusiveNeighbourTable [c];
                            chunk9 [c] = emptyChunk;
                            if (y == 0 && !chunk.modified)
                            {
                                // if this chunk has no neighbours horizontally and is not modified, it's probably an edge chunk.
                                // in this case, disable AO so the entire edge wall can be rendered using a single quad thanks to greedy meshing
                                thread.allowAO = false;
                            }
                        }
                        neighbourChunks [c] = neighbour;
                    }
                }
            }
#if USES_SEE_THROUGH
            lock (seeThroughLock) {
                // Hide voxels marked as hidden
                for (int c = 0; c < neighbourChunks.Length; c++)
                {
                    ToggleHiddenVoxels(neighbourChunks [c], false);
                }
#endif

            thread.GenerateMeshData();

#if USES_SEE_THROUGH
            // Reactivate hidden voxels
            for (int c = 0; c < neighbourChunks.Length; c++)
            {
                ToggleHiddenVoxels(neighbourChunks [c], true);
            }
        }
#endif
        }