如何实现3D四元数相机平移?

问题描述

我正在尝试像在任何3d编辑器中一样实现3d相机。我已经绕一个点旋转并沿Z轴缩放。实施平移将是很棒的,但是我遇到了缺乏数学知识的问题。似乎可以更改四元数轴,但最终只有抖动和怪异的旋转。那么如何平移呢?

下面是仅旋转/缩放的示例代码

//fragment
#version 420 core

out vec4 fragColor;

sample smooth in vec2 f_TexCoord;
in vec3 f_vertexPos;

vec4 gridColor;

void main()
{
    //Main grid pattern
    if(fract(f_TexCoord.x / 0.0005f) < 0.025f || fract(f_TexCoord.y / 0.0005f) < 0.025f)
        gridColor = vec4(0.75,0.75,1.0);
    else
        gridColor = vec4(0);
    // Check for alpha transparency
    if(gridColor.a != 1)
        discard;

    vec2 point_center = vec2(0.5,0.5);
    float distance = length(f_TexCoord.xy - vec2(0.5,0.5));
    gridColor *= mix(vec4(0.75,1.0),vec4(0.25,0.25,1.),distance);

    fragColor = gridColor;
}
//vertex
#version 420 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

sample smooth out vec2 f_TexCoord;
out vec3 f_vertexPos;

uniform mat4 u_modelMatrix;
uniform mat4 u_viewMatrix;
uniform mat4 u_projectionMatrix;

void main()
{
    mat4 mv_matrix = u_viewMatrix * u_modelMatrix;

    gl_Position = u_projectionMatrix * mv_matrix * vec4(aPos,1.0);
    f_TexCoord = aTexCoord;
    f_vertexPos = aPos;
}
from OpenGL import GL as gl
from OpenGL.GL.shaders import compileShader,compileProgram
from pyside2 import QtWidgets,QtCore,QtGui
import sys
import ctypes
import numpy as np

class GLSurfaceFormat(QtGui.QSurfaceFormat):
    """Setup OpenGL preferences."""
    def __init__(self):
        super(GLSurfaceFormat,self).__init__()
        self.setRenderableType(QtGui.QSurfaceFormat.OpenGL)
        self.setMinorVersion(4)
        self.setProfile(QtGui.QSurfaceFormat.CoreProfile)
        self.setoption(QtGui.QSurfaceFormat.DebugContext)
        self.setColorSpace(QtGui.QSurfaceFormat.sRGBColorSpace)
        self.setSwapBehavior(QtGui.QSurfaceFormat.DoubleBuffer)
        self.setSamples(4)

class PlyViewportWidget(QtWidgets.qopenglwidget):
    """Main 3D scene viewer."""

    def __init__(self):
        super(PlyViewportWidget,self).__init__(parent=None)

        self.setAttribute(QtCore.Qt.WA_Hover)
        self.installEventFilter(self)

        self.m_projectionMatrix = QtGui.QMatrix4x4()
        self.m_viewMatrix = QtGui.QMatrix4x4()

        self.m_mousePos = QtGui.QVector2D()
        self.m_viewRotation = QtGui.QQuaternion()
        self.m_zoom = -10.0

        self.vao = None
        self.vbo = None
        self.ebo = None
        self.shaderProg = None

    def initializeGL(self):
        gl.glEnable(gl.GL_DEPTH_TEST)

        gl.glClearColor(0.4,0.4,1)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT,gl.GL_DEPTH_BUFFER_BIT)

        with open("frag.glsl",'r') as f:
            fragment = compileShader(f.read(),gl.GL_FRAGMENT_SHADER)
        with open("vert.glsl","r") as f:
            vertex = compileShader(f.read(),gl.GL_VERTEX_SHADER)
        self.shaderProg = compileProgram(vertex,fragment)

        vertices = np.array(
            [
                 # Vertex positions     # UVs
                 0.5,0.5,0.0,1.0,-0.5,1.0
            ],dtype=ctypes.c_float
        )
        indices = np.array(
            [
                0,1,3,2,3
            ],dtype=ctypes.c_uint
        )

        self.vao = gl.glGenVertexArrays(1)
        self.vbo = gl.glGenBuffers(1)
        self.ebo = gl.glGenBuffers(1)

        gl.glBindVertexArray(self.vao)

        gl.glBindBuffer(gl.GL_ARRAY_BUFFER,self.vbo)
        gl.glBufferData(gl.GL_ARRAY_BUFFER,vertices.nbytes,vertices,gl.GL_STATIC_DRAW)

        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER,self.ebo)
        gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER,indices.nbytes,indices,gl.GL_STATIC_DRAW)

        # Position attribute
        gl.glEnabLevertexAttribArray(0)
        gl.glVertexAttribPointer(0,gl.GL_FLOAT,gl.GL_FALSE,5 * ctypes.sizeof(ctypes.c_float),ctypes.c_void_p(0))

        # Texture coordinates attribute
        gl.glEnabLevertexAttribArray(1)
        gl.glVertexAttribPointer(1,ctypes.c_void_p(3 * ctypes.sizeof(ctypes.c_float)))

    def paintGL(self):
        gl.glClearColor(0.4,1.0)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

        # This is a *grid* model matrix
        modelMatrix = QtGui.QMatrix4x4()
        modelMatrix.setToIdentity()
        modelMatrix.rotate(90,QtGui.QVector3D(1.0,0.0))
        modelMatrix.scale(1000)

        self.m_viewMatrix.setToIdentity()
        self.m_viewMatrix.translate(0.0,self.m_zoom)
        self.m_viewMatrix.rotate(15,0.0))
        self.m_viewMatrix.rotate(self.m_viewRotation)

        gl.gluseProgram(self.shaderProg)

        u_projection_loc = gl.glGetUniformlocation(self.shaderProg,"u_projectionMatrix")
        gl.gluniformMatrix4fv(u_projection_loc,self.m_projectionMatrix.data())

        u_view_loc = gl.glGetUniformlocation(self.shaderProg,"u_viewMatrix")
        gl.gluniformMatrix4fv(u_view_loc,self.m_viewMatrix.data())

        u_model_loc = gl.glGetUniformlocation(self.shaderProg,"u_modelMatrix")
        gl.gluniformMatrix4fv(u_model_loc,modelMatrix.data())

        gl.glBindVertexArray(self.vao)
        gl.glDrawElements(gl.GL_TRIANGLES,6,gl.GL_UNSIGNED_INT,ctypes.c_void_p(0))

    def resizeGL(self,w: int,h: int):
        aspect = w / h
        self.m_projectionMatrix.setToIdentity()
        self.m_projectionMatrix.perspective(45,aspect,0.1,1000.0)

    def mousepressEvent(self,event: QtGui.QMouseEvent):
        if event.buttons() == QtCore.Qt.LeftButton:
            self.m_mousePos = QtGui.QVector2D(event.localPos())

    def mouseMoveEvent(self,event: QtGui.QMouseEvent):
        if event.buttons() == QtCore.Qt.LeftButton:
            diff = QtGui.QVector2D(event.localPos()) - self.m_mousePos
            self.m_mousePos = QtGui.QVector2D(event.localPos())
            angle = diff.length() / 2.0
            axis = QtGui.QVector3D(diff.y(),diff.x(),0.0)
            self.m_viewRotation = QtGui.QQuaternion.fromAxisAndAngle(axis,angle) * self.m_viewRotation
            self.update()
        event.accept()

    def wheelEvent(self,event:QtGui.QWheelEvent):
        if event.delta() > 0:
            self.m_zoom += 0.5
        elif event.delta() < 0:
            self.m_zoom -= 0.5
        self.update()
if __name__ == '__main__':
    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseDesktopOpenGL)
    QtGui.QSurfaceFormat.setDefaultFormat(GLSurfaceFormat())

    app = QtWidgets.QApplication()
    window = PlyViewportWidget()
    window.show()
    sys.exit(app.exec_())

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)