Exemplo n.º 1
0
    void Start()
    {
        switch (Example)
        {
        case ExampleType.DummyJobs:
            var randomSeed = new Random();
            Debug.Log("Testing Background Threads");
            for (var i = 0; i < 20; i++)
            {
                var i1 = i;
                ThreadManager.Execute((container) =>
                {
                    var random = new Random(randomSeed.Next());
                    var delay  = random.Next(0, 10000);
                    Debug.Log($"Job: {i1} Executes and takes {delay}ms!");
                    Thread.Sleep(delay);
                    Debug.Log($"Job: {i1} Complete!");
                });
            }
            break;

        case ExampleType.AccessMainThreadVariableBad:
            ThreadManager.Execute((container) =>
            {
                Debug.Log("You cannot access certain variables from background threads, only the main thread.");
                Debug.Log("This will throw an error:");
                try
                {
                    Debug.Log($"Current time: {Time.time}");
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }
            });
            break;

        case ExampleType.AccessMainThreadVariableGood:
            ThreadManager.Execute((container) =>
            {
                Debug.Log("To access Main Thread only variables, you can use ExecuteOnMainThreadAndWait()");
                var time = 0f;
                ThreadManager.ExecuteOnMainThreadAndWait(() => { time = Time.time; });
                Debug.Log($"The time was {time}");
            });
            break;

        case ExampleType.PerformActionMainThread:
            ThreadManager.Execute((container) =>
            {
                Debug.Log("If you need to do something on the Main Thread (such as Mesh assignment), you can do it with ExecuteOnMainThread()");
                Debug.Log("You can check if you are on the Main Thread (but generally you should always know where your code is executing). This action will throw a warning");
                MainThreadAction();
                Debug.Log("Lets try that again on the Main Thread");
                ThreadManager.ExecuteOnMainThread(MainThreadAction);
            });
            break;

        case ExampleType.PerformAssignmentMainThread:
            // Lets create a dummy GameObject to work with
            var go           = new GameObject("Dummy", typeof(MeshRenderer), typeof(MeshFilter));
            var meshRenderer = go.GetComponent <MeshRenderer>();
            var meshFilter   = go.GetComponent <MeshFilter>();

            ThreadManager.Execute((container) =>
            {
                Debug.Log("Now lets try making a mesh using the thread pool");

                // Generate mesh data
                var vertices = new List <Vector3>();
                var uvs      = new List <Vector2>();
                var normals  = new List <Vector3>();
                var indices  = new List <int>();
                CubeData.AddCube(ref vertices, ref uvs, ref normals, ref indices, Vector3.zero, false);

                // Convert these lists to arrays for the mesh
                var verts = vertices.ToArray();
                var uv    = uvs.ToArray();
                var norm  = normals.ToArray();
                var ind   = indices.ToArray();

                // Now that we have the data, assign it on the main thread
                ThreadManager.ExecuteOnMainThread(() =>
                {
                    meshRenderer.material = MeshMaterial;
                    var mesh = new Mesh
                    {
                        vertices  = verts,
                        uv        = uv,
                        normals   = norm,
                        triangles = ind,
                    };
                    meshFilter.mesh = mesh;
                    Debug.Log("Mesh Assigned!");
                });
            });
            break;

        case ExampleType.Chunk:
            var chunk = Instantiate(ChunkScriptPrefab.gameObject, new Vector3(0f, 0f, 0f), Quaternion.identity);
            break;

        case ExampleType.ChunkAdvanced:
            Instantiate(ChunkAdvancedScriptPrefab.gameObject, new Vector3(0f, 0f, 0f), Quaternion.identity);
            Instantiate(ChunkAdvancedScriptPrefab.gameObject, new Vector3(ChunkAdvancedScript.ChunkWidth, 0f, 0f), Quaternion.identity);
            Instantiate(ChunkAdvancedScriptPrefab.gameObject, new Vector3(0f, 0f, ChunkAdvancedScript.ChunkDepth), Quaternion.identity);
            Instantiate(ChunkAdvancedScriptPrefab.gameObject, new Vector3(ChunkAdvancedScript.ChunkWidth, 0f, ChunkAdvancedScript.ChunkDepth), Quaternion.identity);
            Instantiate(ChunkAdvancedScriptPrefab.gameObject, new Vector3(0f, ChunkAdvancedScript.ChunkHeight, 0f), Quaternion.identity);
            Instantiate(ChunkAdvancedScriptPrefab.gameObject, new Vector3(ChunkAdvancedScript.ChunkWidth, ChunkAdvancedScript.ChunkHeight, 0f), Quaternion.identity);
            Instantiate(ChunkAdvancedScriptPrefab.gameObject, new Vector3(0f, ChunkAdvancedScript.ChunkHeight, ChunkAdvancedScript.ChunkDepth), Quaternion.identity);
            Instantiate(ChunkAdvancedScriptPrefab.gameObject, new Vector3(ChunkAdvancedScript.ChunkWidth, ChunkAdvancedScript.ChunkHeight, ChunkAdvancedScript.ChunkDepth), Quaternion.identity);
            break;

        default:
            throw new ArgumentOutOfRangeException();
        }
    }
Exemplo n.º 2
0
    /// <summary>
    /// Thread Safe! Sets a Voxel in this Chunk and starts a Meshing job.
    /// </summary>
    private void SetVoxel(int x, int y, int z, byte voxelId)
    {
        lock (_debugLocker)
        {
            _debugVoxelUpdates++;
        }
        // Arrays are reference types, so create a blank array to grab the value to
        var voxels = new byte[ChunkWidth][][];

        for (var x1 = 0; x1 < ChunkWidth; x1++)
        {
            voxels[x1] = new byte[ChunkHeight][];
            for (var y1 = 0; y1 < ChunkHeight; y1++)
            {
                voxels[x1][y1] = new byte[ChunkDepth];
            }
        }
        // Update the Chunk state and grab the current state
        lock (_voxelLocker)
        {
            if (_voxels[x][y][z] == voxelId)
            {
                return;                              // Don't need to generate a new mesh if the state is unchanged
            }
            _voxels[x][y][z] = voxelId;
            for (var x1 = 0; x1 < ChunkWidth; x1++)
            {
                for (var y1 = 0; y1 < ChunkHeight; y1++)
                {
                    for (var z1 = 0; z1 < ChunkDepth; z1++)
                    {
                        voxels[x1][y1][z1] = _voxels[x1][y1][z1];
                    }
                }
            }
        }
        ThreadManager.Execute((container) =>
        {
            var job = GetNextJobId();

            // Generate mesh data
            var vertices = new List <Vector3>();
            var uvs      = new List <Vector2>();
            var normals  = new List <Vector3>();
            var indices  = new List <int>();
            for (var x1 = 0; x1 < ChunkWidth; x1++)
            {
                for (var y1 = 0; y1 < ChunkHeight; y1++)
                {
                    for (var z1 = 0; z1 < ChunkDepth; z1++)
                    {
                        if (voxels[x1][y1][z1] == 0)
                        {
                            continue;
                        }

                        CubeData.AddCube(ref vertices, ref uvs, ref normals, ref indices, new Vector3(x1, y1, z1), false);
                    }
                }
            }

            // Convert these lists to arrays for the mesh
            var verts = vertices.ToArray();
            var uv    = uvs.ToArray();
            var norm  = normals.ToArray();
            var ind   = indices.ToArray();
            ThreadManager.ExecuteOnMainThread(() =>
            {
                if (GetLastJobId() > job) // Stale Mesh
                {
                    return;
                }
                SetLastJobId(job);
                SetMesh(verts, uv, norm, ind);
            });
        });
    }
Exemplo n.º 3
0
    void Update()
    {
        // Randomly update the Voxel to test its meshing
        if (Time.time > _updateTime + UpdateFrequency)
        {
            _updateTime += UpdateFrequency;

            for (var i = 0; i < VoxelChangesPerUpdate; i++)
            {
                // Attempt to change the Chunk state, searching for a voxel which is different
                // Normally you would just do
                // SetVoxel(Random.Range(0, (int)ChunkWidth), Random.Range(0, (int)ChunkHeight), Random.Range(0, (int)ChunkDepth), (byte)Random.Range(0, 2));
                // But in this case I wanted to test how fast we can update the Mesh
                var attempts      = 0;
                var voxel         = (byte)Random.Range(0, 2);
                var x             = Random.Range(0, (int)ChunkWidth);
                var y             = Random.Range(0, (int)ChunkHeight);
                var z             = Random.Range(0, (int)ChunkDepth);
                var outOfAttempts = false;
                while (GetVoxel(x, y, z) == voxel)
                {
                    if (attempts > 20)
                    {
                        outOfAttempts = true;
                        break;
                    }
                    voxel = (byte)Random.Range(0, 2);
                    attempts++;
                }

                if (outOfAttempts)
                {
                    continue;
                }
                // We found a voxel that differs from the one we are setting, so try setting it
                SetVoxel(x, y, z, voxel);
            }
        }

        if (_dirty)
        {
            _dirty = false;
            ThreadManager.Execute((container) =>
            {
                // Get the job Id for this job
                var job = GetNextJobId();

                // Arrays are reference types, so create a blank array to grab the values
                var voxels = new byte[ChunkWidth][][];
                for (var x = 0; x < ChunkWidth; x++)
                {
                    voxels[x] = new byte[ChunkHeight][];
                    for (var y = 0; y < ChunkHeight; y++)
                    {
                        voxels[x][y] = new byte[ChunkDepth];
                    }
                }
                // Grab the current state
                lock (_voxelLocker)
                {
                    for (var x = 0; x < ChunkWidth; x++)
                    {
                        for (var y = 0; y < ChunkHeight; y++)
                        {
                            for (var z = 0; z < ChunkDepth; z++)
                            {
                                voxels[x][y][z] = _voxels[x][y][z];
                            }
                        }
                    }
                }

                // Grab the Lists from our Container or generate them
                if (!container.ContainerObjects.ContainsKey("VertexList"))
                {
                    container.ContainerObjects.Add("VertexList", new List <Vector3>());
                }
                if (!container.ContainerObjects.ContainsKey("UVList"))
                {
                    container.ContainerObjects.Add("UVList", new List <Vector2>());
                }
                if (!container.ContainerObjects.ContainsKey("NormalList"))
                {
                    container.ContainerObjects.Add("NormalList", new List <Vector3>());
                }
                if (!container.ContainerObjects.ContainsKey("IndexList"))
                {
                    container.ContainerObjects.Add("IndexList", new List <int>());
                }
                var vertexList = (List <Vector3>)container.ContainerObjects["VertexList"];
                var uvList     = (List <Vector2>)container.ContainerObjects["UVList"];
                var normalList = (List <Vector3>)container.ContainerObjects["NormalList"];
                var indexList  = (List <int>)container.ContainerObjects["IndexList"];
                vertexList.Clear();
                uvList.Clear();
                normalList.Clear();
                indexList.Clear();

                // Generate mesh data
                for (var x = 0; x < ChunkWidth; x++)
                {
                    for (var y = 0; y < ChunkHeight; y++)
                    {
                        for (var z = 0; z < ChunkDepth; z++)
                        {
                            if (voxels[x][y][z] == 0)
                            {
                                continue;
                            }
                            CubeData.AddCube(ref vertexList, ref uvList, ref normalList, ref indexList, new Vector3(x, y, z), new byte[]
                            {
                                _getVoxel(voxels, x, y, z - 1),
                                _getVoxel(voxels, x - 1, y, z),
                                _getVoxel(voxels, x, y - 1, z),
                                _getVoxel(voxels, x, y, z + 1),
                                _getVoxel(voxels, x + 1, y, z),
                                _getVoxel(voxels, x, y + 1, z),
                            }, false);
                        }
                    }
                }

                // Convert these lists to arrays for the mesh
                var vertices = vertexList.ToArray();
                var uvs      = uvList.ToArray();
                var normals  = normalList.ToArray();
                var indices  = indexList.ToArray();

                ThreadManager.ExecuteOnMainThread(() =>
                {
                    if (GetLastJobId() > job) // Stale Mesh
                    {
                        return;
                    }
                    SetLastJobId(job);
                    SetMesh(vertices, uvs, normals, indices);
                });
            });
        }
        //UpdateDebug();
    }