/// <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); }
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); }
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); }
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."); } }
/// <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)); }
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); } } }
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); }