示例#1
0
        protected override void OnDestroy()
        {
            base.OnDestroy();

            ElevationsBuffer.ReleaseAndDisposeBuffer();
            GroundBuffer.ReleaseAndDisposeBuffer();
        }
示例#2
0
        private void CreateWTable()
        {
            // Some values need for the InitWaveSpectrum function can be precomputed
            var uv = Vector2.zero;
            var st = Vector2.zero;

            float k1, k2, k3, k4, w1, w2, w3, w4;

            var table = new float[FourierGridSize * FourierGridSize * 4];

            for (int x = 0; x < FourierGridSize; x++)
            {
                for (int y = 0; y < FourierGridSize; y++)
                {
                    uv = new Vector2(x, y) / MapSize;

                    st.x = uv.x > 0.5f ? uv.x - 1.0f : uv.x;
                    st.y = uv.y > 0.5f ? uv.y - 1.0f : uv.y;

                    k1 = (st * InverseGridSizes.x).magnitude;
                    k2 = (st * InverseGridSizes.y).magnitude;
                    k3 = (st * InverseGridSizes.z).magnitude;
                    k4 = (st * InverseGridSizes.w).magnitude;

                    w1 = Mathf.Sqrt(9.81f * k1 * (1.0f + k1 * k1 / (WAVE_KM * WAVE_KM)));
                    w2 = Mathf.Sqrt(9.81f * k2 * (1.0f + k2 * k2 / (WAVE_KM * WAVE_KM)));
                    w3 = Mathf.Sqrt(9.81f * k3 * (1.0f + k3 * k3 / (WAVE_KM * WAVE_KM)));
                    w4 = Mathf.Sqrt(9.81f * k4 * (1.0f + k4 * k4 / (WAVE_KM * WAVE_KM)));

                    table[(x + y * FourierGridSize) * 4 + 0] = w1;
                    table[(x + y * FourierGridSize) * 4 + 1] = w2;
                    table[(x + y * FourierGridSize) * 4 + 2] = w3;
                    table[(x + y * FourierGridSize) * 4 + 3] = w4;
                }
            }

            // Write floating point data into render texture
            var buffer = new ComputeBuffer(FourierGridSize * FourierGridSize, sizeof(float) * 4);

            buffer.SetData(table);
            CBUtility.WriteIntoRenderTexture(WTable, CBUtility.Channels.RGBA, buffer, GodManager.Instance.WriteData);
            buffer.ReleaseAndDisposeBuffer();
        }
示例#3
0
        private void CalculateAO()
        {
            Debug.Log("Precomputing AO Started...");

            int GRIDRES_AO = 128;
            int N_AO       = 2;

            var options = new ParallelOptions {
                MaxDegreeOfParallelism = 4
            };

            float[] buf = new float[GRIDRES_AO * GRIDRES_AO * GRIDRES_AO * 4];

            for (int i = 0; i < GRIDRES_AO; ++i)
            {
                for (int j = 0; j < GRIDRES_AO; ++j)
                {
                    for (int k = 0; k < GRIDRES_AO; ++k)
                    {
                        int off = i + j * GRIDRES_AO + k * GRIDRES_AO * GRIDRES_AO;

                        buf[4 * off]     = 0;
                        buf[4 * off + 1] = 0;
                        buf[4 * off + 2] = 0;
                        buf[4 * off + 3] = 0;
                    }
                }
            }

            var indices  = PreProcessMesh.GetIndices(0);
            var vertices = PreProcessMesh.vertices;

            for (int ni = 0; ni < indices.Length; ni += 3)
            {
                int a = indices[ni];
                int b = indices[ni + 1];
                int c = indices[ni + 2];

                float x1 = vertices[a].x, y1 = vertices[a].y, z1 = vertices[a].z;
                float x2 = vertices[b].x, y2 = vertices[b].y, z2 = vertices[b].z;
                float x3 = vertices[c].x, y3 = vertices[c].y, z3 = vertices[c].z;

                x1 = (x1 + 1.0f) / 2.0f;
                x2 = (x2 + 1.0f) / 2.0f;
                x3 = (x3 + 1.0f) / 2.0f;
                y1 = (y1 + 1.0f) / 2.0f;
                y2 = (y2 + 1.0f) / 2.0f;
                y3 = (y3 + 1.0f) / 2.0f;
                z1 = (z1 + 1.0f) / 2.0f;
                z2 = (z2 + 1.0f) / 2.0f;
                z3 = (z3 + 1.0f) / 2.0f;

                double l12 = Mathf.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1));
                double l23 = Mathf.Sqrt((x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2) + (z3 - z2) * (z3 - z2));
                double l31 = Mathf.Sqrt((x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3) + (z1 - z3) * (z1 - z3));

                if (l12 > l23 && l12 > l31)
                {
                    Swap(ref a, ref c);
                    Swap(ref x1, ref x3); Swap(ref y1, ref y3); Swap(ref z1, ref z3);
                    Swap(ref l12, ref l23);
                }
                else if (l31 > l12 && l31 > l23)
                {
                    Swap(ref a, ref b);
                    Swap(ref x1, ref x2); Swap(ref y1, ref y2); Swap(ref z1, ref z2);
                    Swap(ref l31, ref l23);
                }

                int n12 = (int)(Math.Ceiling(l12 * GRIDRES_AO) * 2.0);
                int n13 = (int)(Math.Ceiling(l31 * GRIDRES_AO) * 2.0);

                Parallel.For(0, n12 - 1, i =>
                {
                    var u = (double)i / n12;

                    Parallel.For(0, n13 - 1, j =>
                    {
                        var v = (double)j / n13;

                        if (u + v < 1.0)
                        {
                            var x = x1 + u * (x2 - x1) + v * (x3 - x1);
                            var y = y1 + u * (y2 - y1) + v * (y3 - y1);
                            var z = z1 + u * (z2 - z1) + v * (z3 - z1);

                            int ix = (int)(x * GRIDRES_AO);
                            int iy = (int)(y * GRIDRES_AO);
                            int iz = (int)(z * GRIDRES_AO);

                            if (ix >= 0 && ix < GRIDRES_AO && iy >= 0 && iy < GRIDRES_AO && iz >= 0 && iz < GRIDRES_AO)
                            {
                                int off = 4 * (ix + iy * GRIDRES_AO + iz * GRIDRES_AO * GRIDRES_AO);

                                buf[off]     = 255;
                                buf[off + 1] = 255;
                                buf[off + 2] = 255;
                                buf[off + 3] = 255;
                            }
                        }
                    });
                });
            }

            Debug.Log("Precomputing AO Mesh Passed...");

            double[] vocc = new double[GRIDRES_AO * GRIDRES_AO * GRIDRES_AO];

            for (int i = 0; i < GRIDRES_AO * GRIDRES_AO * GRIDRES_AO; ++i)
            {
                vocc[i] = 1.0;
            }

            double zmax = Math.Abs(Z);
            double zmin = -Math.Abs(Z);

            Parallel.For(0, N_AO - 1, options, i =>
            {
                var theta  = (i + 0.5) / N_AO * Math.PI / 2.0;
                var dtheta = 1.0 / N_AO * Math.PI / 2.0;

                Parallel.For(0, (4 * N_AO) - 1, options, j =>
                {
                    var phi  = (j + 0.5) / (4 * N_AO) * 2.0 * Math.PI;
                    var dphi = 1.0 / (4 * N_AO) * 2.0 * Math.PI;
                    var docc = Math.Cos(theta) * Math.Sin(theta) * dtheta * dphi / Math.PI;

                    if ((i * 4 * N_AO + j) % 4 == 0)
                    {
                        Debug.Log(string.Format("Precomputing AO Step {0} of {1}", i * 4 * N_AO + j, 4 * N_AO * N_AO));
                    }

                    Vector3d uz = new Vector3d(Math.Cos(phi) * Math.Sin(theta), Math.Sin(phi) * Math.Sin(theta), Math.Cos(theta));
                    Vector3d ux = uz.z.EpsilonEquals(1.0, 0.0000001) ? new Vector3d(1.0, 0.0, 0.0) : new Vector3d(-uz.y, uz.x, 0.0).Normalized();
                    Vector3d uy = uz.Cross(ux);

                    Matrix3x3d toView = new Matrix3x3d(ux.x, ux.y, ux.z, uy.x, uy.y, uy.z, uz.x, uz.y, uz.z);
                    Matrix3x3d toVol  = new Matrix3x3d(ux.x, uy.x, uz.x, ux.y, uy.y, uz.y, ux.z, uy.z, uz.z);

                    Box3d b = new Box3d();
                    b       = b.Enlarge(toView * new Vector3d(-1.0, -1.0, zmin));
                    b       = b.Enlarge(toView * new Vector3d(+1.0, -1.0, zmin));
                    b       = b.Enlarge(toView * new Vector3d(-1.0, +1.0, zmin));
                    b       = b.Enlarge(toView * new Vector3d(+1.0, +1.0, zmin));
                    b       = b.Enlarge(toView * new Vector3d(-1.0, -1.0, zmax));
                    b       = b.Enlarge(toView * new Vector3d(+1.0, -1.0, zmax));
                    b       = b.Enlarge(toView * new Vector3d(-1.0, +1.0, zmax));
                    b       = b.Enlarge(toView * new Vector3d(+1.0, +1.0, zmax));

                    int nx = (int)((b.Max.x - b.Min.x) * GRIDRES_AO / 2);
                    int ny = (int)((b.Max.y - b.Min.y) * GRIDRES_AO / 2);
                    int nz = (int)((b.Max.z - b.Min.z) * GRIDRES_AO / 2);

                    int[] occ = new int[nx * ny * nz];
                    for (int v = 0; v < nx * ny * nz; ++v)
                    {
                        occ[v] = 0;
                    }

                    for (int iz = nz - 1; iz >= 0; --iz)
                    {
                        var z = b.Min.z + (iz + 0.5) / nz * (b.Max.z - b.Min.z);

                        for (int iy = 0; iy < ny; ++iy)
                        {
                            var y = b.Min.y + (iy + 0.5) / ny * (b.Max.y - b.Min.y);

                            for (int ix = 0; ix < nx; ++ix)
                            {
                                var x = b.Min.x + (ix + 0.5) / nx * (b.Max.x - b.Min.x);

                                Vector3d p = toVol * new Vector3d(x, y, z);

                                int val = 0;
                                int vx  = (int)((p.x + 1.0) / 2.0 * GRIDRES_AO);
                                int vy  = (int)((p.y + 1.0) / 2.0 * GRIDRES_AO);
                                int vz  = (int)((p.z + 1.0) / 2.0 * GRIDRES_AO);

                                if (vx >= 0 && vx < GRIDRES_AO && vy >= 0 && vy < GRIDRES_AO && vz >= 0 && vz < GRIDRES_AO)
                                {
                                    val = buf[4 * (vx + vy * GRIDRES_AO + vz * GRIDRES_AO * GRIDRES_AO) + 3].EpsilonEquals(255.0f) ? 1 : 0;
                                }

                                occ[ix + iy * nx + iz * nx * ny] = val;

                                if (iz != nz - 1)
                                {
                                    occ[ix + iy * nx + iz * nx * ny] += occ[ix + iy * nx + (iz + 1) * nx * ny];
                                }
                            }
                        }
                    }

                    Parallel.For(0, GRIDRES_AO - 1, options, ix =>
                    {
                        var x = -1.0 + (ix + 0.5) / GRIDRES_AO * 2.0;

                        Parallel.For(0, GRIDRES_AO - 1, options, iy =>
                        {
                            var y = -1.0 + (iy + 0.5) / GRIDRES_AO * 2.0;

                            Parallel.For(0, GRIDRES_AO - 1, options, iz =>
                            {
                                var z = -1.0 + (iz + 0.5) / GRIDRES_AO * 2.0;

                                Vector3d p = toView * new Vector3d(x, y, z);

                                int vx = (int)((p.x - b.Min.x) / (b.Max.x - b.Min.x) * nx);
                                int vy = (int)((p.y - b.Min.y) / (b.Max.y - b.Min.y) * ny);
                                int vz = (int)((p.z - b.Min.z) / (b.Max.z - b.Min.z) * nz);

                                if (vx >= 0 && vx < nx && vy >= 0 && vy < ny && vz >= 0 && vz < nz)
                                {
                                    int occN = occ[vx + vy * nx + vz * nx * ny];

                                    if (occN > 6)
                                    {
                                        vocc[ix + iy * GRIDRES_AO + iz * GRIDRES_AO * GRIDRES_AO] -= docc;
                                    }
                                }
                            });
                        });
                    });
                });
            });

            for (int i = 0; i < GRIDRES_AO; ++i)
            {
                for (int j = 0; j < GRIDRES_AO; ++j)
                {
                    for (int k = 0; k < GRIDRES_AO; ++k)
                    {
                        int off = i + j * GRIDRES_AO + k * GRIDRES_AO * GRIDRES_AO;

                        if (buf[4 * off + 3].EpsilonEquals(255.0f))
                        {
                            var v = Math.Max(vocc[off], 0.0f) * 255;

                            buf[4 * off]     = (float)v;
                            buf[4 * off + 1] = (float)v;
                            buf[4 * off + 2] = (float)v;
                        }
                    }
                }
            }

            GC.Collect();

            var cb = new ComputeBuffer(GRIDRES_AO * GRIDRES_AO * GRIDRES_AO, sizeof(float) * 4);

            PreProcessAORT = RTExtensions.CreateRTexture(GRIDRES_AO, 0, RenderTextureFormat.ARGBFloat, FilterMode.Bilinear, TextureWrapMode.Clamp, GRIDRES_AO);

            CBUtility.WriteIntoRenderTexture(PreProcessAORT, CBUtility.Channels.RGBA, cb, GodManager.Instance.WriteData);
            RTUtility.SaveAs8bit(GRIDRES_AO, GRIDRES_AO * GRIDRES_AO, CBUtility.Channels.RGBA, "TreeAO", DestinationFolder, buf, 0.00392156863f);

            cb.ReleaseAndDisposeBuffer();

            Debug.Log("Precomputing AO Completed!");
        }
示例#4
0
        /// <summary>
        /// This function creates the elevations data and is called by the <see cref="Tile.Tasks.CreateTileTask"/> when the task is run by the <see cref="Utilities.Schedular"/>.
        /// The functions needs the tiles parent data to have already been created. If it has not the program will abort.
        /// </summary>
        /// <param name="level"></param>
        /// <param name="tx"></param>
        /// <param name="ty"></param>
        /// <param name="slot"></param>
        public override void DoCreateTile(int level, int tx, int ty, List <TileStorage.Slot> slot)
        {
            var gpuSlot = slot[0] as GPUTileStorage.GPUSlot;

            if (gpuSlot == null)
            {
                throw new NullReferenceException("gpuSlot");
            }

            var tileWidth = gpuSlot.Owner.TileSize;
            var tileSize  = tileWidth - (1 + GetBorder() * 2);

            GPUTileStorage.GPUSlot parentGpuSlot = null;

            var upsample   = level > 0;
            var parentTile = FindTile(level - 1, tx / 2, ty / 2, false, true);

            // TODO : Make it classwide...
            var residualTileSize = GetTileSize(0);
            var residualTexture  = RTExtensions.CreateRTexture(residualTileSize, 0, RenderTextureFormat.RFloat, FilterMode.Point, TextureWrapMode.Clamp);
            var residualBuffer   = new ComputeBuffer(residualTileSize * residualTileSize, sizeof(float));

            if (ResidualProducer != null)
            {
                if (ResidualProducer.HasTile(level, tx, ty))
                {
                    if (ResidualProducer.IsGPUProducer)
                    {
                        GPUTileStorage.GPUSlot residualGpuSlot = null;

                        var residualTile = ResidualProducer.FindTile(level, tx, ty, false, true);

                        if (residualTile != null)
                        {
                            residualGpuSlot = residualTile.GetSlot(0) as GPUTileStorage.GPUSlot;
                        }
                        else
                        {
                            throw new MissingTileException("Find residual tile failed");
                        }

                        if (residualGpuSlot == null)
                        {
                            throw new MissingTileException("Find parent tile failed");
                        }

                        UpSampleMaterial.SetTexture("_ResidualSampler", residualGpuSlot.Texture);
                        UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.25f / (float)tileWidth, 0.25f / (float)tileWidth, 2.0f / (float)tileWidth, 1.0f));
                    }
                    else
                    {
                        CPUTileStorage.CPUSlot <float> residualCPUSlot = null;

                        var residualTile = ResidualProducer.FindTile(level, tx, ty, false, true);

                        if (residualTile != null)
                        {
                            residualCPUSlot = residualTile.GetSlot(0) as CPUTileStorage.CPUSlot <float>;
                        }
                        else
                        {
                            throw new MissingTileException("Find residual tile failed");
                        }

                        if (residualCPUSlot == null)
                        {
                            throw new MissingTileException("Find parent tile failed");
                        }

                        residualBuffer.SetData(residualCPUSlot.Data);

                        RTUtility.ClearColor(residualTexture);
                        CBUtility.WriteIntoRenderTexture(residualTexture, CBUtility.Channels.R, residualBuffer, GodManager.Instance.WriteData);
                        //RTUtility.SaveAs8bit(residualTileSize, residualTileSize, CBUtility.Channels.R, string.Format("Residual_{0}_{1}-{2}-{3}", TerrainNode.name, level, tx, ty), "/Resources/Preprocess/Textures/Debug/", residualCPUSlot.Data);

                        UpSampleMaterial.SetTexture("_ResidualSampler", residualTexture);
                        UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.25f / (float)tileWidth, 0.25f / (float)tileWidth, 2.0f / (float)tileWidth, 1.0f));
                    }
                }
                else
                {
                    UpSampleMaterial.SetTexture("_ResidualSampler", null);
                    UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f));
                }
            }
            else
            {
                UpSampleMaterial.SetTexture("_ResidualSampler", null);
                UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f));
            }

            if (upsample)
            {
                if (parentTile != null)
                {
                    parentGpuSlot = parentTile.GetSlot(0) as GPUTileStorage.GPUSlot;
                }
                else
                {
                    throw new MissingTileException(string.Format("Find parent tile failed! {0}:{1}-{2}", level - 1, tx / 2, ty / 2));
                }
            }

            if (parentGpuSlot == null && upsample)
            {
                throw new NullReferenceException("parentGpuSlot");
            }

            var rootQuadSize = TerrainNode.TerrainQuadRoot.Length;

            var tileWSD = Vector4.zero;

            tileWSD.x = (float)tileWidth;
            tileWSD.y = (float)rootQuadSize / (float)(1 << level) / (float)tileSize;
            tileWSD.z = (float)tileSize / (float)(TerrainNode.ParentBody.GridResolution - 1);
            tileWSD.w = 0.0f;

            var tileScreenSize = (0.5 + (float)GetBorder()) / (tileWSD.x - 1 - (float)GetBorder() * 2);
            var tileSD         = new Vector2d(tileScreenSize, 1.0 + tileScreenSize * 2.0);

            UpSampleMaterial.SetVector("_TileWSD", tileWSD);
            UpSampleMaterial.SetVector("_TileSD", tileSD.ToVector2());

            if (upsample)
            {
                var parentTexture = parentGpuSlot.Texture;

                var dx = (float)(tx % 2) * (float)(tileSize / 2.0f);
                var dy = (float)(ty % 2) * (float)(tileSize / 2.0f);

                var coarseLevelOSL = new Vector4(dx / (float)parentTexture.width, dy / (float)parentTexture.height, 1.0f / (float)parentTexture.width, 0.0f);

                UpSampleMaterial.SetTexture("_CoarseLevelSampler", parentTexture);
                UpSampleMaterial.SetVector("_CoarseLevelOSL", coarseLevelOSL);
            }
            else
            {
                UpSampleMaterial.SetTexture("_CoarseLevelSampler", null);
                UpSampleMaterial.SetVector("_CoarseLevelOSL", new Vector4(-1.0f, -1.0f, -1.0f, -1.0f));
            }

            var rs = level < NoiseAmplitudes.Length ? NoiseAmplitudes[level] : 0.0f;

            var offset = new Vector4d(((double)tx / (1 << level) - 0.5) * rootQuadSize,
                                      ((double)ty / (1 << level) - 0.5) * rootQuadSize,
                                      rootQuadSize / (1 << level),
                                      TerrainNode.ParentBody.Size);

            UpSampleMaterial.SetFloat("_Amplitude", rs / (TerrainNode.ParentBody.Amplitude / 10.0f));
            UpSampleMaterial.SetFloat("_Frequency", TerrainNode.ParentBody.Frequency * (1 << level));
            UpSampleMaterial.SetVector("_Offset", offset.ToVector4());
            UpSampleMaterial.SetMatrix("_LocalToWorld", TerrainNode.FaceToLocal.ToMatrix4x4());

            if (TerrainNode.ParentBody.TCCPS != null)
            {
                TerrainNode.ParentBody.TCCPS.SetUniforms(UpSampleMaterial);
            }

            Graphics.Blit(null, gpuSlot.Texture, UpSampleMaterial);

            residualTexture.ReleaseAndDestroy();
            residualBuffer.ReleaseAndDisposeBuffer();

            base.DoCreateTile(level, tx, ty, slot);
        }
        /// <summary>
        /// Creates a series of textures that contain random noise.
        /// These texture tile together using the Wang Tiling method.
        /// Used by the UpSample shader to create fractal noise for the terrain elevations.
        /// </summary>
        private void CreateDemNoise()
        {
            var tileWidth = Cache.GetStorage(0).TileSize;

            NoiseTextures = new RenderTexture[6];

            var layers = new int[] { 0, 1, 3, 5, 7, 15 };
            var rand   = 1234567;

            for (byte nl = 0; nl < 6; ++nl)
            {
                var noiseArray = new float[tileWidth * tileWidth];
                var l          = layers[nl];
                var buffer     = new ComputeBuffer(tileWidth * tileWidth, sizeof(float));

                for (int j = 0; j < tileWidth; ++j)
                {
                    for (int i = 0; i < tileWidth; ++i)
                    {
                        noiseArray[i + j * tileWidth] = Noise.Noise2D(i, j);
                    }
                }

                // Corners
                for (int j = 0; j < tileWidth; ++j)
                {
                    for (int i = 0; i < tileWidth; ++i)
                    {
                        noiseArray[i + j * tileWidth] = 0.0f;
                    }
                }

                // Bottom border
                Random.InitState((l & 1) == 0 ? 7654321 : 5647381);

                for (int h = 5; h <= tileWidth / 2; ++h)
                {
                    var N = RandomValue();

                    noiseArray[h + 2 * tileWidth] = N;
                    noiseArray[(tileWidth - 1 - h) + 2 * tileWidth] = N;
                }

                for (int v = 3; v < 5; ++v)
                {
                    for (int h = 5; h < tileWidth - 5; ++h)
                    {
                        var N = RandomValue();

                        noiseArray[h + v * tileWidth] = N;
                        noiseArray[(tileWidth - 1 - h) + (4 - v) * tileWidth] = N;
                    }
                }

                // Right border
                Random.InitState((l & 2) == 0 ? 7654321 : 5647381);

                for (int v = 5; v <= tileWidth / 2; ++v)
                {
                    var N = RandomValue();

                    noiseArray[(tileWidth - 3) + v * tileWidth] = N;
                    noiseArray[(tileWidth - 3) + (tileWidth - 1 - v) * tileWidth] = N;
                }

                for (int h = tileWidth - 4; h >= tileWidth - 5; --h)
                {
                    for (int v = 5; v < tileWidth - 5; ++v)
                    {
                        var N = RandomValue();

                        noiseArray[h + v * tileWidth] = N;
                        noiseArray[(2 * tileWidth - 6 - h) + (tileWidth - 1 - v) * tileWidth] = N;
                    }
                }

                // Top border
                Random.InitState((l & 4) == 0 ? 7654321 : 5647381);

                for (int h = 5; h <= tileWidth / 2; ++h)
                {
                    var N = RandomValue();

                    noiseArray[h + (tileWidth - 3) * tileWidth] = N;
                    noiseArray[(tileWidth - 1 - h) + (tileWidth - 3) * tileWidth] = N;
                }

                for (int v = tileWidth - 2; v < tileWidth; ++v)
                {
                    for (int h = 5; h < tileWidth - 5; ++h)
                    {
                        var N = RandomValue();

                        noiseArray[h + v * tileWidth] = N;
                        noiseArray[(tileWidth - 1 - h) + (2 * tileWidth - 6 - v) * tileWidth] = N;
                    }
                }

                // Left border
                Random.InitState((l & 8) == 0 ? 7654321 : 5647381);

                for (int v = 5; v <= tileWidth / 2; ++v)
                {
                    var N = RandomValue();

                    noiseArray[2 + v * tileWidth] = N;
                    noiseArray[2 + (tileWidth - 1 - v) * tileWidth] = N;
                }

                for (int h = 1; h >= 0; --h)
                {
                    for (int v = 5; v < tileWidth - 5; ++v)
                    {
                        var N = RandomValue();

                        noiseArray[h + v * tileWidth] = N;
                        noiseArray[(4 - h) + (tileWidth - 1 - v) * tileWidth] = N;
                    }
                }

                // Center
                Random.InitState(rand);

                for (int v = 5; v < tileWidth - 5; ++v)
                {
                    for (int h = 5; h < tileWidth - 5; ++h)
                    {
                        var N = RandomValue();
                        noiseArray[h + v * tileWidth] = N;
                    }
                }

                // Randomize for next texture
                rand = (rand * 1103515245 + 12345) & 0x7FFFFFFF;

                NoiseTextures[nl] = RTExtensions.CreateRTexture(new Vector2(tileWidth, tileWidth), 0, RenderTextureFormat.RHalf, FilterMode.Point, TextureWrapMode.Repeat);

                // Write data into render texture
                buffer.SetData(noiseArray);

                CBUtility.WriteIntoRenderTexture(NoiseTextures[nl], 1, buffer, GodManager.Instance.WriteData);

                buffer.ReleaseAndDisposeBuffer();
            }
        }