/* * 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. */ 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 = m_producer.GetTile(quad.GetLevel(), quad.GetTX(), quad.GetTY()); if (!tree.tile.GetTask().IsDone()) { //if task not done schedule task m_manager.GetSchedular().Add(tree.tile.GetTask()); } } if (!quad.IsLeaf() && m_producer.HasChildren(quad.GetLevel(), quad.GetTX(), quad.GetTY())) { for (int i = 0; i < 4; ++i) { GetTiles(tree, ref tree.children[i], quad.GetChild(i)); } } }
protected virtual void SetScreenUniforms(TerrainNode node, TerrainQuad quad, MaterialPropertyBlock matPropertyBlock) { double ox = quad.GetOX(); double oy = quad.GetOY(); double l = quad.GetLength(); Vector3d2 p0 = new Vector3d2(ox, oy, 0.0); Vector3d2 p1 = new Vector3d2(ox + l, oy, 0.0); Vector3d2 p2 = new Vector3d2(ox, oy + l, 0.0); Vector3d2 p3 = new Vector3d2(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.AddMatrix(m_uniforms.screenQuadCorners, (m_localToScreen * corners).ToMatrix4x4()); 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.AddMatrix(m_uniforms.screenQuadVerticals, (m_localToScreen * verticals).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); }
void OnPostRender() { if (!on) { return; } for (int i = 0; i < terrainNode.Length; i++) { if (!terrainNode[i].activeInHierarchy) { continue; } if (node[i] == null) { continue; } TerrainQuad root = node[i].GetRoot(); if (root == null) { continue; } root.DrawQuadOutline(Camera.main.camera, lineMaterial, col[i % 6]); } }
/* * Updates the internal quadtree to make it identical to the given terrain * quadtree. This method releases the texture tiles corresponding to * deleted quads. */ 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) { m_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 (m_producer.HasChildren(quad.GetLevel(), quad.GetTX(), quad.GetTY())) { for (int i = 0; i < 4; ++i) { PutTiles(tree.children[i], quad.GetChild(i)); } } }
/* * Returns true if a tile is needed for the given terrain quad. */ 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() && m_producer.HasChildren(quad.GetLevel(), quad.GetTX(), quad.GetTY())) { needTile = false; } //Check if any of the filters have determined that this tile is not needed foreach (TileFilter filter in m_tileFilters) { if (filter.DiscardTile(quad)) { needTile = false; break; } } //if this quad is not visilbe and have not been asked to store invisilbe quads dont need tile if (!m_storeInvisible && !quad.IsVisible()) { needTile = false; } return(needTile); }
//Creates the four subquads of this quad. void Subdivide() { float hl = (float)m_length / 2.0f; m_children[0] = new TerrainQuad(m_owner, this, 2 * m_tx, 2 * m_ty, m_ox, m_oy, hl, m_zmin, m_zmax); m_children[1] = new TerrainQuad(m_owner, this, 2 * m_tx + 1, 2 * m_ty, m_ox + hl, m_oy, hl, m_zmin, m_zmax); m_children[2] = new TerrainQuad(m_owner, this, 2 * m_tx, 2 * m_ty + 1, m_ox, m_oy + hl, hl, m_zmin, m_zmax); m_children[3] = new TerrainQuad(m_owner, this, 2 * m_tx + 1, 2 * m_ty + 1, m_ox + hl, m_oy + hl, hl, m_zmin, m_zmax); }
/* * Creates a new TerrainQuad. * * param owner the TerrainNode to which the terrain quadtree belongs. * param parent the parent quad of this quad. * param tx the logical x coordinate of this quad. * param ty the logical y coordinate of this quad. * param ox the physical x coordinate of the lower left corner of this quad. * param oy the physical y coordinate of the lower left corner of this quad. * param l the physical size of this quad. * param zmin the minimum %terrain elevation inside this quad. * param zmax the maximum %terrain elevation inside this quad. */ public TerrainQuad(TerrainNode owner, TerrainQuad parent, int tx, int ty, double ox, double oy, double length, float zmin, float zmax) { m_owner = owner; m_parent = parent; m_level = (m_parent == null) ? 0 : m_parent.GetLevel() + 1; m_tx = tx; m_ty = ty; m_ox = ox; m_oy = oy; m_zmax = zmax; m_zmin = zmin; m_length = length; m_localBox = new Box3d(m_ox, m_ox + m_length, m_oy, m_oy + m_length, m_zmin, m_zmax); }
/* * Override the default TileSampler NeedTile to retrive the tile * that is below the camera as well as its default behaviour */ protected override bool NeedTile(TerrainQuad quad) { Vector3d2 c = quad.GetOwner().GetLocalCameraPos(); int l = quad.GetLevel(); double ox = quad.GetOX(); double oy = quad.GetOY(); if (c.x >= ox && c.x < ox + l && c.y >= oy && c.y < oy + l) { return(true); } return(base.NeedTile(quad)); }
protected override void SetScreenUniforms(TerrainNode node, TerrainQuad quad, MaterialPropertyBlock matPropertyBlock) { double ox = quad.GetOX(); double oy = quad.GetOY(); double l = quad.GetLength(); Vector3d2 p0 = new Vector3d2(ox, oy, R); Vector3d2 p1 = new Vector3d2(ox + l, oy, R); Vector3d2 p2 = new Vector3d2(ox, oy + l, R); Vector3d2 p3 = new Vector3d2(ox + l, oy + l, R); Vector3d2 pc = (p0 + p3) * 0.5; double l0 = 0.0, l1 = 0.0, l2 = 0.0, l3 = 0.0; Vector3d2 v0 = p0.Normalized(ref l0); Vector3d2 v1 = p1.Normalized(ref l1); Vector3d2 v2 = p2.Normalized(ref l2); Vector3d2 v3 = p3.Normalized(ref l3); 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.AddMatrix(m_uniforms.screenQuadCorners, (m_localToScreen * deformedCorners).ToMatrix4x4()); 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.AddMatrix(m_uniforms.screenQuadVerticals, (m_localToScreen * deformedVerticals).ToMatrix4x4()); matPropertyBlock.AddVector(m_uniforms.screenQuadCornerNorms, new Vector4((float)l0, (float)l1, (float)l2, (float)l3)); Vector3d2 uz = pc.Normalized(); Vector3d2 ux = (new Vector3d2(0, 1, 0)).Cross(uz).Normalized(); Vector3d2 uy = uz.Cross(ux); Matrix4x4d ltow = node.GetLocalToWorld(); Matrix3x3d tangentFrameToWorld = new Matrix3x3d(ltow.m[0, 0], ltow.m[0, 1], ltow.m[0, 2], ltow.m[1, 0], ltow.m[1, 1], ltow.m[1, 2], ltow.m[2, 0], ltow.m[2, 1], ltow.m[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.AddMatrix(m_uniforms.tangentFrameToWorld, (tangentFrameToWorld * m).ToMatrix4x4()); }
protected override void GetTiles(QuadTree parent, ref QuadTree tree, TerrainQuad quad) { if (tree == null) { tree = new QuadTreeZ(parent, quad); tree.needTile = NeedTile(quad); } QuadTreeZ t = tree as QuadTreeZ; //If tile needs elevation data read back add to container if (t.tile != null && t.tile.GetTask().IsDone() && !t.readBack && m_maxReadBacksPerFrame > 0) { if (!m_needReadBack.ContainsKey(t.tile.GetId())) { t.readBack = true; m_needReadBack.Add(t.tile.GetId(), t); } } base.GetTiles(parent, ref tree, quad); //Check if this quad is below the camera. If so store a reference to it. if (m_cameraQuad == null && t.tile != null && t.tile.GetTask().IsDone()) { Vector3d2 c = quad.GetOwner().GetLocalCameraPos(); double l = quad.GetLength(); double ox = quad.GetOX(); double oy = quad.GetOY(); if (c.x >= ox && c.x < ox + l && c.y >= oy && c.y < oy + l) { m_cameraQuadCoords = new Vector2((float)((c.x - ox) / l), (float)((c.y - oy) / l)); m_cameraQuad = t; } } }
//Creates the four subquads of this quad. void Subdivide() { float hl = (float) m_length / 2.0f; m_children[0] = new TerrainQuad(m_owner, this, 2 * m_tx, 2 * m_ty, m_ox, m_oy, hl, m_zmin, m_zmax); m_children[1] = new TerrainQuad(m_owner, this, 2 * m_tx + 1, 2 * m_ty, m_ox + hl, m_oy, hl, m_zmin, m_zmax); m_children[2] = new TerrainQuad(m_owner, this, 2 * m_tx, 2 * m_ty + 1, m_ox, m_oy + hl, hl, m_zmin, m_zmax); m_children[3] = new TerrainQuad(m_owner, this, 2 * m_tx + 1, 2 * m_ty + 1, m_ox + hl, m_oy + hl, hl, m_zmin, m_zmax); }
/** * Creates a new TerrainQuad. * * param owner the TerrainNode to which the terrain quadtree belongs. * param parent the parent quad of this quad. * param tx the logical x coordinate of this quad. * param ty the logical y coordinate of this quad. * param ox the physical x coordinate of the lower left corner of this quad. * param oy the physical y coordinate of the lower left corner of this quad. * param l the physical size of this quad. * param zmin the minimum %terrain elevation inside this quad. * param zmax the maximum %terrain elevation inside this quad. */ public TerrainQuad(TerrainNode owner, TerrainQuad parent, int tx, int ty, double ox, double oy, double length, float zmin, float zmax) { m_owner = owner; m_parent = parent; m_level = (m_parent == null) ? 0 : m_parent.GetLevel() + 1; m_tx = tx; m_ty = ty; m_ox = ox; m_oy = oy; m_zmax = zmax; m_zmin = zmin; m_length = length; m_localBox = new Box3d(m_ox, m_ox + m_length, m_oy, m_oy + m_length, m_zmin, m_zmax); }
protected virtual void SetScreenUniforms(TerrainNode node, TerrainQuad quad, MaterialPropertyBlock matPropertyBlock) { double ox = quad.GetOX(); double oy = quad.GetOY(); double l = quad.GetLength(); Vector3d2 p0 = new Vector3d2(ox, oy, 0.0); Vector3d2 p1 = new Vector3d2(ox + l, oy, 0.0); Vector3d2 p2 = new Vector3d2(ox, oy + l, 0.0); Vector3d2 p3 = new Vector3d2(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.AddMatrix(m_uniforms.screenQuadCorners, (m_localToScreen * corners).ToMatrix4x4()); 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.AddMatrix(m_uniforms.screenQuadVerticals, (m_localToScreen * verticals).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); }
public QuadTreeZ(QuadTree parent, TerrainQuad quad) : base(parent) { this.quad = quad; readBack = false; }
/* * Returns true if a texture tile must be produced for the given quad. */ public abstract bool DiscardTile(TerrainQuad q);
/* * Override the default TileSampler NeedTile to retrive the tile * that is below the camera as well as its default behaviour */ protected override bool NeedTile(TerrainQuad quad) { Vector3d2 c = quad.GetOwner().GetLocalCameraPos(); int l = quad.GetLevel(); double ox = quad.GetOX(); double oy = quad.GetOY(); if (c.x >= ox && c.x < ox + l && c.y >= oy && c.y < oy + l) { return true; } return base.NeedTile(quad); }
protected override void GetTiles(QuadTree parent, ref QuadTree tree, TerrainQuad quad) { if (tree == null) { tree = new QuadTreeZ(parent, quad); tree.needTile = NeedTile(quad); } QuadTreeZ t = tree as QuadTreeZ; //If tile needs elevation data read back add to container if(t.tile != null && t.tile.GetTask().IsDone() && !t.readBack && m_maxReadBacksPerFrame > 0) { if(!m_needReadBack.ContainsKey(t.tile.GetId())) { t.readBack = true; m_needReadBack.Add(t.tile.GetId(), t); } } base.GetTiles(parent, ref tree, quad); //Check if this quad is below the camera. If so store a reference to it. if (m_cameraQuad == null && t.tile != null && t.tile.GetTask().IsDone()) { Vector3d2 c = quad.GetOwner().GetLocalCameraPos(); double l = quad.GetLength(); double ox = quad.GetOX(); double oy = quad.GetOY(); if (c.x >= ox && c.x < ox + l && c.y >= oy && c.y < oy + l) { m_cameraQuadCoords = new Vector2((float)((c.x - ox) / l), (float)((c.y - oy) / l)); m_cameraQuad = t; } } }
protected override void SetScreenUniforms(TerrainNode node, TerrainQuad quad, MaterialPropertyBlock matPropertyBlock) { double ox = quad.GetOX(); double oy = quad.GetOY(); double l = quad.GetLength(); Vector3d2 p0 = new Vector3d2(ox, oy, R); Vector3d2 p1 = new Vector3d2(ox + l, oy, R); Vector3d2 p2 = new Vector3d2(ox, oy + l, R); Vector3d2 p3 = new Vector3d2(ox + l, oy + l, R); Vector3d2 pc = (p0 + p3) * 0.5; double l0 = 0.0, l1 = 0.0, l2 = 0.0, l3 = 0.0; Vector3d2 v0 = p0.Normalized(ref l0); Vector3d2 v1 = p1.Normalized(ref l1); Vector3d2 v2 = p2.Normalized(ref l2); Vector3d2 v3 = p3.Normalized(ref l3); 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.AddMatrix(m_uniforms.screenQuadCorners, (m_localToScreen * deformedCorners).ToMatrix4x4()); 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.AddMatrix(m_uniforms.screenQuadVerticals, (m_localToScreen * deformedVerticals).ToMatrix4x4()); matPropertyBlock.AddVector(m_uniforms.screenQuadCornerNorms, new Vector4((float)l0, (float)l1, (float)l2, (float)l3)); Vector3d2 uz = pc.Normalized(); Vector3d2 ux = (new Vector3d2(0,1,0)).Cross(uz).Normalized(); Vector3d2 uy = uz.Cross(ux); Matrix4x4d ltow = node.GetLocalToWorld(); Matrix3x3d tangentFrameToWorld = new Matrix3x3d(ltow.m[0,0], ltow.m[0,1], ltow.m[0,2], ltow.m[1,0], ltow.m[1,1], ltow.m[1,2], ltow.m[2,0], ltow.m[2,1], ltow.m[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.AddMatrix(m_uniforms.tangentFrameToWorld, (tangentFrameToWorld * m).ToMatrix4x4()); }