3D引擎开发:如何判断三角形的正确表面法线方向?
三角形法线方向选择方案
你的排序逻辑是通过三角形中心加上法线后的点到原点的距离来排序,但顶点的顺时针/逆时针顺序导致生成了方向相反的法线。要解决这个问题,核心是根据你的排序需求,统一选择朝向正确的法线:
判断逻辑
我们可以通过三角形中心到原点的向量,和法线的点积来判断方向:
- 计算三角形中心指向原点的向量:
center_to_origin = 原点 - 三角形中心 - 分别计算该向量与两个法线的点积:点积为正,说明法线方向和「中心指向原点」的方向夹角小于90度(法线朝向原点一侧);点积为负则相反。
- 根据你的排序需求选择对应法线——比如如果你的排序是希望“更靠近原点的延伸点”优先,就选点积为正的那个法线。
修改后的代码
// 遍历所有待绘制三角形 for (int i = 0; i < tridrawcount; i++) { triangle &listtri = tridrawlist[i]; vec3 norm; vec3 line; vec3 line2; vec3 apos; vec3 ppos; vec3 center_to_origin; line = listtri.vpos2 - listtri.vpos; line2 = listtri.vpos3 - listtri.vpos; // 先计算其中一个法线,另一个是它的反方向,不用单独计算 norm = line.cross(line2); float length = norm.mag(); norm = norm / length; vec3 norm2 = -norm; // 直接取反,节省计算量 apos = (listtri.vpos + listtri.vpos2 + listtri.vpos3)/3; // 三角形中心 center_to_origin = vec3(0, 0, 0) - apos; // 计算点积判断方向 float dot_norm = norm.dot(center_to_origin); vec3 selected_norm = (dot_norm > 0) ? norm : norm2; // 计算目标点和距离 ppos = selected_norm + apos; float dist = sqrt(pow(0 - ppos.x,2) + pow(0 - ppos.y, 2) + pow(0 - ppos.z, 2)); // 这里可以加入你的排序逻辑,比如把dist和三角形关联起来排序 }
额外优化点
- 不用分别计算
norm和norm2的叉乘,直接对norm取反就能得到norm2,减少计算量。 - 如果排序只需要比较距离的大小,可以不用开平方(
sqrt),直接比较距离的平方值,提升性能:float dist_sq = pow(0 - ppos.x,2) + pow(0 - ppos.y, 2) + pow(0 - ppos.z, 2);
内容的提问来源于stack exchange,提问作者user18504606
相关产品推荐
相关产品推荐

