【问题标题】:OpenGL custom transformation troubleOpenGL自定义转换麻烦
【发布时间】:2011-10-01 14:25:46
【问题描述】:

我正在尝试使用投影变换投射阴影。但似乎 OpenGL 不喜欢我的矩阵,因为它在glMultMatrix 之后没有绘制任何东西。弹出矩阵后,一切正常。 我也在使用 JOGL,可能是这个问题,但我对此表示怀疑,因为我的自定义平移和旋转矩阵工作正常。

矩阵如下所示:

lightPosition = {x, y, z, 1}
planeEquation = {a, b, c, d}
pl = a*x + b*y + c*z + d

a*x-pl  b*x     c*x     d*x
a*y     b*y-pl  c*y     d*y
a*z     b*z     c*z-pl  d*z
a       b       c       d-pl

现在这是我计算的矩阵,但我还使用了我在互联网上搜索的其他两种口味;一个有点不同,另一个和我的时间 -1 完全一样。 这是足够的信息吗?还是我也应该提交代码?

也许这是我的平面方程?

three points on plane = p0, p1, p2

v0 = p1 - p0
v1 = p2 - p0

n = {a, b, c} = v0 (cross) v1
d = -(n (dot) p0)

planeEquation = {a, b, c, d}

有没有人觉得很熟悉?还是只是代码?

编辑:我正在尝试进行此测试,并使用和不使用矩阵(对于 x-z 平面和 {0, 20, 0} 聚光灯)绘制单个顶点,并使用正交投影矩阵。此外,我正在尝试通过获取 OpenGL 的投影和模型视图矩阵并将其与它们相乘,并使用 w 坐标进行归一化,从而为自己计算出该顶点的归一化设备坐标。

我得到的是,没有我的“阴影矩阵”,它可以很好地显示点,而且我对顶点的计算似乎与我所看到的相匹配。但是对于我的“阴影矩阵”,我什么也得不到,尽管顶点的坐标位于所有轴上的 [-1,1] 范围内。

这太奇怪了……

编辑:在此处添加测试程序:https://gist.github.com/e0c54d5ab3cbc92dffe6

【问题讨论】:

    标签: opengl transformation jogl


    【解决方案1】:

    您可能只是将传递给 OpenGL 的矩阵转置。 OpenGL 的矩阵索引起初有点违反直觉(不过,如果您将矩阵理解为列向量的行向量,这很有意义)OpenGL 索引如下:

    0 4 8 c
    1 5 9 d
    2 6 a e
    3 7 b f
    

    相对于C排大调

    0 1 2 3 
    4 5 6 7
    8 9 a b
    c d e f
    

    【讨论】:

    • 感谢您的回复,不过我已经检查过了...(尝试打开和关闭转置)
    【解决方案2】:

    想通了(这是问题的作者)。这只是一个错字,我没有计算飞机在正确方向上的法线...... 这不像我说的那样(v0 X v1)它是偶然的(v1 X v0)。您可以在代码中看到它。所以,如果飞机是相反的方向,你就不能在上面投影。

    因为这是一个愚蠢的错误。对于所有想知道平面上的矩阵投影背后的数学的人,我将尝试对其进行解释:

    在开始之前,我假设对线性代数有一点粗略的了解。不需要太多。

    假设我们有一个带有法线 N 的平面,上面有一个点 Q。对于每个点 P,当(且仅当)P 在平面上时,(P-Q).N=0(这是一个点积),因为向量 (P-Q) 和 N 是垂直的。

    现在假设我们还有一个(固定聚光灯)点 S。我们想从那个聚光灯在我们的平面上投影一个点 P。这意味着我们希望找到点 R,它位于由点 P 和 S 定义的直线上的某处,并且也在平面上。换句话说,找到一个标量 t,使得S+t(P-S)=R,使得 R 在平面上。 (P-S) 是从聚光灯经过点 P 的方向向量。我们在该向量上“行走”一定量 t,从点 S 开始,直到我们降落在平面上。

    从两段前,我们学到了一个很好的技巧来判断一个点是否在平面上。因此,如果我们在 R 上应用它,我们会得到 R 在平面上当(且仅当):

    N.(R-Q)=0  
    N.R-N.Q=0  
    N.R=N.Q  
    N.(S+t(P-S))=N.Q  
    N.S+tN.(P-S)=N.Q  
    t=(N.Q-N.S)/(N.(P-S))
    

    现在,如果我们把它放回 R 的定义中:

    R=S+(N.Q-N.S)*(1/(N.(P-S))*(P-S)
    

    让我们将N.(P-S)定义为k

    kR=(N.(P-S))*S+(N.Q-N.S)*P-(N.Q-N.S)*S  
    kR=(N.P)*S+(N.Q-N.S)*P-(N.Q-N.S)*S-(N.S)*S    
    kR=(N.P)*S+(N.Q-N.S)*P-(N.Q)*S  
    

    让我们提醒自己我们知道什么,我们不知道什么,以及我们想知道什么。我们知道 N 和 Q 和 S。P 给了我们,我们想找到 R。换句话说,我们想表达 R 给定 P,并使用 N、Q 和 S。让我们继续分解一下进一步,

    kR=(N_x*P_x+N_y*P_y+N_z*P_z)*S+(N.Q-N.S)*P-(N.Q)*S
    

    R 是点,所以让我们用 P 的坐标来定义它的每一个坐标(还有 S,因为他也在等式的右边)。

    kR_x=[N_x*S_x+(N.Q-N.S)]P_x+[N_y*S_x]P_y+[N_z*S_x]P_z-(N.Q)*S_x
    kR_y=[N_x*S_y]P_x+[N_y*S_y+(N.Q-N.S)]P_y+[N_z*S_y]P_z-(N.Q)*S_y  
    kR_z=[N_x*S_z]P_x+[N_y*S_z]P_y+[N_z*S_z+(N.Q-N.S))]P_z-(N.Q)*S_z  
    

    看起来我们没有得到任何东西,因为我们得到了左边的 k,我们仍然需要除以它(而且 k 是由 P 定义的!)。不用担心,因为 OpenGL 使用四个元素向量而不是三个。最后第四个元素用于平移矩阵和透视深度插值。对于我们现在的需求,我们只需要知道 openGL 将每个顶点的坐标除以它的第四个元素。这意味着可怕的 k 是我们的第四个元素。我们得到:

    R_w=k  
    R_w=N.(P-S)  
    R_w=N.P-N.S  
    R_w=[N_x]P_x+[N_y]P_y+[N_z]P_z-N.S  
    

    好的,我们通过 P 定义了我们的 R,使用 N、S 和 Q。让我们把它放在一个矩阵 M 中。我们想要:

    M*P=R

    所以,

    M=
    N_x*S_x + (N.Q-N.S),  N_y*S_x,             N_z*S_x,             -(N.Q)*S_x 
    N_x*S_y,              N_y*S_y + (N.Q-N.S), N_z*S_y,             -(N.Q)*S_y
    N_x*S_z,              N_y*S_z,             N_z*S_z + (N.Q-N.S), -(N.Q)*S_z
    N_x,                  N_y,                 N_z,                 -(N.S)
    

    看着这个,请记住,因为 P 是一个点,所以它的第四个元素是 1。(准确地说,!=0,但我们可以假设它是一个设备标准化顶点)

    关于平面方程。平面方程是一个向量,它的前三个元素作为法线。它的第四个元素是它与原点的有符号距离。另一种计算平面到原点距离的方法是:

    给定平面上的点Q,法线为N,平面到原点的距离为|N.Q|

    很简单,对吧?这是正确的,因为:

    N.Q=|N|*|Q|*cos(N,Q) 
    

    |N|=1,给我们:

    N.Q=|Q|*cos(N,Q)=|Q|*d/|Q|=d
    

    其中 d 是从原点到平面的距离。或者,它是向量 N 的大小; N的大小是从原点到平面的距离的大小。您可以通过绘制平面,选择平面上的某个点 Q,绘制从原点延伸到平面的法线 N,并查看由两个向量和平面组成的线组成的三角形。

    在上面的矩阵中,将 -N.Q 替换为 d(平面方程中的最后一个元素),就完成了。 (d = -N.Q)。给定点 P 的矩阵会将其从 S 定义的聚光灯投射到 N 和 Q 定义的平面上。

    希望能教会你一些新的东西。如果我犯了错误,请发表评论,我会修复它。

    【讨论】:

      猜你喜欢
      • 2021-04-04
      • 2013-09-19
      • 1970-01-01
      • 1970-01-01
      • 2011-07-03
      • 2010-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多