非均匀网格
定义
可以引入新的点(Steiner Point)生成三角剖分
称为Steiner Triangulation(Steiner三角剖分)
目的
让三角剖分后的结果每个三角形的每个角度都在45 - 90中
且三角形数量少
且三角形大小变化均匀
基于四叉树的非均匀网格生成算法:
名词
每个结点代表一个正方形,结点的四个孩子分别代表其父亲正方形的四个象限(quadtree subdivision,四叉树划分)
有些边界上的结点可能多于4个顶点,仍称之为正方形;正方形顶点称为角顶点(corner vertex)
连接两个相邻顶点的为侧边side,完全落在一个边上的是edge;邻居:两个正方形共用一条边
用四叉树保存平面上的一组点;只要某个正方形中包含的点多于一个,就递归进行分割(有点类似德劳内三角划分的桶结构)。
分析
初始正方形:点集的最小包围正方形
四叉树会很不均匀,但有极限:
深度不超过log(s(初始正方形边长)/c(各点中最近距离)) + 3/2
n个点,d深度的四叉树,节点数为O((d + 1)*n),可在O((d + 1)*n)时间构造出来
邻居查找
某个正方形的邻居要么是当前爹爹的孩子(同系),要么是它爹爹邻居的后代或者他爹爹邻居本人
所以可以得到:邻居查找时间复杂度为O(d(深度) + 1)
以上的四叉树很不平衡(面积很大的正方形与面积很小的正方形相邻)
平衡四叉树
引入一种四叉树变种:平衡四叉树(balanced quadtree):任何邻居正方形的边长不超过两倍
只是需要一个平衡化的函数,在之前的四叉树基础上操作即可
算法
//将四叉树变为平衡四叉树
quadtree BalanceTheQuadtree(quadtree qdtree) {
queue leavesQ;
while(!leavesQ.empty()) {
leaf topLeaf = leavesQ.top();
if(needSplit(topLeaf ,qdtree)) {
Block blockTopLeaf = LeaveToBlock(topLeaf);//将topLeave生成内部点;
qdtree.AddLeave(sonA, sonB, sonC, sonD);//其四个孩子都是叶子(是其四个象限);
if(haveaPoint(blockTopLeaf)) {//如果topLeave中有一个点
//从blockTopLeaf中取出,存入对应的新的叶子
}
//将四个新叶子插入leavesQ;
//检查topLeaf的各个邻居,看是否需要分割
//如果某些邻居需要分分割,将其加入到leavesQ
}
}
return qdtree;
}
//是否需要将topLeaf进行分割
bool needSplit(leaf topLeaf, quadtree qdtree) {
通过邻居查找算法,查看附近的边是否是自己的一半以内
}
拓展
八叉树
渲染/光线追踪
弹道轨迹
总之就是位置确定相关
从四叉树到网格
构造四叉树的递归终止条件:知道正方形不在于任何目标边界相交,或者正方形边长缩短到一个单位,就不再继续细分。
一般考虑:对于内部没有边穿过的正方形,为他们添加一条对角线即可。但这样并不是一致的。
平衡化四叉树后按照如下算法划分三角形:
两种情况:
a、侧边内部不含顶点,直接一条对角线划分正方形
b、侧边有顶点,则根据平衡结果一定是侧边中点,再此正方形中心加入Steiner点,然后链接边上所有顶点。