针对渲染圆柱体出现“麻花“状问题解决
圆柱体渲染结果,在侧面有麻花状条纹,边缘不够硬朗,上下的圆看起来不够平,很明显,是法向量导致的。
原始模型 渲染结果
计算点的法向量采用简单的平均法:
-
计算该点相邻面的法向量
-
将所有相邻面的法向量取平均
-
最后归一化为单位向量
C++代码:
void compute_vertex_normals_manual(const Mesh& mesh, std::vector<Vector_3>& vertex_normals) {vertex_normals.resize(mesh.num_vertices(), Vector_3(0, 0, 0));// 记录每个顶点的相邻面数(用于平均)std::vector<unsigned int> vertex_face_count(mesh.num_vertices(), 0);for (auto face : mesh.faces()) {auto h = mesh.halfedge(face);auto v0 = mesh.target(h);auto v1 = mesh.target(mesh.next(h));auto v2 = mesh.target(mesh.prev(h));Point_3 p0 = mesh.point(v0);Point_3 p1 = mesh.point(v1);Point_3 p2 = mesh.point(v2);Vector_3 e0 = p1 - p0;Vector_3 e1 = p2 - p0;// 计算面法向量(先归一化,再累加)Vector_3 face_normal = CGAL::cross_product(e0, e1);double len = CGAL::sqrt(face_normal.squared_length());if (len > 0) face_normal = face_normal / len;// 累加归一化后的面法向量vertex_normals[v0] += face_normal;vertex_normals[v1] += face_normal;vertex_normals[v2] += face_normal;// 更新相邻面计数vertex_face_count[v0]++;vertex_face_count[v1]++;vertex_face_count[v2]++;}// 计算平均法向量并归一化for (size_t i = 0; i < vertex_normals.size(); ++i) {if (vertex_face_count[i] > 0) {vertex_normals[i] = vertex_normals[i] / vertex_face_count[i];double len = CGAL::sqrt(vertex_normals[i].squared_length());if (len > 0) vertex_normals[i] = vertex_normals[i] / len;}}
}
原因分析:模型不够精细,点太少,三角形 顶点1、 2 、3的法向量不一样,显卡在渲染的时候会进行插值,插值的点会根据点1、2、3的法向量自动计算,渲染时有过度的效果,因此看起来会有倾斜的条纹。
原始模型 渲染结果
解决办法:
确保统一平面上的点的法向量一致或有平直的过度,那么渲染就比较自然了。
方案1. 将上下两个圆和侧面分离,作为独立的对象渲染,使得边缘处的法向量不受平均法向量影响
原始模型 渲染结果
方案2. 精细化模型,简单的方法是在硬边缘处增加卡线,每条边缘增加两条卡线,使受平均法向量影响的点限制在两条卡线中间,只有边缘处有平滑效果,其他的三角形过度就是平直的
原始模型 渲染结果