我正在尝试将几个3d点投射到屏幕坐标,以确定触摸是否发生在大致相同的区域。应该注意的是,我在Kivy中这样做,这是Python和OpenGL。我见过问题like this,但我仍然没有解决方案。我尝试了以下内容,但数字并不接近屏幕坐标。
def to2D(self, pos, width, height, modelview, projection):
p = modelview*[pos[0], pos[1], pos[2], 0])
p = projection*p
a = p[0]
b = p[1]
c = p[2]
a /= c
b /= c
a = (a+1)*width/2.
b = (b+1)*height/2.
return (a, b)
为了说明这不会产生好的结果,请采用以下参数
modelview = [[-0.831470, 0.553001, 0.053372, 0.000000],
[0.000000, 0.096068, -0.995375, 0.000000],
[-0.555570, -0.827624, -0.079878, 0.000000],
[-0.000000, -0.772988, -2.898705, 1.000000]]
projection = [[ 15.763722, 0.000000, 0.000000, 0.000000],
[ 0.000000, 15.257052, 0.000000, 0.000000],
[ 0.000000, 0.000000, -1.002002, -2.002002],
[ 0.000000, 0.000000, -1.000000, 0.000000]]
pos = [0.523355213060808, -0.528964010275341, -0.668054187020413] #I'm working on a unit sphere, so these are more meaningful in spherical coordinates
width = 800
height = 600
使用这些参数,to2D
给出的屏幕坐标为(1383,-274)
我不认为这个问题与OpenGL和python有关,而是与从3D到屏幕坐标的操作有关。 我正在尝试做什么:当触摸发生时,将3d点投影到2d屏幕坐标。
我的想法: 拿相机的模型视图和投影矩阵,我感兴趣的点和触摸位置,然后制作一个从点到触摸位置的方法。通过将this source code for gluProject转换为Python
来获取方法我是怎么做到的:
将所有数学对象带入Sage以简化计算。
我的触摸位置是(150,114.1)
modelview = matrix([[ -0.862734, 0.503319, 0.048577, 0.000000 ],
[ 0.000000, 0.096068, -0.995375, 0.000000 ],
[ -0.505657, -0.858744, -0.082881, 0.000000 ],
[ 0.000000, -0.772988, -2.898705, 1.000000 ]])
projection = matrix([[ 15.763722, 0.000000, 0.000000, 0.000000 ],
[ 0.000000, 15.257052, 0.000000, 0.000000 ],
[ 0.000000, 0.000000, -1.002002, -2.002002 ],
[ 0.000000, 0.000000, -1.000000, 0.000000 ]])
width = 800.
height = 600.
v4 = vector(QQ, [0.52324, -0.65021, -0.55086, 1.])
p = modelview*v4
p = projection*p
x = p[0]
y = p[1]
z = p[2]
w = p[3]
x /= w
y /= w
z /= w
x = x*0.5 + 0.5
y = y*0.5 + 0.5
z = z*0.5 + 0.5
x = x*width
y = y*height #There's no term added because the widget is located at (0, 0)
结果:
x = 15362.18
y = -6251.43
z = 10.14
修订:由于这甚至没有结束,我回到了第8步和第9步,并改变了乘法的顺序,看看会发生什么。所以现在8.是p = v4*modelview
,而9.是p = p*projection
。在这种情况下,矢量是行矢量。查看此内容的另一种方法是p = modelviewTranspose*v4
和p = projectionTranspose*p
,其中向量是列向量。
结果第2部分:
x = 150.29
y = 196.15
z = 0.6357
回想一下,目标是(150,114.1)。 x坐标非常好,但y坐标不是。所以我看了y*z
,即124.69。我可以忍受这个答案,虽然我不确定看y*z
是不是我应该做的事情
答案 0 :(得分:5)
第一个问题在这里:
p = modelview*[pos[0], pos[1], pos[2], 0])
当您使用矩阵作为4分量向量的多个向量时,最后一个组件(w
)必须为1.0
另一个在这里:
c = p[2]
a /= c
b /= c
不是将x和y除以z,而应将x,y和z除以w。 w是p [4]。
除此之外:
如有疑问,请找到gluProject
和gluUnproject
的源代码,将其拆分并转换为python。
据我所知,当手动将矢量投影到屏幕上时,你应该做以下事情:
转换"位置" 4 组件向量,.w组件设置为1。
v4.x = v3.x
v4.y = v3.y
v4.z = v3.z
v4.w = 1.0
按矩阵乘以4分量。
然后用w。
划分所有组件v4.x /= v4.w
v4.y /= v4.w
v4.z /= v4.w
然后,您将获得x和y的+ -1.0范围内的屏幕坐标。 (z将在0.0..1.0或0.0 ..- 1.0之内,我忘了在OpenGL的情况下)。
w之所以发挥作用是因为你不能通过矩阵乘法来划分,所以当你需要将x / y / z除以某个东西时,你将它放入w分量中,然后执行除法矩阵乘法。 w也使翻译矩阵成为可能。任何w == 0的向量都不能使用平移矩阵进行平移,只能围绕原点旋转并使用仿射变换进行变形("原点"表示坐标空间的零点 - (0.0,0.0,0.0)点)
P.S。此外,我不知道python如何处理整数到浮动转换,但我将a = (a+1)*width/2
替换为a = (a+1.0)*width/2.0
以明确指定您在此处使用浮点数。 / p>
答案 1 :(得分:0)
如果您有权访问它,pyopengl的gluProject(x, y, z)
会返回当前上下文的屏幕空间x,y,z坐标。 (其他实现可能需要更多参数并设置指针而不是返回!)