void GenerateQuadTree(Quad parentQuad) { this.AddChild(parentQuad); parentQuad.PreCalculate(); if (parentQuad.LOD == this.levels) { parentQuad.isLeaf = true; return; } parentQuad.isLeaf = false; var currX = parentQuad.transform.localPosition.x; var currY = parentQuad.transform.localPosition.y; var currZ = parentQuad.transform.localPosition.z; var stride = parentQuad.size * 0.5f; for (int i=0; i < 4; i++) { var childQuad = new Quad(parentQuad.LOD + 1, parentQuad.size * 0.5f, parentQuad.size * 0.5f, this.heightMap); parentQuad.children.Add(childQuad); childQuad.transform.localPosition = new Vector3(currX, currY, currZ); this.GenerateQuadTree(childQuad); currX = currX + stride; if ((currX - parentQuad.transform.localPosition.x) >= parentQuad.size) { currX = parentQuad.transform.localPosition.x; currZ = currZ + stride; } } }
// Chunked LOD implementation: http://tulrich.com/geekstuff/sig-notes.pdf // TODO: Optimizations // Store coordinates of bounding boxes and exclude branches in quadtree that are out of range void ChunkedLOD(Quad quad, float scalingFactor=1.0f) { var camPos = this.cam.transform.position; Vector3 closestPoint = quad.boundingBox.ClosestPoint(camPos); float distance = Vector3.Distance(closestPoint, camPos); // Screen space error float rho = (quad.error / distance ) * scalingFactor; // Largest allowable screen error float tau = 120; if (quad.isLeaf || rho <= tau) { quad.active = true; } else { // TODO: When we implement excluding of whole subbranches, we'll have to turn off visibility for all chunks in that branch foreach (Quad q in quad.children) { this.ChunkedLOD(q, scalingFactor); } } }