为OpenGL Gouraud阴影提供带有三角形条和扇形的法线

时间:2014-12-01 17:27:15

标签: c++ opengl

我是Open GL的新手,我对Gouraud阴影有点困惑。我主要处理共面三角形。 我理解的是,在Gouraud阴影中,我必须为三个顶点中的每一个找到法线,然后在推顶点之前我必须推动它的法线。


    glNormal3d(nx1.x, nx1.y, nx1.z);
    glVertex3d(x1.x, x1.y, x1.z);

通过对相邻三角形的面法线求平均来获得法线。 现在,让我们假设我想绘制一个锥体,以n-gon为基础。对于基础,我使用triangle_fan并且所有三角形都具有相同的正常权利?那么,我如何推动法线?我只计算一个法线,我用它来表示所有三角形?或者我还有计算每个顶点的法线?我也希望在锥体的顶部使用Gouraud阴影(这些三角形也被定义为triangle_fan),但似乎不起作用,为什么?我改变了单个三角形以便能够使用Gouraud。

现在,我想创建一个圆柱体,两个n-gons作为顶面和底面。对于侧面,我使用triangle_strips,对于底座,我使用三角扇。所以,侧面像:


    *--------*
    |\       |
    | \      |
    |  \     |
    |   \    |
    |    \   |
    |     \  |
    |      \ |
    |       \|
    *--------*   

现在,我有与上述相同的问题。对于底座中的Gouraud阴影,是否足以使用单个法线?对于横向三角形的Gourdaud阴影,两个三角形具有相同的法线,我是否应该对它们使用相同的?

2 个答案:

答案 0 :(得分:1)

绘制圆锥有点复杂。顶部顶点的每个相邻三角形必须具有不同的法线。那是因为顶点没有明确定义的“表面”(无限小而扁平)。

将圆锥视为圆柱体,但顶部半径为0。

因此,要绘制圆锥体,您需要复制顶部顶点n次,每次都有不同的法线,并且您不能使用三角形扇形(因为每个顶点都有不同的顶点)三角形)。

基本上,如果顶点不是连续曲面的一部分,并且圆锥顶部不连续,则需要复制顶点。另一方面,球体的表面是连续的,所以在这里你可以简单地平均脸部的法线(就像你解释的那样)。立方体的角不是,需要用三个不同的法线绘制。 (只是给你一些其他的例子。)

答案 1 :(得分:1)

@leemes在前一个答案中涵盖了特定的气缸外壳。但是我想从你的问题中找到一个更通用的项目:

  

通过平均相邻三角形的面法线来获得法线。

这通常是你应该做的事情。如果模型基于分析曲面,则需要计算表面的法线以获取法线向量。分析表面的典型示例包括:

  • 几何形状,如球形,圆锥形,圆环形等。
  • 样条曲面。

您将使用这些曲面的三角剖分进行OpenGL渲染。这种三角测量是近似表面。如果将法线计算为相邻三角形法线的平均值,则这些法线也是近似于曲面法线的近似值。除非您的曲面具有非常小的曲率,或者您使用非常精细的曲面细分,否则这些近似法线远不及实际曲面法线。

这不仅仅是理论。具有法线计算为平均值的表面大多看起来很粗糙。您可以尝试通过将三角形的大小或相邻角度考虑进行平均来改进近似。但它始终是真实事物的近似值。

幸运的是,我们可以计算分析曲面的实际曲面法线。通常,这很容易。

  • 例如,球体是微不足道的。法向量与从中心到顶点的归一化向量相同。您通常甚至不需要单独的法向量。对于以原点为中心的半径为1.0的球体,顶点和法线具有完全相同的坐标。因此,您可以计算单位球体的顶点,直接将它们用作法线,并获得与所需位置和半径匹配的平移/缩放的最终顶点。

  • 对于您的锥形示例,您还可以通过几个纸质草图直观地推导出法线。但为了说明更通用的计算方法,让我们进行计算。

许多曲面由基于两个参数的参数方程表示。这可能是你计算锥顶点的方法。

在xy平面上取一个圆锥体,底边的半径为r,高度为h,尖端位于正z轴上。然后,您将顶点计算为:

(a = 0..2*pi, t = 0..h)

          ( r * cos(a) * (h - t) / h )
f(a, t) = ( r * sin(a) * (h - t) / h )
          ( t                        )

对于这样的参数曲面,法线可以计算为两个梯度的叉积。首先计算两个梯度向量:

        ( -r * sin(a) * (h - t) / h )
df/da = (  r * cos(a) * (h - t) / h )
        ( 0                         )

        ( -r * cos(a) / h )
df/dt = ( -r * sin(a) / h )
        ( 1               )

现在我们可以计算出这两个向量的叉积:

( r * cos(a) * (h - t) / h  )
( r * sin(a) * (h - t) / h  )
( r * r * (h - t) / (h * h) )

由于无论如何我们必须对这个向量进行标准化,我们可以摆脱一些常见的因素,这将它简化为:

( cos(a) )
( sin(a) )
( r / h  )

这具有直观意义。它从中心向外指向与顶点相同的方向,并且它在z方向上越来越多,半径越大,高度越小。

通过另一次轻微操作(我们仍然不关心幅度),这可以写成:

( h * cos(a) )
( h * sin(a) )
( r          )

现在需要将其标准化。长度变为:

sqrt(h * h + r * r)

对于所有顶点,方便地相同。所以我们可以计算一次比例因子:

s = 1 / sqrt(h * h + r * r)

每个点的法向量计算如下:

( s * h * cos(a) )
( s * h * sin(a) )
( s * r          )

这显然比圆柱体需要更复杂,但它应该有助于说明可以应用于更复杂表面的一般过程。

平均法线的方法只应在你拥有的只是网格时使用,并且无法获得更多信息来计算正常法线。