/* * 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. */ public virtual void SetUniforms(TerrainNode node, Material mat) { if (mat == null || node == null) { return; } float d1 = node.GetSplitDist() + 1.0f; float d2 = 2.0f * node.GetSplitDist(); mat.SetVector(m_uniforms.blending, new Vector2(d1, d2 - d1)); m_localToCamera = node.GetView().GetWorldToCamera() * node.GetLocalToWorld(); m_localToScreen = node.GetView().GetCameraToScreen() * m_localToCamera; Vector3d2 localCameraPos = node.GetLocalCameraPos(); Vector3d2 worldCamera = node.GetView().GetWorldCameraPos(); Matrix4x4d A = LocalToDeformedDifferential(localCameraPos); Matrix4x4d B = DeformedToTangentFrame(worldCamera); Matrix4x4d ltot = B * node.GetLocalToWorld() * A; m_localToTangent = new Matrix3x3d(ltot.m[0, 0], ltot.m[0, 1], ltot.m[0, 3], ltot.m[1, 0], ltot.m[1, 1], ltot.m[1, 3], ltot.m[3, 0], ltot.m[3, 1], ltot.m[3, 3]); mat.SetMatrix(m_uniforms.localToScreen, m_localToScreen.ToMatrix4x4()); mat.SetMatrix(m_uniforms.localToWorld, node.GetLocalToWorld().ToMatrix4x4()); }
/** * 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. */ public virtual void SetUniforms(TerrainNode node, TerrainQuad quad, MaterialPropertyBlock matPropertyBlock) { if(matPropertyBlock == null || node == null || quad == null) return; double ox = quad.GetOX(); double oy = quad.GetOY(); double l = quad.GetLength(); double distFactor = (double)node.GetDistFactor(); int level = quad.GetLevel(); matPropertyBlock.AddVector(m_uniforms.offset, new Vector4((float)ox, (float)oy, (float)l, (float)level)); Vector3d2 camera = node.GetLocalCameraPos(); matPropertyBlock.AddVector(m_uniforms.camera, new Vector4( (float)((camera.x - ox) / l), (float)((camera.y - oy) / l), (float)((camera.z - node.GetView().GetGroundHeight()) / (l * distFactor)), (float)camera.z)); Vector3d2 c = node.GetLocalCameraPos(); 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.AddMatrix(m_uniforms.tileToTangent, m.ToMatrix4x4()); SetScreenUniforms(node, quad, matPropertyBlock); }
/** * 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. */ public virtual void SetUniforms(TerrainNode node, Material mat) { if(mat == null || node == null) return; float d1 = node.GetSplitDist() + 1.0f; float d2 = 2.0f * node.GetSplitDist(); mat.SetVector(m_uniforms.blending, new Vector2(d1, d2 - d1)); m_localToCamera = node.GetView().GetWorldToCamera() * node.GetLocalToWorld(); m_localToScreen = node.GetView().GetCameraToScreen() * m_localToCamera; Vector3d2 localCameraPos = node.GetLocalCameraPos(); Vector3d2 worldCamera = node.GetView().GetWorldCameraPos(); Matrix4x4d A = LocalToDeformedDifferential(localCameraPos); Matrix4x4d B = DeformedToTangentFrame(worldCamera); Matrix4x4d ltot = B * node.GetLocalToWorld() * A; m_localToTangent = new Matrix3x3d( ltot.m[0,0], ltot.m[0,1], ltot.m[0,3], ltot.m[1,0], ltot.m[1,1], ltot.m[1,3], ltot.m[3,0], ltot.m[3,1], ltot.m[3,3]); mat.SetMatrix(m_uniforms.localToScreen, m_localToScreen.ToMatrix4x4()); mat.SetMatrix(m_uniforms.localToWorld, node.GetLocalToWorld().ToMatrix4x4()); }
/* * 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. */ public virtual void SetUniforms(TerrainNode node, TerrainQuad quad, MaterialPropertyBlock matPropertyBlock) { if (matPropertyBlock == null || node == null || quad == null) { return; } double ox = quad.GetOX(); double oy = quad.GetOY(); double l = quad.GetLength(); double distFactor = (double)node.GetDistFactor(); int level = quad.GetLevel(); matPropertyBlock.AddVector(m_uniforms.offset, new Vector4((float)ox, (float)oy, (float)l, (float)level)); Vector3d2 camera = node.GetLocalCameraPos(); matPropertyBlock.AddVector(m_uniforms.camera, new Vector4((float)((camera.x - ox) / l), (float)((camera.y - oy) / l), (float)((camera.z - node.GetView().GetGroundHeight()) / (l * distFactor)), (float)camera.z)); Vector3d2 c = node.GetLocalCameraPos(); 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.AddMatrix(m_uniforms.tileToTangent, m.ToMatrix4x4()); SetScreenUniforms(node, quad, matPropertyBlock); }
/* * Subdivides or unsubdivides this quad based on the current * viewer distance to this quad, relatively to its size. This * method uses the current viewer position provided by the * TerrainNode to which this quadtree belongs. */ public void Update() { Frustum.VISIBILTY v = (m_parent == null) ? Frustum.VISIBILTY.PARTIALLY : m_parent.GetVisible(); if (v == Frustum.VISIBILTY.PARTIALLY) { m_visible = m_owner.GetVisibility(m_localBox); } else { m_visible = v; } // here we reuse the occlusion test from the previous frame: // if the quad was found unoccluded in the previous frame, we suppose it is // still unoccluded at this frame. If it was found occluded, we perform // an occlusion test to check if it is still occluded. if (m_visible != Frustum.VISIBILTY.INVISIBLE && m_occluded) { m_occluded = m_owner.IsOccluded(m_localBox); if (m_occluded) { m_visible = Frustum.VISIBILTY.INVISIBLE; } } double ground = m_owner.GetView().GetGroundHeight(); double dist = m_owner.GetCameraDist(new Box3d(m_ox, m_ox + m_length, m_oy, m_oy + m_length, Math.Min(0.0, ground), Math.Max(0.0, ground))); if ((m_owner.GetSplitInvisibleQuads() || m_visible != Frustum.VISIBILTY.INVISIBLE) && dist < m_length * m_owner.GetSplitDist() && m_level < m_owner.GetMaxLevel()) { if (IsLeaf()) { Subdivide(); } int[] order = new int[4]; double ox = m_owner.GetLocalCameraPos().x; double oy = m_owner.GetLocalCameraPos().y; double cx = m_ox + m_length / 2.0; double cy = m_oy + m_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; } } m_children[order[0]].Update(); m_children[order[1]].Update(); m_children[order[2]].Update(); m_children[order[3]].Update(); // we compute a more precise occlusion for the next frame (see above), // by combining the occlusion status of the child nodes m_occluded = (m_children[0].GetOccluded() && m_children[1].GetOccluded() && m_children[2].GetOccluded() && m_children[3].GetOccluded()); } else { if (m_visible != Frustum.VISIBILTY.INVISIBLE) { // we add the bounding box of this quad to the occluders list m_occluded = m_owner.AddOccluder(m_localBox); if (m_occluded) { m_visible = Frustum.VISIBILTY.INVISIBLE; } } if (!IsLeaf()) { Release(); } } }