如何在四叉树中强制执行从 LOD 到 LOD 的恒定 2:1 细分?

问题描述 投票:0回答:1

首先感谢TARN4T1ON。他建议使用边界框进行距离检测帮助我解决了我的问题。

现在我有了新的障碍。

我想要我的相机具有径向对称的细节渐变。我通过相机周围的同心球壳和四叉树子项的边界框(AABB 碰撞检测)实现了径向对称。这些球壳与四叉树相交并提供细分。哪个球壳与四叉树相互作用取决于相机距离。我之所以需要多个球体而不仅仅是一个球体,是因为我想要定义详细程度级别。我想要从 lod 到 lod 的 2:1 渐变。这就是为什么我的球壳随着 2^i 变得更大。 尽管如此,有时我会得到 4:1 而不是 2:1 的 lod 过渡。这肯定是由于我的细分条件造成的,因为这不是一个干净的解决方案。

如果我将最外层球壳与四叉树相交产生的确切子尺寸转移到底层球壳等,这会是一个干净的解决方案吗?

我总是需要 2:1 的细节渐变并且不能更大

_LODRadii(minRadius, numLayers){
        
    const lodRadii = [];
    for(let i = 0; i < numLayers; i++){
        lodRadii.push(minRadius * 2 ** i);
    }           
    return lodRadii;    
}

//I don't use this function for anything right now
_Lod0(child, pos, numLayers, lodRadii){
        
    const lodCenter = pos;
    const closestPoint = new THREE.Vector3();
    child.newBounds.clampPoint(lodCenter, closestPoint); 
    const squaredDistance = lodCenter.distanceToSquared(closestPoint);              

    let lod0 = -1; 
            
    for (let i = 0; i < numLayers; i++) { 
        const lodRadius = lodRadii[i]; 
        if (squaredDistance <= lodRadius ** 2) { 
            lod0 = i; 
            break; 
        } 
    }   
    return lod0;            
}


//pos = cameraPosition
Insert(pos) {
    const minRadius = this._params.min_lod_radius;  //is 24
    const numLayers =   this._params.lod_layers;    //is 15
    const lodRadii = this._LODRadii(minRadius, numLayers);
    const lod0 = this._Lod0(this.root_, pos, numLayers, lodRadii);      
    this._Insert(this.root_, pos, lodRadii, numLayers, lod0);   
}


_Insert(child, pos, lodRadii, numLayers, lod0) {    
    
    //lod0  is the smallest spherical radius that intersects the quadtree. But I don't use that
                
    const lodCenter = pos;
    const closestPoint = new THREE.Vector3();
    child.newBounds.clampPoint(lodCenter, closestPoint); 
    const squaredDistance = lodCenter.distanceToSquared(closestPoint); //squared distance from the camera to bounding box
            

    for(let i = numLayers; i >= 0; i--) {
            
        const lodRadius = lodRadii[i];
    
        if(squaredDistance <= lodRadius ** 2 && child.size.x >= lodRadius ) {
            child.children = this._CreateChildren(child);
            for (let c of child.children) {
                this._Insert(c, pos, lodRadii, i, lod0);
            }
            break;
        }           
    }   
}

核心是我的_Insert函数。它决定了我的四叉树的细分。由于有关四叉树的其他所有内容或多或少都是相同的,并且对于细分并不重要,因此我将其省略。数百行非贡献代码没有帮助。核心是_Insert函数。其中发生的事情决定了细分。

我之所以做了_Lod0这个函数,是因为我有一个想法,就是以相机周围最小的区域为参考,然后再以2:1的更小的细分出去,但我不知道如何实现如果这有意义的话。

quadtree
1个回答
0
投票

您当前的方法是通过相机和四叉树边界框之间的距离来确定适当的 LOD。这将给出 LOD 的径向渐变。然而,您遇到的问题是 LOD 之间的非恒定细分为 2:1,有时您会得到 4:1 的差异。

我将提供一个解决方案来确保 2:1 的细分:

1- 距离分桶:

在细分过程之前,计算每个 LOD 级别的距离桶:

let lodBuckets = [];
for(let i = 0; i < numLayers; i++){
    lodBuckets.push({min: lodRadii[i], max: lodRadii[i+1]});
}

2- 确定 LOD:

确定 LOD 的函数为:

function determineLOD(distance, lodBuckets){
   for(let i = 0; i < lodBuckets.length; i++) {
       if(distance >= lodBuckets[i].min && distance < lodBuckets[i].max) {
           return i;
       }
   }
   return -1; // or whatever you want for out-of-range distances
}

3-递归插入:

修改 _Insert 函数以使用确定 LOD 方法:

_Insert(child, pos, lodRadii, numLayers, lodBuckets) {    
 
    const lodCenter = pos;
    const closestPoint = new THREE.Vector3();
    child.newBounds.clampPoint(lodCenter, closestPoint); 
    const squaredDistance = lodCenter.distanceToSquared(closestPoint); //squared distance from the camera to bounding box
    const distance = Math.sqrt(squaredDistance);
    const currentLOD = determineLOD(distance, lodBuckets);

    if(currentLOD != -1 && child.size.x >= lodRadii[currentLOD]) {
        child.children = this._CreateChildren(child);
        for (let c of child.children) {
            this._Insert(c, pos, lodRadii, numLayers, lodBuckets);
        }
    }           
}

通过对距离进行分桶,可以确保两个同心球之间的空间始终映射到一个 LOD。这应该在 LOD 之间提供一致的 2:1 细节渐变,并且过渡应始终为 2:1。

此外,请记住,您需要确保边界框的大小和初始距离适合确保这种渐变。如果设置不正确,您可能仍会遇到 LOD 意外跳跃的情况。

最后,在开发过程中始终可视化您的结构和 LOD。它将帮助您快速发现不一致之处和潜在改进的领域。

© www.soinside.com 2019 - 2024. All rights reserved.