/// <summary>
        /// Updates the internal quadtree to make it identical to the given terrain
        /// quadtree.Collects the tasks necessary to create the missing texture
        /// tiles, corresponding to newly created quads.
        /// </summary>
        protected virtual void GetTiles(QuadTree parent, ref QuadTree tree, TerrainQuad quad)
        {
            //if tree not created, create a new tree and check if its tile is needed
            if (tree == null)
            {
                tree          = new QuadTree(parent);
                tree.NeedTile = NeedTile(quad);
            }

            //If this trees tile is needed get a tile and add its task to the schedular if the task is not already done
            if (tree.NeedTile && tree.Tile == null)
            {
                tree.Tile = Producer.GetTile(quad.Level, quad.Tx, quad.Ty);

                if (!tree.Tile.IsDone)
                {
                    tree.Tile.CreateTile();
                }
            }

            if (!quad.IsLeaf && Producer.HasChildren(quad.Level, quad.Tx, quad.Ty))
            {
                for (int i = 0; i < 4; ++i)
                {
                    GetTiles(tree, ref tree.Children[i], quad.GetChild(i));
                }
            }
        }
Beispiel #2
0
        protected override void Start()
        {
            base.Start();

            SplitDist             = 1.1f;
            HorizonCulling        = true;
            DeformedFrustumPlanes = new Vector4d[6];

            World.SkyNode.InitUniforms(m_terrainMaterial);

            FaceToLocal  = CalculateFaceToLocal(m_face);
            LocalToWorld = /*Matrix4x4d.ToMatrix4x4d(transform.localToWorldMatrix) * */ FaceToLocal;

            float size = m_size;

            if (World.IsDeformed)
            {
                size   = World.Radius;
                Deform = new SphericalDeformation(size);
            }
            else
            {
                Deform = new Deformation();
            }

            Root = new TerrainQuad(this, null, 0, 0, -size, -size, 2.0 * size, m_zmin, m_zmax);
        }
        /// <summary>
        /// Sets the shader uniforms that are necessary to project on screen the
        /// given TerrainQuad. This method can set the uniforms that are specific to
        /// the given quad.
        /// </summary>
        public virtual void SetUniforms(TerrainNode node, TerrainQuad quad, MaterialPropertyBlock matPropertyBlock)
        {
            if (matPropertyBlock == null || node == null || quad == null)
            {
                return;
            }

            double ox         = quad.Ox;
            double oy         = quad.Oy;
            double l          = quad.Length;
            double distFactor = node.DistFactor;
            int    level      = quad.Level;

            matPropertyBlock.SetVector(m_uniforms.offset, new Vector4((float)ox, (float)oy, (float)l, (float)level));

            Vector3d camera = node.LocalCameraPos;

            matPropertyBlock.SetVector(m_uniforms.camera, new Vector4((float)((camera.x - ox) / l), (float)((camera.y - oy) / l),
                                                                      (float)((camera.z - node.View.GroundHeight) / (l * distFactor)),
                                                                      (float)camera.z));

            Vector3d c = node.LocalCameraPos;

            Matrix3x3d m = m_localToTangent * (new Matrix3x3d(l, 0.0, ox - c.x, 0.0, l, oy - c.y, 0.0, 0.0, 1.0));

            matPropertyBlock.SetMatrix(m_uniforms.tileToTangent, MathConverter.ToMatrix4x4(m));

            SetScreenUniforms(node, quad, matPropertyBlock);
        }
        /// <summary>
        /// Updates the internal quadtree to make it identical to the given terrain
        /// quadtree.This method releases the texture tiles corresponding to
        /// deleted quads.
        /// </summary>
        protected virtual void PutTiles(QuadTree tree, TerrainQuad quad)
        {
            if (tree == null)
            {
                return;
            }

            //Check if this tile is needed, if not put tile.
            tree.NeedTile = NeedTile(quad);

            if (!tree.NeedTile && tree.Tile != null)
            {
                Producer.PutTile(tree.Tile);
                tree.Tile = null;
            }

            //If this qiad is a leaf then all children of the tree are not needed
            if (quad.IsLeaf)
            {
                if (!tree.IsLeaf)
                {
                    tree.RecursiveDeleteChildren(this);
                }
            }
            else if (Producer.HasChildren(quad.Level, quad.Tx, quad.Ty))
            {
                for (int i = 0; i < 4; ++i)
                {
                    PutTiles(tree.Children[i], quad.GetChild(i));
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        protected virtual void SetScreenUniforms(TerrainNode node, TerrainQuad quad, MaterialPropertyBlock matPropertyBlock)
        {
            double ox = quad.Ox;
            double oy = quad.Oy;
            double l  = quad.Length;

            Vector3d p0 = new Vector3d(ox, oy, 0.0);
            Vector3d p1 = new Vector3d(ox + l, oy, 0.0);
            Vector3d p2 = new Vector3d(ox, oy + l, 0.0);
            Vector3d p3 = new Vector3d(ox + l, oy + l, 0.0);

            Matrix4x4d corners = new Matrix4x4d(p0.x, p1.x, p2.x, p3.x,
                                                p0.y, p1.y, p2.y, p3.y,
                                                p0.z, p1.z, p2.z, p3.z,
                                                1.0, 1.0, 1.0, 1.0);

            matPropertyBlock.SetMatrix(m_uniforms.screenQuadCorners, MathConverter.ToMatrix4x4(m_localToScreen * corners));

            Matrix4x4d verticals = new Matrix4x4d(0.0, 0.0, 0.0, 0.0,
                                                  0.0, 0.0, 0.0, 0.0,
                                                  1.0, 1.0, 1.0, 1.0,
                                                  0.0, 0.0, 0.0, 0.0);

            matPropertyBlock.SetMatrix(m_uniforms.screenQuadVerticals, MathConverter.ToMatrix4x4(m_localToScreen * verticals));
        }
Beispiel #6
0
        /// <summary>
        /// Creates the four subquads of this quad.
        /// </summary>
        private void Subdivide()
        {
            float hl = (float)Length / 2.0f;

            m_children[0] = new TerrainQuad(Owner, this, 2 * Tx, 2 * Ty, Ox, Oy, hl, ZMin, ZMax);
            m_children[1] = new TerrainQuad(Owner, this, 2 * Tx + 1, 2 * Ty, Ox + hl, Oy, hl, ZMin, ZMax);
            m_children[2] = new TerrainQuad(Owner, this, 2 * Tx, 2 * Ty + 1, Ox, Oy + hl, hl, ZMin, ZMax);
            m_children[3] = new TerrainQuad(Owner, this, 2 * Tx + 1, 2 * Ty + 1, Ox + hl, Oy + hl, hl, ZMin, ZMax);
        }
Beispiel #7
0
        /// <summary>
        /// Find all the quads in a terrain that need to be drawn. If a quad is a leaf and is visible it should
        /// be drawn. If that quads tile is not ready the first ready parent is drawn
        /// NOTE - because of the current set up all task are run on the frame they are generated so
        /// the leaf quads will always have tiles that are ready to be drawn
        /// </summary>
        private void FindDrawableQuads(TerrainQuad quad, List <TileSampler> samplers)
        {
            quad.Drawable = false;

            if (!quad.IsVisible)
            {
                quad.Drawable = true;
                return;
            }

            if (quad.IsLeaf)
            {
                for (int i = 0; i < samplers.Count; ++i)
                {
                    TileProducer p  = samplers[i].Producer;
                    int          l  = quad.Level;
                    int          tx = quad.Tx;
                    int          ty = quad.Ty;

                    if (p.HasTile(l, tx, ty) && p.FindTile(l, tx, ty, false, true) == null)
                    {
                        return;
                    }
                }
            }
            else
            {
                int nDrawable = 0;
                for (int i = 0; i < 4; ++i)
                {
                    FindDrawableQuads(quad.GetChild(i), samplers);
                    if (quad.GetChild(i).Drawable)
                    {
                        ++nDrawable;
                    }
                }

                if (nDrawable < 4)
                {
                    for (int i = 0; i < samplers.Count; ++i)
                    {
                        TileProducer p  = samplers[i].Producer;
                        int          l  = quad.Level;
                        int          tx = quad.Tx;
                        int          ty = quad.Ty;

                        if (p.HasTile(l, tx, ty) && p.FindTile(l, tx, ty, false, true) == null)
                        {
                            return;
                        }
                    }
                }
            }

            quad.Drawable = true;
        }
Beispiel #8
0
        protected override void SetScreenUniforms(TerrainNode node, TerrainQuad quad, MaterialPropertyBlock matPropertyBlock)
        {
            double ox = quad.Ox;
            double oy = quad.Oy;
            double l  = quad.Length;

            Vector3d p0 = new Vector3d(ox, oy, R);
            Vector3d p1 = new Vector3d(ox + l, oy, R);
            Vector3d p2 = new Vector3d(ox, oy + l, R);
            Vector3d p3 = new Vector3d(ox + l, oy + l, R);
            Vector3d pc = (p0 + p3) * 0.5;

            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;

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

            matPropertyBlock.SetMatrix(m_uniforms.screenQuadCorners, MathConverter.ToMatrix4x4(m_localToScreen * deformedCorners));

            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);

            matPropertyBlock.SetMatrix(m_uniforms.screenQuadVerticals, MathConverter.ToMatrix4x4(m_localToScreen * deformedVerticals));
            matPropertyBlock.SetVector(m_uniforms.screenQuadCornerNorms, new Vector4((float)l0, (float)l1, (float)l2, (float)l3));

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

            Matrix4x4d ltow = node.LocalToWorld;

            Matrix3x3d tangentFrameToWorld = new Matrix3x3d(ltow[0, 0], ltow[0, 1], ltow[0, 2],
                                                            ltow[1, 0], ltow[1, 1], ltow[1, 2],
                                                            ltow[2, 0], ltow[2, 1], ltow[2, 2]);

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

            matPropertyBlock.SetMatrix(m_uniforms.tangentFrameToWorld, MathConverter.ToMatrix4x4(tangentFrameToWorld * m));
        }
Beispiel #9
0
 /// <summary>
 /// Creates a new TerrainQuad.
 /// </summary>
 /// <param name="owner">the TerrainNode to which the terrain quadtree belongs</param>
 /// <param name="parent">the parent quad of this quad</param>
 /// <param name="tx">the logical x coordinate of this quad</param>
 /// <param name="ty">the logical y coordinate of this quad</param>
 /// <param name="ox">the physical x coordinate of the lower left corner of this quad</param>
 /// <param name="oy">the physical y coordinate of the lower left corner of this quad</param>
 /// <param name="length">the physical size of this quad</param>
 /// <param name="zmin">the minimum terrain elevation inside this quad</param>
 /// <param name="zmax">the maximum terrain elevation inside this quad</param>
 public TerrainQuad(TerrainNode owner, TerrainQuad parent, int tx, int ty, double ox, double oy, double length, float zmin, float zmax)
 {
     Owner    = owner;
     m_parent = parent;
     Level    = (m_parent == null) ? 0 : m_parent.Level + 1;
     Tx       = tx;
     Ty       = ty;
     Ox       = ox;
     Oy       = oy;
     ZMax     = zmax;
     ZMin     = zmin;
     Length   = length;
     LocalBox = new Box3d(Ox, Ox + Length, Oy, Oy + Length, ZMin, ZMax);
 }
        /// <summary>
        /// Returns true if a tile is needed for the given terrain quad.
        /// </summary>
        protected virtual bool NeedTile(TerrainQuad quad)
        {
            bool needTile = m_storeLeaf;

            //if the quad is not a leaf and producer has children
            //and if have been asked not to store parent then dont need tile
            if (!m_storeParent && !quad.IsLeaf && Producer.HasChildren(quad.Level, quad.Tx, quad.Ty))
            {
                needTile = false;
            }

            //if this quad is not visilbe and have not been asked to store invisilbe quads dont need tile
            if (!quad.IsVisible)
            {
                needTile = false;
            }

            return(needTile);
        }
Beispiel #11
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="quad"></param>
 /// <param name="matPropertyBlock"></param>
 public void SetPerQuadUniforms(TerrainQuad quad, MaterialPropertyBlock matPropertyBlock)
 {
     Deform.SetUniforms(this, quad, matPropertyBlock);
 }
Beispiel #12
0
        private void DrawQuad(TerrainNode node, TerrainQuad quad, List <TileSampler> samplers)
        {
            if (!quad.IsVisible)
            {
                return;
            }

            if (!quad.Drawable)
            {
                return;
            }

            if (quad.IsLeaf)
            {
                m_propertyBlock.Clear();

                //Set the unifroms needed to draw the texture for this sampler
                for (int i = 0; i < samplers.Count; ++i)
                {
                    samplers[i].SetTile(m_propertyBlock, quad.Level, quad.Tx, quad.Ty);
                }

                //Set the uniforms unique to each quad
                node.SetPerQuadUniforms(quad, m_propertyBlock);

                //Draw the mesh
                Graphics.DrawMesh(m_quadMesh, Matrix4x4.identity, node.Material, 0, Camera.main, 0, m_propertyBlock);
            }
            else
            {
                //draw quads in a order based on distance to camera
                int[]  order = new int[4];
                double ox    = node.LocalCameraPos.x;
                double oy    = node.LocalCameraPos.y;

                double cx = quad.Ox + quad.Length / 2.0;
                double cy = quad.Oy + quad.Length / 2.0;

                if (oy < cy)
                {
                    if (ox < cx)
                    {
                        order[0] = 0;
                        order[1] = 1;
                        order[2] = 2;
                        order[3] = 3;
                    }
                    else
                    {
                        order[0] = 1;
                        order[1] = 0;
                        order[2] = 3;
                        order[3] = 2;
                    }
                }
                else
                {
                    if (ox < cx)
                    {
                        order[0] = 2;
                        order[1] = 0;
                        order[2] = 3;
                        order[3] = 1;
                    }
                    else
                    {
                        order[0] = 3;
                        order[1] = 1;
                        order[2] = 2;
                        order[3] = 0;
                    }
                }

                int done = 0;
                for (int i = 0; i < 4; ++i)
                {
                    if (quad.GetChild(order[i]).Visible == FRUSTUM_VISIBILTY.INVISIBLE)
                    {
                        done |= (1 << order[i]);
                    }
                    else if (quad.GetChild(order[i]).Drawable)
                    {
                        DrawQuad(node, quad.GetChild(order[i]), samplers);
                        done |= (1 << order[i]);
                    }
                }

                if (done < 15)
                {
                    //If a leaf quad needs to be drawn but its tiles are not ready then this
                    //will draw the next parent tile instead that is ready.
                    //Because of the current set up all tiles always have there tasks run on the frame they are generated
                    //so this section of code is never reached

                    m_propertyBlock.Clear();

                    //Set the unifroms needed to draw the texture for this sampler
                    for (int i = 0; i < samplers.Count; ++i)
                    {
                        samplers[i].SetTile(m_propertyBlock, quad.Level, quad.Tx, quad.Ty);
                    }

                    //Set the uniforms unique to each quad
                    node.SetPerQuadUniforms(quad, m_propertyBlock);

                    //Draw the mesh.
                    Graphics.DrawMesh(m_quadMesh, Matrix4x4.identity, node.Material, 0, Camera.main, 0, m_propertyBlock);
                }
            }
        }