OpenGL中将矩阵与向量对齐:三角形法线可视化朝向调整问题
三角形法线可视化对齐解决方案
问题原因
你之前的实现出错核心有两点:
glm::lookAt本身是用来生成相机视图矩阵的,它输出的是「世界坐标系到观察者局部坐标系」的变换矩阵,你直接把它作为模型矩阵(将小三角形局部坐标转到世界坐标)使用,相当于变换方向完全颠倒,所以位置和旋转都会异常。- 你的可视化小三角形顶点默认沿
X轴正方向延伸,你需要额外构造旋转矩阵,把默认朝向转到对应法线方向,再叠加位移即可。
修复方案
直接计算默认朝向到目标法线的旋转矩阵,叠加到位移变换之后即可,修改后的绘制代码如下:
for(unsigned int i = 0; i < worldTriangles->size(); i++) { Triangle *tri = &worldTriangles->at(i); glm::vec3 wp = tri->worldPosition; glm::vec3 nrm = glm::normalize(tri->normal); // 先归一化法线避免计算误差 nrmGizmoMatrix = glm::mat4(1.0f); // 第一步:先把三角形位移到目标点 nrmGizmoMatrix = glm::translate(nrmGizmoMatrix, wp); // 第二步:计算从默认朝向(X正方向)到法线方向的旋转 const glm::vec3 default_dir = glm::vec3(1.0f, 0.0f, 0.0f); float dot_val = glm::dot(default_dir, nrm); // 处理两个向量平行的边界情况,避免万向锁 if (fabs(dot_val + 1.0f) < 0.000001f) { // 法线和默认朝向完全相反,绕Y轴旋转180度 nrmGizmoMatrix = glm::rotate(nrmGizmoMatrix, glm::pi<float>(), glm::vec3(0.0f, 1.0f, 0.0f)); } else if (fabs(dot_val - 1.0f) > 0.000001f) { // 非平行情况,计算旋转轴和旋转角应用旋转 float rot_angle = acosf(dot_val); glm::vec3 rot_axis = glm::normalize(glm::cross(default_dir, nrm)); nrmGizmoMatrix = glm::rotate(nrmGizmoMatrix, rot_angle, rot_axis); } gizmoShader.setMatrix(projectionMatrix, viewMatrix, nrmGizmoMatrix); glBindVertexArray(nrmGizmoVAO); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0); glBindVertexArray(0); }
额外注意事项
你初始化VAO的代码里有个拼写错误:glBindBuffer(GL_ARRAY_BUFFER, nmrGizmoVBO); 中nmrGizmoVBO是拼写错误,正确为nrmGizmoVBO,这个错误会导致顶点数据无法正确绑定,运行时看不到可视化元素。
如果你一定要用glm::lookAt实现也可以,只要对生成的lookAt矩阵取逆即可,代码如下:
glm::mat4 look_mat = glm::lookAt(glm::vec3(0.0f), nrm, glm::vec3(0.0f, 1.0f, 0.0f)); nrmGizmoMatrix = glm::translate(glm::mat4(1.0f), wp) * glm::inverse(look_mat);
不过该方案在法线和Y轴平行时会出现精度问题,不如直接计算旋转的方案稳定。
内容的提问来源于stack exchange,提问作者nyaol9
相关产品推荐
相关产品推荐

