Python 如何找到OpenGL Vertice的PyGame窗口坐标?

Python 如何找到OpenGL Vertice的PyGame窗口坐标?,python,opengl,pygame,coordinate-transformation,perspectivecamera,Python,Opengl,Pygame,Coordinate Transformation,Perspectivecamera,我试图在pygame窗口中计算出两个矩形顶点的坐标,该窗口使用OpenGL创建3D对象 import pygame from pygame.locals import * import random from OpenGL.GL import * from OpenGL.GLU import * rect1 = [(-5.125,0,-40),(-3.125,0,-40),(-3.125,5,-40),(-5.125,5,-40),] rect2 = [(3.125,0,-40),(5.125

我试图在pygame窗口中计算出两个矩形顶点的坐标,该窗口使用OpenGL创建3D对象

import pygame
from pygame.locals import *
import random
from OpenGL.GL import *
from OpenGL.GLU import *

rect1 = [(-5.125,0,-40),(-3.125,0,-40),(-3.125,5,-40),(-5.125,5,-40),]
rect2 = [(3.125,0,-40),(5.125,0,-40),(5.125,5,-40),(3.125,5,-40)]
edges = ((0,1),(1,2),(2,3),(3,0))

#This draws the rectangles edges
def Target():
    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(rect1[vertex])
    glEnd()
    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(rect2[vertex])
    glEnd()

def main():
    try:
        pygame.init()
        display = (320,240)
        pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
        gluPerspective(45, (display[0]/display[1]), .1, 1000)

        while True:
            #iterates through events to check for quits
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()        
            Target()
            pygame.display.flip()
            pygame.time.wait(100)
            glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)         
    except Exception as e:
        print (e)
main()

如何获取对象的pygame窗口(320240)上的坐标?

投影矩阵描述了从场景的3D点到视口的2D点的映射。它从眼睛空间转换到剪辑空间,剪辑空间中的坐标通过与剪辑坐标的
w
分量相除而转换为标准化设备坐标(NDC)。NDC在(-1,-1,-1)到(1,1,1)之间。

在透视投影中,投影矩阵描述了从针孔相机中看到的世界上的三维点到视口中的二维点的映射
摄影机平截头体(截断棱锥体)中的眼空间坐标映射到立方体(规范化设备坐标)

透视投影矩阵:

r = right, l = left, b = bottom, t = top, n = near, f = far

2*n/(r-l)      0              0                0
0              2*n/(t-b)      0                0
(r+l)/(r-l)    (t+b)/(t-b)    -(f+n)/(f-n)    -1    
0              0              -2*f*n/(f-n)     0
其中:

aspect = w / h
tanFov = tan( fov_y / 2 );

2 * n / (r-l) = 1 / (tanFov * aspect)
2 * n / (t-b) = 1 / tanFov
由于投影矩阵由视野和纵横比定义,因此可以使用视野和纵横比恢复视口位置。前提是它是一个对称的透视投影,其中视野没有被分开(如您的情况)

首先,必须将mose位置转换为标准化设备坐标:

w = with of the viewport
h = height of the viewport
x = X position of the mouse
y = Y position ot the mouse

ndc_x = 2.0 * x/w - 1.0;
ndc_y = 1.0 - 2.0 * y/h; // invert Y axis
然后必须将标准化设备坐标转换为视图坐标:

z = z coodinate of the geometry in view space

viewPos.x = -z * ndc_x * aspect * tanFov;
viewPos.y = -z * ndc_y * tanFov;  

如果要检查鼠标是否悬停在矩形上,则代码可能如下所示:

mpos = pygame.mouse.get_pos()
z = 40

ndc = [ 2.0 * mpos[0]/width - 1.0, 1.0 - 2.0 * mpos[1]/height ]
tanFov = math.tan( fov_y * 0.5 * math.pi / 180 )
aspect = width / height 
viewPos = [z * ndc[0] * aspect * tanFov, z * ndc[1] * tanFov ]

onRect1 = 1 if (viewPos[0]>=rect1[0][0] and viewPos[0]<=rect1[1][0] and viewPos[1]>=rect1[0][1] and viewPos[1]<=rect1[2][1] ) else 0
onRect2 = 1 if (viewPos[0]>=rect2[0][0] and viewPos[0]<=rect2[1][0] and viewPos[1]>=rect2[0][1] and viewPos[1]<=rect2[2][1] ) else 0
你需要一个函数,用投影矩阵变换三维笛卡尔向量。这是通过将向量乘以投影矩阵来实现的,投影矩阵给出了齐次剪辑空间坐标。通过将
x
y
z
分量除以
w
分量来计算归一化设备坐标

def TransformVec3(vecA,mat44):
    vecB = [0, 0, 0, 0]
    for i0 in range(0, 4):
        vecB[i0] = vecA[0] * mat44[0*4+i0] + vecA[1] * mat44[1*4+i0] + vecA[2] * mat44[2*4+i0] + mat44[3*4+i0]
    return [vecB[0]/vecB[3], vecB[1]/vecB[3], vecB[2]/vecB[3]]
以下函数测试鼠标位置是否位于由左下角点和右上角点定义的矩形中(角点必须位于视图空间坐标中):

def TestRec(prjMat、mpos、ll、tr): ll_ndc=TransformVec3(ll,prjMat) tr_ndc=TransformVec3(tr,prjMat) ndc=[2.0*mpos[0]/宽度-1.0,1.0-2.0*mpos[1]/高度]
inRect=1如果(ndc[0]>=ll_ndc[0]和ndc[0]=ll_ndc[1]和ndc[1]=ll_ndc[0]和ndc[0]=ll_ndc[1]和ndc[1]这太棒了。我对如何在pygame框架中近似矩形的位置有点困惑。我希望在pygame框架中得到这些点的(x,y)位置。所以基本上转换(x,y,z)(x,y)中矩形的在我的屏幕上看到的pygame。与其将它们作为标准化的三维设备坐标进行比较,我可以根据鼠标位置进行比较吗?基本上,我正在尝试创建一个包含NDC和pygame窗口坐标的数据集。@goofyreader,但这是第二个soultuion所做的。注意,
pos\u NDC=TransformVec3(pos,prjMat);
pos\u pixel\u xy=[宽度*(pos\u ndc[0]+1.0)/2.0,高度*(1.0-pos\u ndc[1])/2.0]
prjMat = (GLfloat * 16)()
glGetFloatv(GL_PROJECTION_MATRIX, prjMat)
def TransformVec3(vecA,mat44):
    vecB = [0, 0, 0, 0]
    for i0 in range(0, 4):
        vecB[i0] = vecA[0] * mat44[0*4+i0] + vecA[1] * mat44[1*4+i0] + vecA[2] * mat44[2*4+i0] + mat44[3*4+i0]
    return [vecB[0]/vecB[3], vecB[1]/vecB[3], vecB[2]/vecB[3]]
def TestRec(prjMat, mpos, ll, tr):
    ll_ndc = TransformVec3(ll, prjMat)
    tr_ndc = TransformVec3(tr, prjMat)
    ndc = [ 2.0 * mpos[0]/width - 1.0, 1.0 - 2.0 * mpos[1]/height ]
    inRect = 1 if (ndc[0]>=ll_ndc[0] and ndc[0]<=tr_ndc[0] and ndc[1]>=ll_ndc[1] and ndc[1]<=tr_ndc[1] ) else 0
    return inRect
import pygame
from pygame.locals import *
import random
from OpenGL.GL import *
from OpenGL.GLU import *
import math

rect1 = [(-5.125,0,-40),(-3.125,0,-40),(-3.125,5,-40),(-5.125,5,-40),]
rect2 = [(3.125,0,-40),(5.125,0,-40),(5.125,5,-40),(3.125,5,-40)]
edges = ((0,1),(1,2),(2,3),(3,0))

fov_y = 45
width = 320
height = 200

def TransformVec3(vecA,mat44):
    vecB = [0, 0, 0, 0]
    for i0 in range(0, 4):
        vecB[i0] = vecA[0] * mat44[0*4+i0] + vecA[1] * mat44[1*4+i0] + vecA[2] * mat44[2*4+i0] + mat44[3*4+i0]
    return [vecB[0]/vecB[3], vecB[1]/vecB[3], vecB[2]/vecB[3]]

def TestRec(prjMat, mpos, ll, tr):
    ll_ndc = TransformVec3(ll, prjMat)
    tr_ndc = TransformVec3(tr, prjMat)
    ndc = [ 2.0 * mpos[0]/width - 1.0, 1.0 - 2.0 * mpos[1]/height ]
    inRect = 1 if (ndc[0]>=ll_ndc[0] and ndc[0]<=tr_ndc[0] and ndc[1]>=ll_ndc[1] and ndc[1]<=tr_ndc[1] ) else 0
    return inRect


#This draws the rectangles edges
def Target():

    prjMat = (GLfloat * 16)()
    glGetFloatv(GL_PROJECTION_MATRIX, prjMat)

    mpos = pygame.mouse.get_pos()
    onRect1 = TestRec(prjMat, mpos, rect1[0], rect1[2])
    onRect2 = TestRec(prjMat, mpos, rect2[0], rect2[2])

    glColor3f( 1, 1-onRect1, 1-onRect1 )
    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(rect1[vertex])
    glEnd()

    glColor3f( 1, 1-onRect2, 1-onRect2 )
    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(rect2[vertex])
    glEnd()

def main():
    try:
        pygame.init()
        display = (width,height)
        pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
        glMatrixMode(GL_PROJECTION)
        gluPerspective(fov_y, (display[0]/display[1]), .1, 1000)
        glMatrixMode(GL_MODELVIEW)

        while True:
            #iterates through events to check for quits
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()        
            Target()
            pygame.display.flip()
            pygame.time.wait(100)
            glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)         
    except Exception as e:
        print (e)
main()