如何在python / pyglet中正确使用gluUnProject?

时间:2019-01-03 11:45:02

标签: python-3.x opengl pyglet

我正在尝试让gluUnProject在pyglet中工作,以获取鼠标相对于背景的位置(通过glTranslatefglScalef移动鼠标)。这是我所拥有的,虽然它给了我一个位置,但它不是正确的位置:

def mouse_unproject(x,y):
    pmat = (pyglet.gl.GLdouble * 16)()
    mvmat = (pyglet.gl.GLdouble * 16)()
    view = (pyglet.gl.GLint * 4)()
    px = (pyglet.gl.GLdouble)()
    py = (pyglet.gl.GLdouble)()
    pz = (pyglet.gl.GLdouble)()
    pyglet.gl.glGetDoublev(pyglet.gl.GL_MODELVIEW_MATRIX, mvmat)
    pyglet.gl.glGetDoublev(pyglet.gl.GL_PROJECTION_MATRIX, pmat)
    pyglet.gl.glGetIntegerv(pyglet.gl.GL_VIEWPORT, view)
    pyglet.gl.gluUnProject(x, y, 0, mvmat, pmat, view, px, py, pz)
    return (px.value,py.value)

整个源代码:

from pyglet.image.codecs.png import PNGImageDecoder
from pyglet.window import key, mouse
from ship import Ships
import pyglet
import numpy as np
import csv

def mouse_unproject(x,y):
    pmat = (pyglet.gl.GLdouble * 16)()
    mvmat = (pyglet.gl.GLdouble * 16)()
    view = (pyglet.gl.GLint * 4)()
    px = (pyglet.gl.GLdouble)()
    py = (pyglet.gl.GLdouble)()
    pz = (pyglet.gl.GLdouble)()
    pyglet.gl.glGetDoublev(pyglet.gl.GL_MODELVIEW_MATRIX, mvmat)
    pyglet.gl.glGetDoublev(pyglet.gl.GL_PROJECTION_MATRIX, pmat)
    pyglet.gl.glGetIntegerv(pyglet.gl.GL_VIEWPORT, view)
    pyglet.gl.gluUnProject(x, y, 0, mvmat, pmat, view, px, py, pz)
    return (px.value,py.value)

class Game:
    def __init__(self):
        self.pause = False
        self.ships = []

class Overlay:
    def __init__(self):
        self.radar = pyglet.sprite.Sprite(img=pyglet.image.load('pictures/radar.png',decoder=PNGImageDecoder()))
        self.radar_indicator = pyglet.sprite.Sprite(img=pyglet.image.load('pictures/radar_indicator.png',decoder=PNGImageDecoder()))
        self.radar.update(x=1014,y=630)
        self.radar.opacity = 200
        self.indicator_scale = 1

    def draw(self,ships,scale):
        d = 25 * scale

        self.radar.draw()

        for s in ships:
            x = (((s.icon.x)//d)+1019)
            y = (((s.icon.y)//d)+635)
            pyglet.graphics.draw(4,pyglet.gl.GL_QUADS,('v2f',(x-1,y-1,x+2,y-1,x+2,y+2,x-1,y+2)),('c3B',(0,255,0,0,255,0,0,255,0,0,255,0)))

class Background:
    def __init__(self):
        self.image = pyglet.image.load('pictures/star_background.png',decoder=PNGImageDecoder())
        self.scale = 1
        self.up = False
        self.down = False
        self.right = False
        self.left = False
        self.speed = 15
        self.translation= [0,0]
        self.total_scale = 1

window = pyglet.window.Window(1280,800)
ship_classes = {}

with open('shipclasses.csv',mode='r') as csv_file:
    line_counter = 0
    csv_reader = csv.reader(csv_file)
    for row in csv_reader:
        if not line_counter == 0:
            index = 0
            class_dic = {}
            for atr in row:
                class_dic[headers[index]] = atr
                index += 1
            ship_classes[row[0]] = class_dic
        else:
            headers = row
        line_counter += 1
print(ship_classes)

stars = Background()
player = Ships(True,(640,400),False,ship_classes['Valkyrie'])
keys = key.KeyStateHandler()
window.push_handlers(keys)
game = Game()
game.ships.append(player)
overlay = Overlay()
pause_text = pyglet.text.Label('PAUSE',font_name='Times New Roman',font_size=30,x=window.width//2, y=(window.height * 2)//3,anchor_x='center', anchor_y='center')

@window.event
def update(dt):
    for s in game.ships:
        s.update(dt)
pyglet.clock.schedule_interval(update, 0.02)

@window.event
def background_motion(dt):
    if stars.left:
        pyglet.gl.glTranslatef(stars.speed, 0, 0)
        stars.translation[0] += stars.speed
    if stars.right:
        pyglet.gl.glTranslatef(-stars.speed, 0, 0)
        stars.translation[0] -= stars.speed
    if stars.up:
        pyglet.gl.glTranslatef(0, -stars.speed, 0)
        stars.translation[1] -= stars.speed
    if stars.down:
        pyglet.gl.glTranslatef(0, stars.speed, 0)
        stars.translation[1] += stars.speed
pyglet.clock.schedule_interval(background_motion, 0.05)

@window.event
def on_mouse_scroll(x, y, scroll_x, scroll_y):
    if scroll_y > 0:
        stars.scale += 0.01
        stars.total_scale += 0.01

    elif scroll_y < 0:
        stars.scale -= 0.01
        stars.total_scale -= 0.01

@window.event
def on_mouse_press(x, y, button, modifiers):
    if button == mouse.RIGHT and player.course_setting:
        player.heading = (x,y)
        player.course_setting = False
        player.course = True
        player.update(0)

@window.event
def on_mouse_motion(x, y, dx, dy):
    if player.course_setting:
        player.projected_heading = mouse_unproject(x,y)

@window.event
def on_key_press(symbol, modifiers):
    if symbol == key.SPACE:
        if game.pause:
            game.pause = False
        else:
            game.pause = True

    elif symbol == key.W:
        stars.up = True

    elif symbol == key.S:
        stars.down = True

    elif symbol == key.D:
        stars.right = True

    elif symbol == key.A:
        stars.left = True

    elif symbol == key.C:
        if player.course_setting:
            player.course_setting = False
        else:
            player.course_setting = True
            player.update_projected()

    elif symbol == key.V:
        if player.course_setting:
            if player.max_v:
                player.max_v = False
            else:
                player.max_v = True

        elif player.course:
            if player.course_max_v:
                player.course_max_v = False
            else:
                player.course_max_v = True

@window.event
def on_key_release(symbol, modifiers):
    if symbol == key.W:
        stars.up = False

    elif symbol == key.S:
        stars.down = False

    elif symbol == key.D:
        stars.right = False

    elif symbol == key.A:
        stars.left = False

@window.event
def on_draw():
    window.clear()

    pyglet.gl.glScalef(stars.scale,stars.scale, 1, 1)

    stars.image.blit(0,0)
    for s in game.ships:
        s.draw()

    pyglet.gl.glPushMatrix()
    pyglet.gl.glLoadIdentity()

    #HUD Start
    overlay.draw(game.ships,stars.scale)
    if game.pause:
        pause_text.draw()
    #HUD End

    pyglet.gl.glPopMatrix()
    stars.scale = 1

if __name__ == '__main__':
    pyglet.app.run()

运送文件:

from pyglet.image.codecs.png import PNGImageDecoder
import pyglet
import numpy as np

class Ships:
    def __init__(self,player_ship,position,hostile,Class):
        self.velocity_vector = [0,0]
        self.Class = Class['Class Name']
        self.type = Class['Type']
        self.health = int(Class['Health'])
        self.shield = int(Class['Shield'])
        self.acelleration_magnitude = (float(Class['Acceleration(g)']) * 9.8) / 20000
        self.acelleration_angle = 0
        self.acelleration_vector = [0,0]
        self.alive = True
        self.player_ship = player_ship
        self.hostile = hostile
        self.velocity_magnitude = 0
        self.course = False
        self.heading = position
        self.course_setting = False
        self.target_velocity = 25
        self.velocity_angle = 0
        self.projected_heading = position
        self.displacement_vector = list(position)
        self.max_v = False
        self.course_max_v = False
        self.scale_factor = 1

        if not self.hostile:
            course_icon = pyglet.image.load('pictures/friendly_course_icon.png',decoder=PNGImageDecoder())
            course_icon.anchor_x = course_icon.width // 2
            course_icon.anchor_y = course_icon.height // 2

            ship_icon = pyglet.image.load('pictures/friendly_ship.png', decoder=PNGImageDecoder())
            ship_icon.anchor_x = ship_icon.width // 2
            ship_icon.anchor_y = ship_icon.height // 2

            self.icon = pyglet.sprite.Sprite(img=ship_icon)

            self.projected_acelleration_icon = pyglet.sprite.Sprite(img=course_icon )
            self.projected_deceleration_icon = pyglet.sprite.Sprite(img=course_icon)
            self.projected_heading_icon = pyglet.sprite.Sprite(img=course_icon)
            self.course_acelleration_icon = pyglet.sprite.Sprite(img=course_icon)
            self.course_deceleration_icon = pyglet.sprite.Sprite(img=course_icon)
            self.heading_icon = pyglet.sprite.Sprite(img=course_icon)

        else:
            self.color = (255, 100, 0)

        self.icon.x = position[0]
        self.icon.y = position[1]

    def update_projected(self):
        if self.course_setting and self.player_ship:

            self.projected_course_x = self.projected_heading[0] - self.icon.x
            self.projected_course_y = self.projected_heading[1] - self.icon.x

            if self.max_v:
                self.projected_deceleration = (np.sqrt(((self.projected_course_x ** 2) + (self.projected_course_y ** 2))) / 2)

            else:
                self.projected_deceleration =np.sqrt(((self.projected_course_x ** 2) + (self.projected_course_y ** 2))) - ((self.target_velocity ** 2) / (2 * self.acelleration_magnitude))
                self.projected_acelleration = (((self.target_velocity ** 2) - (self.velocity_magnitude ** 2)) / (2 * self.acelleration_magnitude)) / 1000


    def update(self,update_time):
        if self.health <= 0:
            self.alive = False

        if not self.alive:
            return

        self.update_projected()

        if self.velocity_vector[1] != 0:
            self.velocity_angle = np.arctan2(self.velocity_vector[0],self.velocity_vector[1])

        self.velocity_magnitude = np.sqrt((self.velocity_vector[0] ** 2) + (self.velocity_vector[1] ** 2))

        if self.course:
            if (self.icon.y - self.heading[1]) != 0:
                self.acelleration_angle = np.arctan2((self.heading[0] - self.icon.x), (self.heading[1] - self.icon.y))

            self.sina = np.sin(self.acelleration_angle)
            self.cosa = np.cos(self.acelleration_angle)

            self.course_x = self.heading[0] - self.icon.x
            self.course_y = self.icon.y - self.heading[1]

            self.course_displacement = np.sqrt(((self.course_x ** 2) + (self.course_y ** 2)))

            self.acelleration_vector[0] = (self.acelleration_magnitude * self.sina)
            self.acelleration_vector[1] = (self.acelleration_magnitude * self.cosa)

            if self.course_displacement <= ((self.velocity_magnitude ** 2) / (2 * self.acelleration_magnitude)) or (not self.course_max_v and self.velocity_magnitude > self.target_velocity):
                self.velocity_vector[0] -= self.acelleration_vector[0] * update_time
                self.velocity_vector[1] -= self.acelleration_vector[1] * update_time

            elif self.course_max_v or self.velocity_magnitude < self.target_velocity:
                self.velocity_vector[0] += self.acelleration_vector[0] * update_time
                self.velocity_vector[1] += self.acelleration_vector[1] * update_time

            if self.course_max_v:
                self.course_deceleration = (np.sqrt(((self.projected_course_x ** 2) + (self.projected_course_y ** 2))) / 2)

            else:
                self.course_deceleration = self.course_displacement - ((self.target_velocity ** 2) / (2 * self.acelleration_magnitude))
                self.course_acelleration = ((self.target_velocity ** 2) - (self.velocity_magnitude ** 2)) / (2 * self.acelleration_magnitude)

            if -1 <= self.course_displacement <= 1:
                self.course = False

        self.displacement_vector[0] += (self.velocity_vector[0] * update_time)
        self.displacement_vector[1] += (self.velocity_vector[1] * update_time)


    def draw(self):

        self.icon.update(x=int(round(self.displacement_vector[0])) ,y=int(round(self.displacement_vector[1])))

        if self.course_setting and self.player_ship:
            self.projected_angle = np.arctan2(((self.projected_heading[0]) - (self.icon.x)), ((self.projected_heading[1]) - (self.icon.y)))

            self.projected_heading_icon.update(x=self.projected_heading[0],y=self.projected_heading[1])
            self.projected_heading_icon.draw()

            pyglet.graphics.draw(2,pyglet.gl.GL_LINES,('v2f',(self.icon.x,self.icon.y,self.projected_heading_icon.x,self.projected_heading_icon.y)),('c3B',(0, 70, 0,0, 70, 0)))

            self.projected_deceleration_icon.x = int(round((self.projected_deceleration * np.sin(self.projected_angle)))) + self.icon.x
            self.projected_deceleration_icon.y = int(round((self.projected_deceleration * np.cos(self.projected_angle)))) + self.icon.y

            self.projected_deceleration_icon.draw()

            if not self.max_v:
                self.projected_acelleration_icon.x = int(round(((self.projected_acelleration * np.sin(self.projected_angle))))) + self.icon.x
                self.projected_acelleration_icon.y = int(round(((self.projected_acelleration * np.cos(self.projected_angle))))) + self.icon.y

                self.projected_acelleration_icon.draw()

        if self.course:
            self.heading_icon.update(x=int(round(self.heading[0])) ,y=int(round(self.heading[1])))
            self.heading_icon.draw()

            pyglet.graphics.draw(2, pyglet.gl.GL_LINES, ('v2f', (self.icon.x, self.icon.y, self.heading_icon.x, self.heading_icon.y)), ('c3B', (0, 70, 0, 0, 70, 0)))

            self.course_deceleration_icon.x = int(round(self.course_deceleration * np.sin(self.acelleration_angle))) + self.icon.x
            self.course_deceleration_icon.y = int(round(self.course_deceleration * np.cos(self.acelleration_angle))) + self.icon.y

            self.course_deceleration_icon.draw()

            if not self.course_max_v:
                self.course_acelleration_icon.x = int(round(self.course_acelleration * np.sin(self.acelleration_angle)))
                self.course_acelleration_icon.y = int(round(self.course_acelleration * np.cos(self.acelleration_angle)))

                self.course_acelleration_icon.draw()

        self.icon.draw()

        if False:
            pygame.draw.line(surface, self.color, tuple(self.position), tuple((self.position[0] + int(15 * np.sin(self.velocity_angle)), self.position[1] + int(15 * np.cos(self.velocity_angle)))), 2)

1 个答案:

答案 0 :(得分:2)

就像我推测您正在遇到OpenGL矩阵堆栈的状态性问题一样,并且您正在查询的不是用于绘图的矩阵。在您的绘图功能中

@window.event
def on_draw():
    window.clear()

    pyglet.gl.glScalef(stars.scale,stars.scale, 1, 1)
    …

您正在进行“无目标”矩阵操作调用。毫无疑问,除非您非常小心地在调用on_draw事件处理程序之间使矩阵处于众所周知的状态,否则您将不知道会发生什么。

就您的程序而言,就我所知,您从未接触过投影矩阵,因此投影矩阵处于身份状态。并且在每次on_draw调用之后,您进一步缩放了模型视图矩阵。

然后您要进行glPushMatrix设置身份并绘制船只,这会为您提供已知状态。

我建议您直接在绘图函数内部查询矩阵,而不要查询mouse_unproject,因为这是矩阵处于已知状态的唯一位置。