// Push draw data public void PushDrawData(DRAWDATA data) { drawDataList.Add(data); }
void CollectRenderNodes_r(int nodeIndex) { QtreeNode node = nodeBuf[nodeIndex]; // Only render node whose info is up-to-date if (node.updateCnt != updateCnt) { // If a node isn't up-to-date, all it's children must not be. return; } // do camera cull with node's AABB at first, but node may not have min-y and max-y // at this moment if it's mesh wasn't built, so now we only do a conservative check // with x and z axis. // NOTE: we ONLY consider tranlation of terrain, but not rotation and scale Vector3 offset = terrain.transform.position; Rect rcLocal = node.CalcLocalArea(terrain.gridSize); Vector3 mins = new Vector3(rcLocal.xMin + offset.x, -10000.0f, rcLocal.yMin + offset.z); Vector3 maxs = new Vector3(rcLocal.xMax + offset.x, 10000.0f, rcLocal.yMax + offset.z); Bounds aabb = new Bounds(); aabb.SetMinMax(mins, maxs); if (!GeometryUtility.TestPlanesAABB(camPlanes, aabb)) { return; // The whole node isn't visible } if (node.meshState == (byte)eNodeMeshState.LOAD_INBORN || node.meshState == (byte)eNodeMeshState.LOD_GRADEUP) { // Get index buffer according to neighbour's LOD grade int sideMask = 0; for (int i = 0; i < 4; i++) { if (node.neighbour[i] < 0) { continue; } QtreeNode neighbour = nodeBuf[node.neighbour[i]]; if (neighbour.updateCnt == updateCnt && neighbour.areaLOD > node.areaLOD) { sideMask |= (1 << i); } } // This node's may be drawn ComputeBuffer _vertCB = null; ComputeBuffer _indexCB = null; QuadtreeMesh nodeMesh = null; if (node.meshState == (byte)eNodeMeshState.LOAD_INBORN) { nodeMesh = terrain.meshMan.GetNodeMesh(nodeIndex); if (nodeMesh != null) { _vertCB = nodeMesh.vertCB; _indexCB = terrain.trnRes.GetNodeIndexCB(sideMask, -1); } } else if (node.meshState == (byte)eNodeMeshState.LOD_GRADEUP) { // LOD grade-up rendering, use parent's mesh Debug.Assert(node.parent >= 0); nodeMesh = terrain.meshMan.GetNodeMesh(node.parent); if (nodeMesh != null) { _vertCB = nodeMesh.vertCB; _indexCB = terrain.trnRes.GetNodeIndexCB(sideMask, node.childPos); } } if (_vertCB != null && _indexCB != null) { // do camera cull again with more precise aabb mins.y = nodeMesh.aabb.min.y + offset.y; maxs.y = nodeMesh.aabb.max.y + offset.y; aabb.SetMinMax(mins, maxs); if (!GeometryUtility.TestPlanesAABB(camPlanes, aabb)) { return; // The whole node isn't visible } // Push node to rendering collector DRAWDATA drawData = new DRAWDATA() { node = node, nodeAABB = aabb, vertCB = _vertCB, indexCB = _indexCB, }; curRenderer.PushDrawData(drawData); } } if (!node.IsLeaf()) { // Go on for children for (int i = 0; i < 4; i++) { CollectRenderNodes_r(node.children[i]); } } }