【问题标题】:OpenGL - Correct Surface Normals after ProjectionOpenGL - 投影后正确的表面法线
【发布时间】:2012-11-11 04:05:38
【问题描述】:

我目前正在使用 OpenGL 开发一个小玩具程序,该程序在剪辑空间视图中显示一个场景,即它绘制一个立方体以可视化规范视图体积,并在立方体内部绘制投影变换模型。显示模型图的代码 sn-p:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(1.0f, 1.0f, -1.0f);
glMultMatrixd(projectionMat);
glMultMatrixd(modelviewMat);
glEnable(GL_LIGHTING);
draw_model();
glDisable(GL_LIGHTING);

因此,自然地,绘制的模型是“扭曲的”(这是所需的行为)。然而,光照是错误的,因为表面法线也被投影矩阵变换,因此在变换后与它们的表面不正交。我想要完成的是“正确”的照明,即扭曲模型的表面具有正确的法线。

问题是 - 我该怎么做?我正在使用通常的法线转置逆矩阵规则,但据我所知,这就是 OGL 默认情况下对其法线所做的事情。我想在用模型视图矩阵转换表面之后,我必须重新计算表面法线,但是该怎么做呢?还是有别的办法?

【问题讨论】:

  • 实际上,“双投影”正是我想要做的,是的:) 正如您在教程中所描述的,重点是在标准化设备坐标中查看对象的“奇怪”形状。但是,我并没有真正找到/理解您对表面法线所做的工作以在 NDC 空间中获得“正确”的照明。在我的示例中,从反转置模型视图矩阵中“移除”投影部分是否足以使法线仅由“真实”模型视图矩阵转换?我是一个 OGL 新手,所以请多多包涵:D
  • 你看我的回答了吗?此外,本教程不会在 NDC 空间中进行照明。渲染位置的空间不一定是您进行照明的空间。
  • @NicolBolas 您的教程链接现在指向一些奇怪的广告页面,我也刚刚弹出一个窗口,它希望我安装一些 Chrome 插件。最好删除/更新链接,以免没有人点击它并爱上它。这是 web.archive.org 上的教程:web.archive.org/web/20150225192609/http://www.arcsynthesis.org/…

标签: opengl transform projection normals


【解决方案1】:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(1.0f, 1.0f, -1.0f);
glMultMatrixd(projectionMat);

投影矩阵进入glMatrixMode(GL_PROJECTION);。转换法线发生在模型视图的逆转置中。如果模型视图中有投影组件,它会打乱您的正常转换。

正确的代码是

glMatrixMode(GL_PROJECTION);
glLoadMatrixd(projectionMat);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(1.0f, 1.0f, -1.0f);
glMultMatrixd(modelviewMat);
glEnable(GL_LIGHTING);
draw_model();
glDisable(GL_LIGHTING);

【讨论】:

  • 谢谢,但你误解了我想要做的事情。我非常清楚投影矩阵的存储位置(实际上,在 GL_PROJECTION 模式下存储了一个正确的透视投影矩阵)。但是,我的整个代码的目的是通过绘制由透视投影变换的模型来可视化透视投影引入的“失真”。我向你保证我的代码是正确的,并且 - 从几何上 - 实现了我想要的。我唯一的问题是照明。
  • @user1845810:哦,好吧,这当然不能与固定功能管道配合得很好。那么为什么不简单地使用顶点着色器呢?在其中,您可以根据需要进行所有计算,也可以将正常计算与某些“模型视图”矩阵解耦;相反,您传递一个单独的法线变换矩阵,该矩阵派生自尚未投影的模型视图。
  • 遗憾的是,我对 OGL 还很陌生,不知道如何使用顶点着色器。这通常不是问题,但由于我的代码可能会在仅限固定功能的大学作业中使用,我想最好不要使用顶点着色器。
  • @user1845810:请告诉您的教授或助教,固定功能已经过时,并且现在销售的每个硬件至少支持着色器模型 2(顶点和片段着色器),并且大多数野外的 GPU 至少支持着色器模型 3;无论如何,您可以将双投影都放入 GL_PROJECTION 矩阵中,以将法线变换与其解耦。
【解决方案2】:

如果您使用的是固定函数,则必须将所有这些都放在投影矩阵中。 包括投影后发生的缩放、平移和旋转:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glScalef(1.0f, 1.0f, -1.0f);
glMultMatrixd(projectionMat);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixd(modelviewMat);
glEnable(GL_LIGHTING);
draw_model();
glDisable(GL_LIGHTING);

这是可行的,因为位置(即:您所看到的)由投影和模型视图矩阵转换,但 固定功能照明 仅在视图空间中完成(即:在模型视图之后但之前投影)。

事实上,这正是固定函数 GL 区分两个矩阵的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2013-11-26
    • 2011-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多