解释 OpenGL 如何管理它的变换矩阵

Posted

技术标签:

【中文标题】解释 OpenGL 如何管理它的变换矩阵【英文标题】:Explanation of how OpenGL manages its transformation matrices 【发布时间】:2020-04-28 14:40:34 【问题描述】:

我在 Python 中使用 PyOpenGL 模块进行编程。我开始研究用于视野操作的相机模块,但我坚持使用 gluLookAt() 函数。我的问题是,当我按下一个键来平移相机时,它可以正常工作,但是当我释放键时它不会停止。我认为这可能是因为我必须重新初始化转换矩阵或其他东西。我已经看到我应该推送和弹出矩阵,或者在某处加载单位矩阵,但现在我对 OpenGL 对我假设 gluLookAt() 给出的矩阵究竟做了什么感到非常困惑。

这是我的代码:

import pygame
from pygame.locals import *
import numpy as np
import glm
from math import * 
from OpenGL.GLU import *
from OpenGL.GL import *

class camera:
    def __init__(self, position, angles, target):
        self.position = glm.vec3(position[0], position[1], position[2])
        self.front = glm.normalize(self.position - glm.vec3(target[0], target[1], target[2]))
        self.upVector = glm.normalize(glm.cross(self.front, glm.normalize(glm.cross(self.front, glm.vec3(0, 1, 0)))))
    def update(self):
        glMatrixMode(GL_MODELVIEW)
        gluLookAt(self.position[0], self.position[1], self.position[2], self.position[0] + self.front[0],
        self.position[1] + self.front[1], self.position[2] + self.front[2], self.upVector[0], self.upVector[1], self.upVector[2])        

    def getPos(self):
        return self.position

    def translateCamera(self, vector):
        self.position = self.position + vector

    def keyboardControl(self):
        keys = pygame.key.get_pressed()
        if keys[K_LALT] and keys[K_F4]:
            pygame.quit()
            quit()
        if keys[K_w] and not isSprinting:
            self.position += self.front * 0.02085
        if keys[K_s]:
            self.position -= self.front * 0.02085
        if keys[K_d]:
            self.position += glm.normalize(glm.cross(self.front, self.upVector)) * 0.02085
        if keys[K_a]:
            self.position -= glm.normalize(glm.cross(self.front, self.upVector)) * 0.02085

当我松开按键时,相机一直在滑行,我想可能是因为我没有在某处重置矩阵,它只是一遍又一遍地应用 gluLookAt() 给出的矩阵。

我还尝试了 GLM,并设法使用 glm.lookAt() 创建了我想要的转换矩阵,但我不知道如何传递它,所以 OpenGL 处理它。

我应该如何使用 glPushMatrix 和 glPopMatrix?我什么时候必须使用 glLoadIdentity?

【问题讨论】:

从您报告的错误来看,更有可能是您没有正确处理关键事件。连续运动是由您使用的矩阵和向量的连续变化引起的。每次按下和释放按钮时都会打印“按下键”和“释放键”之类的内容。然后回来报告。 【参考方案1】:

当我松开按键时相机一直在滑行,我想可能是因为我没有在某处重置矩阵,它只是一遍又一遍地应用gluLookAt()给出的矩阵。

gluLookAt 不只是设置一个矩阵,如果定义一个矩阵并将当前矩阵乘以新矩阵。 注意所有矩阵运算,如glRotateglScaleglTranslate 等。将矩阵乘以当前矩阵。

gluLookAt之前加载Identity matrix,glLoadIdentity

glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(
    self.position[0], self.position[1], self.position[2],
    self.position[0] + self.front[0], self.position[1] + self.front[1], self.position[2] + self.front[2], 
    self.upVector[0], self.upVector[1], self.upVector[2])        

我还尝试了 GLM,并设法使用 glm.lookAt() 创建了我想要的转换矩阵,但我不知道如何传递它,所以 OpenGL 处理它。

使用glLoadMatrixglm.value_ptr 加载矩阵:

viewMatrix = glm.lookAt(self.position, self.position + self.front, self.upVector)
vieMatList = [viewMatrix[i][j] for i in range(4) for j in range(4)]
glMatrixMode(GL_MODELVIEW)
glLoadMatrixf(vieMatList)

注意一个矩阵可以乘以glMultMatrix

【讨论】:

我尝试了这两个建议。使用 gluLookAt 的那个有点工作,问题是场景现在是二维的(我正在使用立方体进行调试,它只渲染某些 z 值之间的一个面),但我认为这是另一个问题和与此问题无关。对于使用 GLM 的人,它返回一个 AttributeError。另外,我应该使用 glLoadMatrixf() 还是 glLoadMatrixd()? 场景不是二维的,它似乎是二维的。这与观点和projection有关。无论如何,解释所有这些都是为了广泛的答案。有很多不错的教程,推荐阅读LearnOpenGL - Camera/View space。是的,我知道本教程的语言是 C++。 OpenGL with PyOpenGL introduction 似乎也是一个不错的教程。

以上是关于解释 OpenGL 如何管理它的变换矩阵的主要内容,如果未能解决你的问题,请参考以下文章

opengl 矩阵问题

OpenGL中的坐标变换矩阵变换

浅谈OpenGL变换矩阵

OpenGL 矩阵变换

✠OpenGL-3-数学基础

OPENGL之矩阵