八叉树设计(rust)

#松散八叉树设计方案

##1.松散八叉树

八叉树就是用在3D空间中的场景管理,可以很快地知道物体在3D场景中的位置,或侦测与其它物体是否有碰撞以及是否在可视范围内。
松散八叉树不会出现物体跨界的情况,也不会出现很小的物体需要放到很大的节点之中的问题。  
缺点:由于节点与节点之间相互重叠在一起,相对于经典八叉树来说,做视锥裁剪时,程序逻辑可能需要检查更多的节点。

##2.[写时复制](http://hackerboss.com/copy-on-write-101-part-1-what-is-it/)

写入时复制(Copy-on-write)是一个被使用在程式设计领域的最佳化策略。其基础的观念是,如果有多个呼叫者(callers)同时要求相同资源,他们会共同取得相同的指标指向相同的资源,直到某个呼叫者(caller)尝试修改资源时,系统才会真正复制一个副本(private copy)给该呼叫者,以避免被修改的资源被直接察觉到,这过程对其他的呼叫只都是通透的(transparently)。此作法主要的优点是如果呼叫者并没有修改该资源,就不会有副本(private copy)被建立。


## 3.设计方案 
八叉树主要管理两种数据:八叉树据本身节点;物件数据。

###3.1.数据结构
pub struct S3dOctree{  
pub root : AtomicPtr<*mut _S3dOTNode>, // 八叉树根节点,支持原子操作。  
}

pub struct _S3dOTNode{  
pub     aabb: PiAABBBox, // 本节点的世界坐标系下空间范围  
pub     children : [*mut _S3dOTNode;octree::_CHD_NUM],     //子节点  
pub     objects:*const _S3dOTObj, // 节点列表,注意:第一个obj为引用占位  
pub     obj_num:i32, //本节点直接持有的物体数量  
pub     all_obj_num:i32, //包括自己和其所有子节点所持有的物体数量  
pub    splitted:bool, //此节点是否执行过分裂  
pub    ref_count : AtomicUsize; //引用计数,根节点有用,原子操作  
}
 
###3.2. 应用场景 
本方案适用于:一个写线程,一个或多个读线程的场景。一个场景中只存在一棵树。

###3.3.设计思路 

写操作时,复制(深拷贝)老树(真实存在的)上变化的节点生成新的节点,这些新生成的节点 和 老树上的不变节点,组成一棵新的树,
称新树(逻辑树)。然后用新树的根节点指针替换(原子操作)老树的根节点指针,释放老树上变化节点所占用的内存空间。整个过程就
完成了八叉树的写时复制。

方案中两处使用原子操作:根节点内部引用计数;树的根节点指针。根节点使用引用计数用于树的节点内存管理,当根节点为引用计数为0时,
释放老树上变化的节点所占内存(释放工作由写线程完成)。读线程访问树时,根节点引用加1,访问完成时,根节点引用计数减1。使用原子操作,不需要加额外的锁,开销小。

八叉树的变化由物件的增、删、改驱动的。物件的插入,可能导致的几种结果: 插入已有节点,表现为节点更新;分化出新节点,物件插入新节点,
表现为节点增加;分化出新节点,并导致父节点的物件下放,表现为节点新增和节点更新同时发生。物件删除,可能导致: 从节点上删除,表现为
节点数据更新;节点收缩,表现为节点删除;收缩节点的同时,上放物件,表现为节点新增和节点更新同时发生。物件的修改,可能导致:节点收缩;节点新增;节点删除;或同时发生。


## 4.八叉树的性能 

### 4.1 读的性能
语言 :c , rust(cow),rust  
树的规模(物件个数): 1000,5000,10000,100000  
测试方法: 遍历树10000次  
结果: 单位秒,保留小数后两位有效数字  
<table>   
    <tr>
        <td> </td>       
        <td>1000</td>
        <td>5000</td>
        <td>10000</td>
        <td>100000</td>
    </tr>
    <tr>
        <td>c</td>       
        <td>0.31</td>
        <td>1.35</td>
        <td>2.68</td>
        <td>26.73</td>   
    </tr>
    <tr>
        <td>rust(cow)</td>        
        <td>0.71</td>
        <td>3.15</td>
        <td>5.52</td>
        <td>57.28</td>   
    </tr>
    <tr>
        <td>rust</td>         
        <td>1.28</td>
        <td>5.77</td> 
        <td>11.09</td> 
        <td>100.15</td>  
    </tr>    
</table> 
  
### 4.2 写的性能 
 
语言 :c , rust(cow),rust    
测试方法: 向树插入1000,5000,10000,100000规模的物件  
结果: 单位秒,保留小数后两位有效数字  
<table>   
    <tr>
        <td> </td>       
        <td>1000</td>
        <td>5000</td>
        <td>10000</td>
        <td>100000</td>
    </tr>
    <tr>
        <td>c</td>       
        <td>0.0014</td>
        <td>0.0073</td>
        <td>0.014</td>
        <td>0.14</td>   
    </tr>
    <tr>
        <td>rust(cow)</td>        
        <td>0.026</td>
        <td>0.15</td>
        <td>0.32</td>
        <td>41.66</td>   
    </tr>
    <tr>
        <td>rust</td>         
        <td>0.00026</td>
        <td>0.0012</td> 
        <td>0.0023</td> 
        <td>0.020</td>  
    </tr>    
</table>   


#s3d 整体设计方案

##1.概述 

s3d 向外提供添加、删除、修改、查询物件的接口;对内管理八叉树数据。


##2.数据结构 

//场景数据
pub struct S3dScene{
  pub  octree : Box<Octree>,  //八叉树指针,一个场景中只存在一个棵树
  pub obj_index : AtomicUsize, //物件索引器
  pub obj_map: VecMap<_S3dObj>, //物件存储器
  pub write_read: RwLock<u32>, //读写锁  
}


//物件数据 

pub struct S3dObj {
pub    point : PiVector3, //
pub    aabb : PiAABBBox, //aabb    
pub    obb : PiOBBBox,  //obb
pub    internal_mask : u32,//掩码
}

##3.设计思路

### 3.1 物件存储

物件的数据的信息存在S3d层,方便直接获取单个物件的数据,不需要每次都查询八叉树,加快了数据的查询;八叉树只存储物件的索引和aabb数据,加快写时复制的效率。物件存储器负责物件的存储,数据以<索引,S3dObj对象>的形式存储;物件索引器负责物件的索引的分配,支持原子操作,保证了数据的唯一性;读写锁控制物件存储器的读写权限。

物件创建和插入过程: 获取从物件索引器获取索引,索引器自加1(原子操作);创建S3dObj对象;将<索引,物件对象>插入物件对象管理器,将物件插入八叉树(只保存索引和AABB数据)。


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值