旋转曲面法线计算异常求助:渲染存在无法消除的线条
旋转曲面法线计算异常导致渲染出现线条问题
渲染旋转曲面时始终存在一条无法消除的异常线条,效果如下:
坐标先存入结构体传递给OpenGL,再基于曲面数据计算法线,以下是环面生成代码和法线计算代码,请求排查问题。
环面生成代码
for (int x = 0; x < num_heights; ++x) { for (int y = 0; y < num_revs; ++y) { mesh[(x * num_revs_) + y].pos[0] = (c + (a * cos(omega * x))) * cos(omega * y) * sphere_size; mesh[(x * num_revs_) + y].pos[1] = a * sin(omega * x) * sphere_size; mesh[(x * num_revs_) + y].pos[2] = (c + (a * cos(omega * x))) * sin(omega * y) * sphere_size; } }
法线计算代码(相邻顶点叉积求平均后归一化)
for (int x = 0; x < num_heights; ++x) { for (int y = 0; y < num_revs; ++y) { int index = x * num_revs + y; Vec3 cur = Vec3(mesh[(x * (num_revs)) + y].pos[0], mesh[(x * (num_revs)) + y].pos[1], mesh[(x * (num_revs)) + y].pos[2]); int left_ind = index - 1; if (left_ind < 0) { left_ind = num_revs - 1; } Vec3 left = Vec3(mesh[left_ind].pos[0], mesh[left_ind].pos[1], mesh[left_ind].pos[2]); int up_ind = ((x + 1) * (num_revs)) + y; Vec3 up = Vec3(mesh[up_ind].pos[0], mesh[up_ind].pos[1], mesh[up_ind].pos[2]); int right_ind = index + 1; if (right_ind > (num_heights * num_revs)) { right_ind = 0; } Vec3 right = Vec3(mesh[right_ind].pos[0], mesh[right_ind].pos[1], mesh[right_ind].pos[2]); int down_ind = ((x - 1) * (num_revs)) + y; if (down_ind < 0) { down_ind = (num_heights - 1) * (num_revs) + y; } Vec3 down = Vec3(mesh[down_ind].pos[0], mesh[down_ind].pos[1], mesh[down_ind].pos[2]); int new_ind = 0; if (x == (num_heights ) - 1) { left = Vec3(1, 0, 0); up = Vec3(1, 0, 0); right = Vec3(1, 0, 0); down = Vec3(1, 0, 0); } Vec3 dir_left = left - cur; Vec3 dir_up = up - cur; Vec3 dir_right = right - cur; Vec3 dir_down = down - cur; Vec3 cross = Vec3::CrossProduct(dir_left, dir_up); cross += Vec3::CrossProduct(dir_up, dir_right); cross += Vec3::CrossProduct(dir_right, dir_down); cross += Vec3::CrossProduct(dir_down, dir_left); cross.Normalize(); mesh[(x * num_revs_) + y].normal[0] = cross.x; mesh[(x * num_revs_) + y].normal[1] = cross.y; mesh[(x * num_revs_) + y].normal[2] = cross.z; } }
问题排查方向
- 数组下标不一致:生成代码用
num_revs_作为下标乘数,法线计算代码混用num_revs和num_revs_,若两个变量值不同,会直接导致顶点索引错乱,法线计算完全错误。 - 边界顶点处理逻辑错误:
- 当
x = num_heights - 1时,硬编码left/up/right/down为Vec3(1,0,0),导致最后一行顶点法线与相邻顶点完全不连续,渲染时出现断层线条。 right_ind的判断条件错误:right_ind > (num_heights * num_revs)应改为right_ind >= (num_heights * num_revs),更准确的是当y == num_revs - 1时,right_ind应指向当前x行的第一个顶点(x * num_revs),而非直接跳转到0(跨x行取顶点会导致方向向量错误)。
- 当
- 越界访问问题:当
x = num_heights - 1时,up_ind = num_heights * num_revs + y会超出数组范围,需根据母线是否闭合处理x方向边界(闭合则循环到x=0,非闭合则取当前x行顶点)。 - 叉积方向不统一:四个叉积的方向可能存在冲突,导致法线被抵消或方向错误,需确保每个叉积都指向曲面外侧后再累加平均。
内容的提问来源于stack exchange,提问作者agutier2
相关产品推荐
相关产品推荐

