Beispiel #1
0
        protected override void Awake()
        {
            base.Awake();

            int tileSize = TileSize;
            int capacity = Capacity;

            for (int i = 0; i < capacity; i++)
            {
                RenderTexture texture = new RenderTexture(tileSize, tileSize, 0, m_internalFormat, m_readWrite);
                texture.filterMode        = m_filterMode;
                texture.wrapMode          = m_wrapMode;
                texture.useMipMap         = m_mipmaps;
                texture.enableRandomWrite = m_enableRandomWrite;

                GPUSlot slot = new GPUSlot(this, texture);

                AddSlot(i, slot);
            }
        }
        /// <summary>
        /// Sets the uniforms necessary to access the texture tile for the given quad.
        /// The samplers producer must be using a GPUTileStorage at the first slot
        /// for this function to work
        /// </summary>
        private void SetTile(ref RenderTexture tex, ref Vector3 coord, ref Vector3 size, int level, int tx, int ty)
        {
            if (!Producer.IsGPUProducer)
            {
                return;
            }

            Tile t = null;
            int  b = Producer.Border;
            int  s = Producer.Cache.GetStorage(0).TileSize;

            float dx  = 0;
            float dy  = 0;
            float dd  = 1;
            float ds0 = (s / 2) * 2.0f - 2.0f * b;
            float ds  = ds0;

            if (!Producer.HasTile(level, tx, ty))
            {
                throw new MissingTileException("Producer should have tile.");
            }

            QuadTree tt = m_root;
            QuadTree tc;
            int      tl = 0;

            while (tl != level && (tc = tt.Children[((tx >> (level - tl - 1)) & 1) | ((ty >> (level - tl - 1)) & 1) << 1]) != null)
            {
                tl += 1;
                tt  = tc;
            }

            t = tt.Tile;

            dx = dx * ((s / 2) * 2 - 2 * b) / dd;
            dy = dy * ((s / 2) * 2 - 2 * b) / dd;

            if (t == null)
            {
                throw new NullReferenceException("tile is null");
            }

            GPUSlot gpuSlot = t.GetSlot(0) as GPUSlot;

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

            float w = gpuSlot.Texture.width;
            float h = gpuSlot.Texture.height;

            Vector4 coords;

            if (s % 2 == 0)
            {
                coords = new Vector4((dx + b) / w, (dy + b) / h, 0.0f, ds / w);
            }
            else
            {
                coords = new Vector4((dx + b + 0.5f) / w, (dy + b + 0.5f) / h, 0.0f, ds / w);
            }

            tex   = gpuSlot.Texture;
            coord = new Vector3(coords.x, coords.y, coords.z);
            size  = new Vector3(coords.w, coords.w, (s / 2) * 2.0f - 2.0f * b);
        }
        public override void DoCreateTile(int level, int tx, int ty, List <Slot> slot)
        {
            GPUSlot gpuSlot = slot[0] as GPUSlot;

            Tile    elevationTile    = m_elevationProducer.FindTile(level, tx, ty, false, true);
            GPUSlot elevationGpuSlot = null;

            if (elevationTile != null)
            {
                elevationGpuSlot = elevationTile.GetSlot(0) as GPUSlot;
            }
            else
            {
                throw new MissingTileException("Find elevation tile failed");
            }

            int tileWidth = gpuSlot.Owner.TileSize;

            m_normalsMat.SetVector(m_uniforms.tileSD, new Vector2(tileWidth, (tileWidth - 1.0f) / (World.GridResolution - 1.0f)));

            RenderTexture elevationTex = elevationGpuSlot.Texture;

            m_normalsMat.SetTexture(m_uniforms.elevationSampler, elevationTex);

            Vector4 elevationOSL = new Vector4(0.25f / elevationTex.width, 0.25f / elevationTex.height, 1.0f / elevationTex.width, 0.0f);

            m_normalsMat.SetVector(m_uniforms.elevationOSL, elevationOSL);

            if (World.IsDeformed)
            {
                double D   = TerrainNode.Root.Length;
                double R   = D / 2.0;
                double len = 1 << level;

                double x0 = tx / len * D - R;
                double x1 = (tx + 1) / len * D - R;
                double y0 = ty / len * D - R;
                double y1 = (ty + 1) / len * D - R;

                Vector3d p0 = new Vector3d(x0, y0, R);
                Vector3d p1 = new Vector3d(x1, y0, R);
                Vector3d p2 = new Vector3d(x0, y1, R);
                Vector3d p3 = new Vector3d(x1, y1, R);
                Vector3d pc = new Vector3d((x0 + x1) * 0.5, (y0 + y1) * 0.5, R);

                double   l0 = p0.Magnitude;
                double   l1 = p1.Magnitude;
                double   l2 = p2.Magnitude;
                double   l3 = p3.Magnitude;
                Vector3d v0 = p0.Normalized;
                Vector3d v1 = p1.Normalized;
                Vector3d v2 = p2.Normalized;
                Vector3d v3 = p3.Normalized;

                Vector3d vc = (v0 + v1 + v2 + v3) * 0.25;

                Matrix4x4d deformedCorners = new Matrix4x4d(
                    v0.x * R - vc.x * R, v1.x * R - vc.x * R, v2.x * R - vc.x * R, v3.x * R - vc.x * R,
                    v0.y * R - vc.y * R, v1.y * R - vc.y * R, v2.y * R - vc.y * R, v3.y * R - vc.y * R,
                    v0.z * R - vc.z * R, v1.z * R - vc.z * R, v2.z * R - vc.z * R, v3.z * R - vc.z * R,
                    1.0, 1.0, 1.0, 1.0);

                Matrix4x4d deformedVerticals = new Matrix4x4d(
                    v0.x, v1.x, v2.x, v3.x,
                    v0.y, v1.y, v2.y, v3.y,
                    v0.z, v1.z, v2.z, v3.z,
                    0.0, 0.0, 0.0, 0.0);

                Vector3d uz = pc.Normalized;
                Vector3d ux = (new Vector3d(0, 1, 0)).Cross(uz).Normalized;
                Vector3d uy = uz.Cross(ux);

                Matrix4x4d worldToTangentFrame = new Matrix4x4d(
                    ux.x, ux.y, ux.z, 0.0,
                    uy.x, uy.y, uy.z, 0.0,
                    uz.x, uz.y, uz.z, 0.0,
                    0.0, 0.0, 0.0, 0.0);

                m_normalsMat.SetMatrix(m_uniforms.patchCorners, MathConverter.ToMatrix4x4(deformedCorners));
                m_normalsMat.SetMatrix(m_uniforms.patchVerticals, MathConverter.ToMatrix4x4(deformedVerticals));
                m_normalsMat.SetVector(m_uniforms.patchCornerNorms, new Vector4((float)l0, (float)l1, (float)l2, (float)l3));
                m_normalsMat.SetVector(m_uniforms.deform, new Vector4((float)x0, (float)y0, (float)(D / len), (float)R));
                m_normalsMat.SetMatrix(m_uniforms.worldToTangentFrame, MathConverter.ToMatrix4x4(worldToTangentFrame));
            }
            else
            {
                double D   = TerrainNode.Root.Length;
                double R   = D / 2.0;
                double len = 1 << level;

                double x0 = tx / len * D - R;
                double y0 = ty / len * D - R;

                m_normalsMat.SetMatrix(m_uniforms.worldToTangentFrame, Matrix4x4.identity);
                m_normalsMat.SetVector(m_uniforms.deform, new Vector4((float)x0, (float)y0, (float)(D / len), 0.0f));
            }

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

            base.DoCreateTile(level, tx, ty, slot);
        }
Beispiel #4
0
        public override void DoCreateTile(int level, int tx, int ty, List <Slot> slot)
        {
            GPUSlot gpuSlot = slot[0] as GPUSlot;

            int tileWidth = gpuSlot.Owner.TileSize;
            int tileSize  = tileWidth - 4;

            GPUSlot parentGpuSlot = null;
            Tile    parentTile    = null;

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

                if (parentTile != null)
                {
                    parentGpuSlot = parentTile.GetSlot(0) as GPUSlot;
                }
                else
                {
                    throw new MissingTileException("Find parent tile failed");
                }
            }

            m_upsampleMat.SetFloat(m_uniforms.tileWidth, tileWidth);

            if (level > 0)
            {
                RenderTexture tex = parentGpuSlot.Texture;

                m_upsampleMat.SetTexture(m_uniforms.coarseLevelSampler, tex);

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

                Vector4 coarseLevelOSL = new Vector4((dx + 0.5f) / tex.width, (dy + 0.5f) / tex.height, 1.0f / tex.width, 0.0f);

                m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, coarseLevelOSL);
            }
            else
            {
                m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, new Vector4(-1.0f, -1.0f, -1.0f, -1.0f));
            }

            if (m_orthoCPUProducer != null && m_orthoCPUProducer.HasTile(level, tx, ty))
            {
                Tile           orthoCPUTile = m_orthoCPUProducer.FindTile(level, tx, ty, false, true);
                CPUSlot <byte> orthoCPUSlot = null;

                if (orthoCPUTile != null)
                {
                    orthoCPUSlot = orthoCPUTile.GetSlot(0) as CPUSlot <byte>;
                }
                else
                {
                    throw new MissingTileException("Find orthoCPU tile failed");
                }

                int     c    = m_orthoCPUProducer.Channels;
                Color32 col  = new Color32();
                byte[]  data = orthoCPUSlot.Data;

                for (int x = 0; x < tileWidth; x++)
                {
                    for (int y = 0; y < tileWidth; y++)
                    {
                        col.r = data[(x + y * tileWidth) * c];

                        if (c > 1)
                        {
                            col.g = data[(x + y * tileWidth) * c + 1];
                        }
                        if (c > 2)
                        {
                            col.b = data[(x + y * tileWidth) * c + 2];
                        }
                        if (c > 3)
                        {
                            col.a = data[(x + y * tileWidth) * c + 3];
                        }

                        m_residueTex.SetPixel(x, y, col);
                    }
                }

                m_residueTex.Apply();

                m_upsampleMat.SetTexture(m_uniforms.residualSampler, m_residueTex);
                m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(0.5f / tileWidth, 0.5f / tileWidth, 1.0f / tileWidth, 0.0f));
            }
            else
            {
                m_upsampleMat.SetTexture(m_uniforms.residualSampler, null);
                m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(-1, -1, -1, -1));
            }

            float rs = level < m_noiseAmp.Length ? m_noiseAmp[level] : 0.0f;

            int noiseL = 0;
            int face   = TerrainNode.Face;

            if (rs != 0.0f)
            {
                if (face == 1)
                {
                    int offset  = 1 << level;
                    int bottomB = m_noise.Noise2D(tx + 0.5f, ty + offset) > 0.0f ? 1 : 0;
                    int rightB  = (tx == offset - 1 ? m_noise.Noise2D(ty + offset + 0.5f, offset) : m_noise.Noise2D(tx + 1.0f, ty + offset + 0.5f)) > 0.0f ? 2 : 0;
                    int topB    = (ty == offset - 1 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, offset) : m_noise.Noise2D(tx + 0.5f, ty + offset + 1.0f)) > 0.0f ? 4 : 0;
                    int leftB   = (tx == 0 ? m_noise.Noise2D((4.0f * offset - 1.0f - ty) + 0.5f, offset) : m_noise.Noise2D(tx, ty + offset + 0.5f)) > 0.0f ? 8 : 0;
                    noiseL = bottomB + rightB + topB + leftB;
                }
                else if (face == 6)
                {
                    int offset  = 1 << level;
                    int bottomB = (ty == 0 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, 0) : m_noise.Noise2D(tx + 0.5f, ty - offset)) > 0.0f ? 1 : 0;
                    int rightB  = (tx == offset - 1.0f ? m_noise.Noise2D((2.0f * offset - 1.0f - ty) + 0.5f, 0) : m_noise.Noise2D(tx + 1.0f, ty - offset + 0.5f)) > 0.0f ? 2 : 0;
                    int topB    = m_noise.Noise2D(tx + 0.5f, ty - offset + 1.0f) > 0.0f ? 4 : 0;
                    int leftB   = (tx == 0 ? m_noise.Noise2D(3.0f * offset + ty + 0.5f, 0) : m_noise.Noise2D(tx, ty - offset + 0.5f)) > 0.0f ? 8 : 0;
                    noiseL = bottomB + rightB + topB + leftB;
                }
                else
                {
                    int offset  = (1 << level) * (face - 2);
                    int bottomB = m_noise.Noise2D(tx + offset + 0.5f, ty) > 0.0f ? 1 : 0;
                    int rightB  = m_noise.Noise2D((tx + offset + 1) % (4 << level), ty + 0.5f) > 0.0f ? 2 : 0;
                    int topB    = m_noise.Noise2D(tx + offset + 0.5f, ty + 1.0f) > 0.0f ? 4 : 0;
                    int leftB   = m_noise.Noise2D(tx + offset, ty + 0.5f) > 0.0f ? 8 : 0;
                    noiseL = bottomB + rightB + topB + leftB;
                }
            }

            int[] noiseRs = new int[] { 0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 1, 3, 2, 2, 1, 0 };
            int   noiseR  = noiseRs[noiseL];

            int[] noiseLs = new int[] { 0, 1, 1, 2, 1, 3, 2, 4, 1, 2, 3, 4, 2, 4, 4, 5 };
            noiseL = noiseLs[noiseL];

            m_upsampleMat.SetTexture(m_uniforms.noiseSampler, m_noiseTextures[noiseL]);
            m_upsampleMat.SetVector(m_uniforms.noiseUVLH, new Vector4(noiseR, (noiseR + 1) % 4, 0.0f, m_hsv ? 1.0f : 0.0f));


            if (m_hsv)
            {
                Vector4 col = m_noiseColor * rs / 255.0f;
                col.w *= 2.0f;
                m_upsampleMat.SetVector(m_uniforms.noiseColor, col);
            }
            else
            {
                Vector4 col = m_noiseColor * rs * 2.0f / 255.0f;
                col.w *= 2.0f;
                m_upsampleMat.SetVector(m_uniforms.noiseColor, col);
            }

            m_upsampleMat.SetVector(m_uniforms.noiseRootColor, m_rootNoiseColor);

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

            base.DoCreateTile(level, tx, ty, slot);
        }
        /// <summary>
        /// This function creates the elevations data and is called by the CreateTileTask when the task is run by the schedular
        /// The functions needs the tiles parent data to have already been created. If it has not the program will abort.
        /// </summary>
        public override void DoCreateTile(int level, int tx, int ty, List <Slot> slot)
        {
            GPUSlot gpuSlot = slot[0] as GPUSlot;

            int tileWidth = gpuSlot.Owner.TileSize;
            int b         = Border * 2 + 1;
            int tileSize  = tileWidth - b;

            GPUSlot parentGpuSlot = null;
            Tile    parentTile    = null;

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

                if (parentTile != null)
                {
                    parentGpuSlot = parentTile.GetSlot(0) as GPUSlot;
                }
                else
                {
                    throw new MissingTileException("Find parent tile failed");
                }
            }

            float rootQuadSize = (float)TerrainNode.Root.Length;

            Vector4 tileWSD = new Vector4();

            tileWSD.x = tileWidth;
            tileWSD.y = rootQuadSize / (1 << level) / tileSize;
            tileWSD.z = (tileWidth - b) / (World.GridResolution - 1.0f);
            tileWSD.w = 0.0f;

            m_upsampleMat.SetVector(m_uniforms.tileWSD, tileWSD);

            if (level > 0)
            {
                RenderTexture tex = parentGpuSlot.Texture;

                m_upsampleMat.SetTexture(m_uniforms.coarseLevelSampler, tex);

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

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

                m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, coarseLevelOSL);
            }
            else
            {
                m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, new Vector4(-1.0f, -1.0f, -1.0f, -1.0f));
            }

            if (m_residualProducer != null && m_residualProducer.HasTile(level, tx, ty))
            {
                Tile            residualTile = m_residualProducer.FindTile(level, tx, ty, false, true);
                CPUSlot <float> residualSlot = null;

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

                //Must clear residual tex before use or terrain will have artifacts at the seams. Not sure why.
                RTUtility.ClearColor(m_residualTex, Color.clear);

                m_residualBuffer.SetData(residualSlot.Data);
                CBUtility.WriteIntoRenderTexture(m_residualTex, 1, m_residualBuffer, World.WriteData);

                m_upsampleMat.SetTexture(m_uniforms.residualSampler, m_residualTex);
                m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(0.25f / tileWidth, 0.25f / tileWidth, 2.0f / tileWidth, 1.0f));
            }
            else
            {
                m_upsampleMat.SetTexture(m_uniforms.residualSampler, null);
                m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(0.0f, 0.0f, 1.0f, 0.0f));
            }

            float rs = level < m_noiseAmp.Length ? m_noiseAmp[level] : 0.0f;

            int noiseL = 0;
            int face   = TerrainNode.Face;

            if (rs != 0.0f)
            {
                if (face == 1)
                {
                    int offset  = 1 << level;
                    int bottomB = m_noise.Noise2D(tx + 0.5f, ty + offset) > 0.0f ? 1 : 0;
                    int rightB  = (tx == offset - 1 ? m_noise.Noise2D(ty + offset + 0.5f, offset) : m_noise.Noise2D(tx + 1.0f, ty + offset + 0.5f)) > 0.0f ? 2 : 0;
                    int topB    = (ty == offset - 1 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, offset) : m_noise.Noise2D(tx + 0.5f, ty + offset + 1.0f)) > 0.0f ? 4 : 0;
                    int leftB   = (tx == 0 ? m_noise.Noise2D((4.0f * offset - 1.0f - ty) + 0.5f, offset) : m_noise.Noise2D(tx, ty + offset + 0.5f)) > 0.0f ? 8 : 0;
                    noiseL = bottomB + rightB + topB + leftB;
                }
                else if (face == 6)
                {
                    int offset  = 1 << level;
                    int bottomB = (ty == 0 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, 0) : m_noise.Noise2D(tx + 0.5f, ty - offset)) > 0.0f ? 1 : 0;
                    int rightB  = (tx == offset - 1.0f ? m_noise.Noise2D((2.0f * offset - 1.0f - ty) + 0.5f, 0) : m_noise.Noise2D(tx + 1.0f, ty - offset + 0.5f)) > 0.0f ? 2 : 0;
                    int topB    = m_noise.Noise2D(tx + 0.5f, ty - offset + 1.0f) > 0.0f ? 4 : 0;
                    int leftB   = (tx == 0 ? m_noise.Noise2D(3.0f * offset + ty + 0.5f, 0) : m_noise.Noise2D(tx, ty - offset + 0.5f)) > 0.0f ? 8 : 0;
                    noiseL = bottomB + rightB + topB + leftB;
                }
                else
                {
                    int offset  = (1 << level) * (face - 2);
                    int bottomB = m_noise.Noise2D(tx + offset + 0.5f, ty) > 0.0f ? 1 : 0;
                    int rightB  = m_noise.Noise2D((tx + offset + 1) % (4 << level), ty + 0.5f) > 0.0f ? 2 : 0;
                    int topB    = m_noise.Noise2D(tx + offset + 0.5f, ty + 1.0f) > 0.0f ? 4 : 0;
                    int leftB   = m_noise.Noise2D(tx + offset, ty + 0.5f) > 0.0f ? 8 : 0;
                    noiseL = bottomB + rightB + topB + leftB;
                }
            }

            int[] noiseRs = new int[] { 0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 1, 3, 2, 2, 1, 0 };
            int   noiseR  = noiseRs[noiseL];

            int[] noiseLs = new int[] { 0, 1, 1, 2, 1, 3, 2, 4, 1, 2, 3, 4, 2, 4, 4, 5 };
            noiseL = noiseLs[noiseL];

            m_upsampleMat.SetTexture(m_uniforms.noiseSampler, m_noiseTextures[noiseL]);
            m_upsampleMat.SetVector(m_uniforms.noiseUVLH, new Vector4(noiseR, (noiseR + 1) % 4, 0, rs));

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

            base.DoCreateTile(level, tx, ty, slot);
        }