/// <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));
        }
        /// <summary>
        /// Sets the shader uniforms that are necessary to project on screen the
        /// TerrainQuad of the given TerrainNode. This method can set the uniforms
        /// that are common to all the quads of the given terrain.
        /// </summary>
        public virtual void SetUniforms(TerrainNode node, Material mat)
        {
            if (mat == null || node == null)
            {
                return;
            }

            float d1 = node.SplitDist + 1.0f;
            float d2 = 2.0f * node.SplitDist;

            mat.SetVector(m_uniforms.blending, new Vector2(d1, d2 - d1));

            m_localToCamera = node.View.WorldToCamera * node.LocalToWorld;
            m_localToScreen = node.View.CameraToScreen * m_localToCamera;

            Vector3d localCameraPos = node.LocalCameraPos;
            Vector3d worldCamera    = node.View.WorldCameraPos;

            Matrix4x4d A = LocalToDeformedDifferential(localCameraPos);
            Matrix4x4d B = DeformedToTangentFrame(worldCamera);

            Matrix4x4d ltot = B * node.LocalToWorld * A;

            m_localToTangent = new Matrix3x3d(ltot[0, 0], ltot[0, 1], ltot[0, 3],
                                              ltot[1, 0], ltot[1, 1], ltot[1, 3],
                                              ltot[3, 0], ltot[3, 1], ltot[3, 3]);

            mat.SetMatrix(m_uniforms.localToScreen, MathConverter.ToMatrix4x4(m_localToScreen));
            mat.SetMatrix(m_uniforms.localToWorld, MathConverter.ToMatrix4x4(node.LocalToWorld));
        }
        /// <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);
        }
Example #4
0
        private void DrawTerrain(TerrainNode node)
        {
            //Get all the samplers attached to the terrain node. The samples contain the data need to draw the quad
            TileSampler[]      allSamplers = node.transform.GetComponentsInChildren <TileSampler>();
            List <TileSampler> samplers    = new List <TileSampler>();

            //Only use sample if enabled
            foreach (TileSampler sampler in allSamplers)
            {
                if (sampler.enabled && sampler.StoreLeaf)
                {
                    samplers.Add(sampler);
                }
            }

            if (samplers.Count == 0)
            {
                return;
            }

            //Find all the quads in the terrain node that need to be drawn
            FindDrawableQuads(node.Root, samplers);
            //The draw them
            DrawQuad(node, node.Root, samplers);
        }
Example #5
0
        public override void SetUniforms(TerrainNode node, Material mat)
        {
            if (mat == null || node == null)
            {
                return;
            }

            base.SetUniforms(node, mat);

            mat.SetFloat(m_uniforms.radius, (float)R);
        }
Example #6
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));
        }
        protected override void Start()
        {
            base.Start();

            Producer   = GetComponent <TileProducer>();
            m_uniforms = new TileSamplerUniforms(Producer.Name);

            TerrainNode = FindTerrainNode(transform.parent);

            if (TerrainNode == null)
            {
                throw new InvalidOperationException("TileSampler component must be the child of a terrain node.");
            }
        }
Example #8
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>
        /// Finds the Terrain node component on parent of game object.
        /// </summary>
        private TerrainNode FindTerrainNode(Transform transform)
        {
            if (transform == null)
            {
                return(null);
            }

            TerrainNode node = transform.GetComponent <TerrainNode>();

            if (node == null)
            {
                return(FindTerrainNode(transform.parent));
            }
            else
            {
                return(node);
            }
        }
 /// <summary>
 /// Returns the visibility of a bounding box in local space, in a view
 /// frustum defined in deformed space.
 /// </summary>
 /// <param name="node">This is node is used to get the camera position
 /// in local and deformed space with TerrainNode::GetLocalCamera and
 /// TerrainNode::GetDeformedCamera, as well as the view frustum planes
 /// in deformed space with TerrainNode::GetDeformedFrustumPlanes. </param>
 /// <param name="localBox">a bounding box in local space.</param>
 /// <returns>the visibility of the bounding box in the view frustum.</returns>
 public virtual FRUSTUM_VISIBILTY GetVisibility(TerrainNode node, Box3d localBox)
 {
     // localBox = deformedBox, so we can compare the deformed frustum with it
     return(Frustum3d.GetVisibility(node.DeformedFrustumPlanes, localBox));
 }
Example #11
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);
                }
            }
        }
Example #12
0
        public override FRUSTUM_VISIBILTY GetVisibility(TerrainNode t, Box3d localBox)
        {
            Vector3d[] deformedBox = new Vector3d[4];
            deformedBox[0] = LocalToDeformed(new Vector3d(localBox.Min.x, localBox.Min.y, localBox.Min.z));
            deformedBox[1] = LocalToDeformed(new Vector3d(localBox.Max.x, localBox.Min.y, localBox.Min.z));
            deformedBox[2] = LocalToDeformed(new Vector3d(localBox.Max.x, localBox.Max.y, localBox.Min.z));
            deformedBox[3] = LocalToDeformed(new Vector3d(localBox.Min.x, localBox.Max.y, localBox.Min.z));

            double a  = (localBox.Max.z + R) / (localBox.Min.z + R);
            double dx = (localBox.Max.x - localBox.Min.x) / 2 * a;
            double dy = (localBox.Max.y - localBox.Min.y) / 2 * a;
            double dz = localBox.Max.z + R;
            double f  = Math.Sqrt(dx * dx + dy * dy + dz * dz) / (localBox.Min.z + R);

            Vector4d[] deformedFrustumPlanes = t.DeformedFrustumPlanes;

            FRUSTUM_VISIBILTY v0 = GetVisibility(deformedFrustumPlanes[0], deformedBox, f);

            if (v0 == FRUSTUM_VISIBILTY.INVISIBLE)
            {
                return(FRUSTUM_VISIBILTY.INVISIBLE);
            }

            FRUSTUM_VISIBILTY v1 = GetVisibility(deformedFrustumPlanes[1], deformedBox, f);

            if (v1 == FRUSTUM_VISIBILTY.INVISIBLE)
            {
                return(FRUSTUM_VISIBILTY.INVISIBLE);
            }

            FRUSTUM_VISIBILTY v2 = GetVisibility(deformedFrustumPlanes[2], deformedBox, f);

            if (v2 == FRUSTUM_VISIBILTY.INVISIBLE)
            {
                return(FRUSTUM_VISIBILTY.INVISIBLE);
            }

            FRUSTUM_VISIBILTY v3 = GetVisibility(deformedFrustumPlanes[3], deformedBox, f);

            if (v3 == FRUSTUM_VISIBILTY.INVISIBLE)
            {
                return(FRUSTUM_VISIBILTY.INVISIBLE);
            }

            FRUSTUM_VISIBILTY v4 = GetVisibility(deformedFrustumPlanes[4], deformedBox, f);

            if (v4 == FRUSTUM_VISIBILTY.INVISIBLE)
            {
                return(FRUSTUM_VISIBILTY.INVISIBLE);
            }

            Vector3d c        = t.DeformedCameraPos;
            double   lSq      = c.SqrMagnitude;
            double   rm       = R + Math.Min(0.0, localBox.Min.z);
            double   rM       = R + localBox.Max.z;
            double   rmSq     = rm * rm;
            double   rMSq     = rM * rM;
            Vector4d farPlane = new Vector4d(c.x, c.y, c.z, Math.Sqrt((lSq - rmSq) * (rMSq - rmSq)) - rmSq);

            FRUSTUM_VISIBILTY v5 = GetVisibility(farPlane, deformedBox, f);

            if (v5 == FRUSTUM_VISIBILTY.INVISIBLE)
            {
                return(FRUSTUM_VISIBILTY.INVISIBLE);
            }

            if (v0 == FRUSTUM_VISIBILTY.FULLY && v1 == FRUSTUM_VISIBILTY.FULLY &&
                v2 == FRUSTUM_VISIBILTY.FULLY && v3 == FRUSTUM_VISIBILTY.FULLY &&
                v4 == FRUSTUM_VISIBILTY.FULLY && v5 == FRUSTUM_VISIBILTY.FULLY)
            {
                return(FRUSTUM_VISIBILTY.FULLY);
            }

            return(FRUSTUM_VISIBILTY.PARTIALLY);
        }