OpenGL自定义变换麻烦
我正在尝试通过投影变换投射阴影。但 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}
是不是有人觉得很熟悉?或者这只是一个代码问题?
编辑:我正在尝试做这个测试,即使用和不使用矩阵(对于 xz 平面和 {0, 20, 0} 聚光灯)以及正交投影矩阵来绘制单个顶点。另外,我试图通过获取 OpenGL 的投影和模型视图矩阵并将其与它们相乘,然后使用 w 坐标进行标准化,来计算自己该顶点的标准化设备坐标。
我得到的是,如果没有我的“阴影矩阵”,它可以很好地显示该点,并且我对顶点的计算似乎与我所看到的相匹配。但是通过我的“阴影矩阵”,尽管顶点的坐标位于所有轴上的 [-1,1] 范围内,但我什么也没得到。
这太奇怪了...
编辑:在这里添加了测试程序: https://gist.github.com/e0c54d5ab3cbc92dffe6< /a>
I am trying to cast a shadow with a projection transformation. But it seems that OpenGL doesn't like my matrix as it does not draw anything after glMultMatrix
. After I pop my matrix everything's ok.
I'm also using JOGL, maybe the problem's with that, but I doubt it since my custom translation and rotation matrices work fine.
The matrix looks like this:
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
Now this is a matrix which I calculated, but I also used two other flavors I searched for on the internet; one a bit different, and another which is exactly like mine times -1.
Is this enough information? Or should I submit code also?
Maybe it's my plane equation?
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}
Does it sound familiar to anyone? Or it's just a code thing?
EDIT: There's this test that I'm trying to do, and that to draw a single vertex point with and without the matrix (for an x-z plane and a {0, 20, 0} spot light), and with an orthogonal projection matrix. Also, I'm trying to calculate myself the normalized device coordinates of that vertex by getting OpenGL's projection and model view matrices and multiplying it with them, and normalizing with the w coordinate.
What I get is that without my "shadow matrix" it displays the point nicely and it seems my calculations of the vertex match what I'm seeing. But with my "shadow matrix" I get nothing, although the vertex's coordinates lie within the [-1,1] range on all axes.
This is just too strange...
EDIT: added test program here: https://gist.github.com/e0c54d5ab3cbc92dffe6
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可能只是转置了传递给 OpenGL 的矩阵。 OpenGL 的矩阵索引一开始有点违反直觉(不过,如果您将矩阵理解为列向量的行向量,那么这是有道理的)OpenGL 索引如下:
与 C 行主要排序相反
It may, that you simply transposed the matrix passed to OpenGL. OpenGL's matrix indexing is a bit counterintuitive at first (it makes sense though, if you understand the matrix as a row vector of column vectors) OpenGL indices the following:
In contrast to the C row major ordering
想通了(这是问题的作者)。这只是一个错字,我没有计算出飞机的法线方向正确......
这不像我说的那样(v0 X v1),而是偶然的(v1 X v0)。你可以在代码中看到它。因此,如果飞机的方向相反,则无法在其上投影。
因为这是一个愚蠢的错误。对于所有想了解平面上矩阵投影背后的数学原理的人,我将尝试解释一下:
在开始之前,我假设您对线性代数有一些粗略的了解。不需要太多。
假设我们有一个法线为 N 的平面,其上有一个点 Q。对于每个点 P,
(PQ).N=0
(即点积)当(且仅当)P 在平面上时,因为向量(PQ)
和 N 垂直。现在假设我们还有一个(固定聚光灯)点 S。我们想从该聚光灯在平面上投影一个点 P。这意味着我们想要找到点 R,它位于点 P 和 S 定义的直线上的某个位置,并且也在平面上。换句话说,找到一个标量 t,使得 S+t(PS)=R,使得 R 在平面上。
(PS)
是从聚光灯穿过点 P 的方向向量。我们在该向量上“行走”一定量 t,从点 S 开始,直到落在平面上。从前两段中,我们学到了一个很好的技巧来知道一个点是否在平面上。因此,如果我们将其应用到 R 上,我们会得到 R 在平面上,当(且仅当):
现在,如果我们将其放回到 R 的定义中:
让我们将 N.(PS) 定义为让
我们提醒自己我们知道什么,不知道什么,以及我们想知道什么。我们知道 N、Q 和 S。P 已给我们,我们想找到 R。换句话说,我们想在给定 P 的情况下表达 R,并使用 N、Q 和 S。让我们继续对此进行分解此外,
R 是点,所以让我们用 P 的坐标来定义它的每个坐标(还有 S,因为我们也将他放在等式的右侧)。
看起来我们什么也没得到,因为我们在左侧得到了 k,而且我们仍然需要除以它(而且 k 仍然由 P 定义!)。不用担心,因为 OpenGL 使用四个元素向量而不是三个。最后第四个元素用于平移矩阵和透视深度插值。对于我们现在的需求,我们应该知道的是 openGL 将每个顶点的坐标除以它的第四个元素。这意味着可怕的 k 是我们的第四个元素。我们得到:
好吧,我们使用 N、S 和 Q 通过 P 定义了 R。让我们将其放入矩阵 M 中。我们想要:
M*P=R
所以,
在盯着这个时,请记住,因为 P 是一个点,所以它是第四个元素是 1。(!=0,准确地说,但我们可以假设它是设备标准化顶点)
关于平面方程。平面方程是一个向量,其前三个元素为法线。它的第四个元素是它距原点的有符号距离。计算平面到原点距离的另一种方法是:
给定平面上法线为 N 的点 Q,平面到原点的距离为 |NQ|
很简单,对吧?这是正确的,因为 :
和
|N|=1
给我们:其中 d 是从原点到平面的距离。或者,它是向量N的大小; N的大小是从原点到平面的距离的大小。您可以看到,通过绘制平面,在平面上选择某个点 Q,绘制从原点延伸到平面的法线 N,然后查看由两个向量和平面所形成的线组成的三角形。
在上面的矩阵中,将 -NQ 替换为 d(平面方程中的最后一个元素),然后就完成了。 (d = -NQ)。给定点 P 的矩阵将把它从 S 定义的聚光灯投影到 N 和 Q 定义的平面上。
希望这能教给你一些新东西。如果我犯了错误,请发表评论,我会修复它。
Figured it out (this is the author of the question). It was just a typo, I didn't calculate the plane's normal in the right direction...
It's not like I said it to be (v0 X v1) it was accidentally (v1 X v0). You can see it in the code. So, if the plane is directed the other way, you can't project on it.
Because it's a silly mistake like that. For all you wanting to know the math behind this matrix projection on a plane, I'll try to explain it:
Before I begin, I assume a little rough knowledge of linear algebra. Not much is needed.
Let's say we have a plane with normal N, with a point Q on it. For every point P,
(P-Q).N=0
(that's a dot product) if (and only if) P is on the plane, since the vectors(P-Q)
and N are perpendicular.Now let's assume we also have a (fixed spot light) point S. We would like to project a point P on our plane from that spot light. This means we would like to find the point R, that is somewhere on the line defined by the points P and S, and that is also on the plane. In other words, find a scalar t, such that
S+t(P-S)=R
, such that R is on the plane.(P-S)
is the direction vector from the spot light through the point P. We "walk" on that vector a certain amount t, starting from the point S until we land on the plane.From 2 paragraphs ago, we learned a nice trick to know if a point is on the plane or not. So if we apply that on R we get that R is on the plane if (and only if):
Now, if we put this back in the definition of R:
Let's define
N.(P-S)
to be kLet's remind ourselves what we know, and what we don't know, and what we want to know. We know N and Q and S. P is given to us, and we would like to find R. In other words, we would like to express R given P, and using N, Q and S. Let's continue breaking this down a bit further,
R is point, so let's define each of its coordinates, with the coordinates of P (and also S because we also have him on the right side of the equation there).
It may seem like we didn't get anything, since we got that k on our left side, and we still need to divide by it (and that k is defined by P none the less!). Not to worry, because OpenGL uses four element vectors and not three. That last fourth element is used for translation matrices and perspective depth interpolation. For our needs right now, all we should know is that openGL divides the coordinates of each vertex by it's fourth element. This means is that that dreaded k is our fourth element. we get:
Alright, we defined our R through P, using N, S and Q. Let's put that in a matrix M. We want:
M*P=R
So,
While staring at this, remember that since P is a point it's fourth element is 1. (!=0, to be precise but we can assume it's a device normalized vertex)
About the plane equation. The plane equation is a vector, which has its first three elements as the normal. And its fourth element is its signed distance from the origin. Another way to calculate the distance of the plane from the origin is:
Given a point Q on the plane with normal N, the plane's distance from the origin is |N.Q|
Pretty simple, right? This is correct since :
and
|N|=1
, giving us:where d is the distance to the plane from the origin. Or, it's the size of the vector N; and N's magnitude is the size of the distance to the plane from the origin. You can see that by drawing the plane, choosing some point Q on the plane, drawing the normal N reaching out to the plane from the origin, and looking at the triangle made from the lines made by the two vectors and the plane.
In the above matrix replace -N.Q with d (the last element in the plane equation) and you're done. (d = -N.Q). That matrix given point P, will project it onto the plane defined by N and Q, from the spot light defined by S.
Hope that teaches you something new. If I made a mistake, comment and I'll fix it.