OpenGL中的等轴测视图

时间:2019-08-17 20:46:30

标签: python python-3.x opengl view isometric

我试图了解为什么等轴测视图不正确。最精确的表示是垂直轴为55度,水平轴为45度。在mcve中,有两个点应该在每个轴上以45度对齐。我已经根据球面代数定义设置了摄像机运动。飞机的边缘应该重合,但不重合。

MCVE:

from OpenGL.GL import glClear, GL_COLOR_BUFFER_BIT, glEnable, GL_DEPTH_TEST, glMatrixMode, GL_PROJECTION, \
    glLoadIdentity, glOrtho, glClearColor, GL_DEPTH_BUFFER_BIT, GL_MODELVIEW, glLineWidth, glBegin, glColor, glVertex, \
    glEnd, glPointSize, GL_POINT_SMOOTH, GL_POINTS, GL_BLEND, glBlendFunc, GL_SRC_ALPHA, \
    GL_QUADS, glDisable, GL_LINES, GL_LINE_LOOP, glDepthMask, GL_FALSE, GL_TRUE, GL_ONE_MINUS_SRC_ALPHA
from OpenGL.GLU import gluLookAt
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QOpenGLWidget
from math import sin, cos, radians


class Renderizador(QOpenGLWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.dx = 0
        self.dy = 0
        self.dz = 0
        self.theta = 405
        self.phi = 45
        self.x = sin(radians(self.theta)) * cos(radians(self.phi)) + self.dx
        self.z = sin(radians(self.theta)) * sin(radians(self.phi)) + self.dz
        self.y = cos(radians(self.theta)) + self.dy
        self.vertices_vertical = ((100, 100, 0), (-100, 100, 0), (-100, 0, 0), (100, 0, 0))
        self.vertices_vertical_debajo = ((100, 0, 0), (-100, 0, 0), (-100, -100, 0), (100, -100, 0))
        self.vertices_horizontal = ((100, 0, 0), (100, 0, 100), (-100, 0, 100), (-100, 0, 0))
        self.vertices_horizontal_detras = ((100, 0, 0), (100, 0, -100), (-100, 0, -100), (-100, 0, 0))
        self.vertices_borde_v = ((100, 100, 0), (100, -100, 0), (-100, -100, 0), (-100, 100, 0))
        self.vertices_borde_h = ((100, 0, 100), (-100, 0, 100), (-100, 0, -100), (100, 0, -100))
        self.puntos = [("a", 1, 1, 1), ("b", 10, 10, 10)]

    def recalcular(self):
        self.x = sin(radians(self.theta)) * cos(radians(self.phi)) + self.dx
        self.z = sin(radians(self.theta)) * sin(radians(self.phi)) + self.dz
        self.y = cos(radians(self.theta)) + self.dy
        gluLookAt(self.x, self.y, self.z, self.dx, self.dy, self.dz, 0, 1, 0)
        self.update()

    def dibujar_planos(self):
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glDepthMask(GL_FALSE)
        glBegin(GL_QUADS)
        glColor(1, 0, 0, 0.5)
        for vertex in range(4):
            glVertex(self.vertices_horizontal_detras[vertex])
        glColor(0, 1, 0, 0.5)
        for vertex in range(4):
            glVertex(self.vertices_vertical_debajo[vertex])
        glColor(0, 1, 0, 0.5)
        for vertex in range(4):
            glVertex(self.vertices_vertical[vertex])
        glColor(1, 0, 0, 0.5)
        for vertex in range(4):
            glVertex(self.vertices_horizontal[vertex])
        glEnd()
        glDepthMask(GL_TRUE)
        glDisable(GL_BLEND)
        glLineWidth(1)
        glColor(0.2, 1, 0.2, 0.5)
        glBegin(GL_LINE_LOOP)
        for vertex in range(4):
            glVertex(self.vertices_borde_v[vertex])
        glColor(1, 0.2, 0.2, 0.5)
        glEnd()
        glBegin(GL_LINE_LOOP)
        for vertex in range(4):
            glVertex(self.vertices_borde_h[vertex])
        glEnd()

    @staticmethod
    def dibujar_ejes():
        glLineWidth(3)
        glBegin(GL_LINES)
        # X ROJO
        glColor(1, 0, 0)
        glVertex(0, 0, 0)
        glVertex(10, 0, 0)
        # Y VERDE
        glColor(0, 1, 0)
        glVertex(0, 0, 0)
        glVertex(0, 10, 0)
        # Z AZUL
        glColor(0, 0, 1)
        glVertex(0, 0, 0)
        glVertex(0, 0, 10)
        glEnd()

    def dibujar_punto(self):

        glColor(0, 0, 0, 0)
        glPointSize(4)
        glEnable(GL_POINT_SMOOTH)
        glBegin(GL_POINTS)
        for i in range(len(self.puntos)):
            glVertex(self.puntos[i][1], self.puntos[i][3], self.puntos[i][2])
        glEnd()

        # self.x = sin(radians(self.theta)) * cos(radians(self.phi)) + self.dx
        # self.z = sin(radians(self.theta)) * sin(radians(self.phi)) + self.dz
        # self.y = cos(radians(self.theta)) + self.dy
        # gluLookAt(self.x, self.y, self.z, self.dx, self.dy, self.dz, 0, 1, 0)
        self.update()

    def initializeGL(self):
        glEnable(GL_DEPTH_TEST)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        glOrtho(100, -100, -100, 100, -500, 150)
        glMatrixMode(GL_MODELVIEW)

    def paintGL(self):
        glClearColor(1, 1, 1, 0)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()
        up = 1
        if self.theta == 360:
            up = -1
        gluLookAt(self.x, self.y, self.z, self.dx, self.dy, self.dz, 0, up, 0)
        self.dibujar_ejes()
        self.dibujar_planos()
        self.dibujar_punto()

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_W:
            self.theta -= 5
        elif event.key() == QtCore.Qt.Key_A:
            self.phi -= 5
        elif event.key() == QtCore.Qt.Key_S:
            self.theta += 5
        elif event.key() == QtCore.Qt.Key_D:
            self.phi += 5
        elif event.key() == QtCore.Qt.Key_Q:
            self.dz += 1
        elif event.key() == QtCore.Qt.Key_E:
            self.dz -= 1
        elif event.key() == QtCore.Qt.Key_Left:
            self.dx -= 1
        elif event.key() == QtCore.Qt.Key_Up:
            self.dy += 1
        elif event.key() == QtCore.Qt.Key_Right:
            self.dx += 1
        elif event.key() == QtCore.Qt.Key_Down:
            self.dy -= 1

        if self.theta < 360:
            self.theta = 360
        if self.theta > 540:
            self.theta = 540
        if self.phi >= 360:
            self.phi -= 360
        if self.phi < 0:
            self.phi += 360

        self.x = sin(radians(self.theta)) * cos(radians(self.phi)) + self.dx
        self.z = sin(radians(self.theta)) * sin(radians(self.phi)) + self.dz
        self.y = cos(radians(self.theta)) + self.dy

        ui.actualizar()
        self.update()
        super().keyPressEvent(event)


class UiVentana(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(UiVentana, self).__init__(parent)
        ventana.resize(1500, 1015)

        self.widget_central = QtWidgets.QWidget(ventana)
        self.Renderizador = Renderizador(self.widget_central)
        self.Renderizador.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
        self.Renderizador.setFocusPolicy(QtCore.Qt.StrongFocus)

        self.label_5 = QtWidgets.QLabel(self.widget_central)
        self.label_5.setGeometry(QtCore.QRect(1110, 49, 160, 20))
        self.label_6 = QtWidgets.QLabel(self.widget_central)
        self.label_6.setGeometry(QtCore.QRect(1010, 70, 111, 16))
        self.label_7 = QtWidgets.QLabel(self.widget_central)
        self.label_7.setGeometry(QtCore.QRect(1130, 70, 130, 16))

        self.label_5.setText("X: Y: Z:")
        self.label_6.setText("Ángulo vertical:")
        self.label_7.setText("Ángulo horizontal:")

        ventana.setCentralWidget(self.widget_central)
        ventana.show()

    def actualizar(self):
        x = round(100 * (sin(radians(self.Renderizador.theta)) * cos(radians(self.Renderizador.phi)))
                  + self.Renderizador.dx, 2)
        z = round(100 * (sin(radians(self.Renderizador.theta)) * sin(radians(self.Renderizador.phi)))
                  + self.Renderizador.dz, 2)
        y = round(100 * (cos(radians(self.Renderizador.theta))) + self.Renderizador.dy, 2)
        theta = self.Renderizador.theta - 360
        phi = self.Renderizador.phi
        if x == -0:
            x = 0
        if y == -0:
            y = 0
        if z == -0:
            z = 0
        self.label_5.setText("X: {} Y: {} Z: {}".format(x, z, y))
        self.label_6.setText("Ángulo vertical: " + str(theta))
        self.label_7.setText("Ángulo horizontal: " + str(phi))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication([])
    ventana = QtWidgets.QMainWindow()
    ui = UiVentana()
    sys.exit(app.exec_())

1 个答案:

答案 0 :(得分:1)

对于完美的等轴测图,视点必须位于立方体的对角线上。这意味着,如果视图的目标是(0,0,0),则眼睛位置的x,y和z坐标的绝对值必须相等。

当您查看计算x,y和z的公式时:

  
self.x = sin(radians(self.theta)) * cos(radians(self.phi)) + self.dx
self.z = sin(radians(self.theta)) * sin(radians(self.phi)) + self.dz
self.y = cos(radians(self.theta)) + self.dy

这意味着您必须找到一个phitheta,它们的x,y和z相等。

对于phi,这很容易。 phi仅用于计算x和z。 x取决于cos(phi),z取决于sin(phi),因为sin(45) == cos(45)phi必须为45°。

sin(45)等于1/sqrt(2)

因此必须找到一个theta,其中x,y和z何时相等

x = sin(theta) * 1/sqrt(2)
z = sin(theta) * 1/sqrt(2)
y = cos(theta)  

这是

sin(theta) * 1/sqrt(2) = cos(theta) 

Pythagoras我们知道:

cos²(theta) + sin²(theta) = 1

所以

sin(theta) = cos(theta) * sqrt(2)sin²(theta) = 1 - cos²(theta)

1 - cos²(theta) = cos²(theta) * 2

1 = cos(theta) * sqrt(3)

theta = acos(1/sqrt(3))

phitheta的结尾必须为:

self.phi   = 45
self.theta = 54.735610317245345684622999669982
相关问题