potree--如何控制八叉树子节点的显示?
经过PotreeConverter的处理,可以把点云数据转换成bin、las、laz三种格式的二进制文件,然后我们就可以将这些文件加载至网页进行显示;
如何判断八叉树的子节点的visible是true还是false?
potree内部总共有四个机制进行判断,首先从整个Potree的window.requestAnimationFrame() 开始分析;
Potree.Viewer.loop函数的内部可以看到,调用了Potree.Viewer.update(),Potree.Viewer.update函数内部调用Potree.updatePointClouds()函数
接下来,我们根据源代码进行分析:
updateVisibilityStructures函数里面调用 let priorityQueue = new BinaryHeap(function(x){return 1 / x.weight;}); 是为了控制八叉树节点的加载顺序,根据weight的大小,weight越大优先级越高;
计算视椎体与该node的boundingBox之间的关系,如果box在frustum内返回true,否则返回false
let insideFrustum = frustum.intersectsBox(box);
最大显示八叉树的深度
let maxLevel = pointcloud.maxLevel || Infinity;
获取该node的深度
let level = node.getLevel();
如果node在视椎体内,visible为ture,否则为false
let visible = insideFrustum;
如果已经显示的节点的所有点数目加上该node的点数目之和大于Potree设置的点数目边界值,visible为false,否则为true
visible = visible && !(numVisiblePoints + node.getNumPoints() > Potree.pointBudget);
如果该node的level大于Potree设置的maxLevel,visible为false,否则为true
visible = visible && level < maxLevel;
如果已有的点数与该node的点数之和大于Potree的点数上限,该循环直接跳出
if(numVisiblePoints + node.getNumPoints() > Potree.pointBudget){
break;
}
如果visible为false,则判断下一个node
if(!visible){
continue;
}
如果该node的visible为true,则对其子节点进行判断
获得子节点并进行循环
let child = children[i];
计算子节点的包围球
let sphere = child.getBoundingSphere();
计算相机与包围球心之间的距离
let distance = sphere.center.distanceTo(camObjPos);
let radius = sphere.radius;
将相机的视角从角度变成弧度
let fov = (camera.fov * Math.PI) / 180;
计算相机视角一半的倾斜度
let slope = Math.tan(fov / 2);
计算像素在屏幕范围内,与距离之间的系数
let projFactor = (0.5 * renderer.domElement.clientHeight) / (slope * distance);
计算包围球的半径在屏幕内实际的像素大小
let screenPixelRadius = radius * projFactor;
如果该子节点的包围球的半径在屏幕范围内的像素尺寸小于预先设置的minimumNodePixelSize,那么该子节点不显示
if(screenPixelRadius < pointcloud.minimumNodePixelSize){
continue;
}
以上这些就是判断一个八叉树的节点是否显示的所有因素;