让我们开始考虑两种类型的相机旋转:
围绕点(轨道)旋转的摄像机:
def rotate_around_target(self, target, delta):
right = (self.target - self.eye).cross(self.up).normalize()
amount = (right * delta.y + self.up * delta.x)
self.target = target
self.up = self.original_up
self.eye = (
mat4.rotatez(amount.z) *
mat4.rotatey(amount.y) *
mat4.rotatex(amount.x) *
vec3(self.eye)
)
相机旋转目标(FPS)
def rotate_target(self, delta):
right = (self.target - self.eye).cross(self.up).normalize()
self.target = (
mat4.translate(self.eye) *
mat4().rotate(delta.y, right) *
mat4().rotate(delta.x, self.up) *
mat4.translate(-self.eye) *
self.target
)
然后是一个更新函数,其中从眼睛/目标/上摄像机矢量中计算出投影/视图矩阵:
def update(self, aspect):
self.view = mat4.lookat(self.eye, self.target, self.up)
self.projection = mat4.perspective_fovx(
self.fov, aspect, self.near, self.far
)
当相机的观看方向变得平行于上轴(在此处为z-up)时,出现这些旋转功能的问题...在那时,相机的行为确实令人讨厌,因此我将遇到以下故障:
所以我的问题是,如何调整上面的代码,使相机进行完整的旋转,而最终结果在某些边缘点上看起来并不奇怪(相机轴围绕:/翻转)?
我希望与许多DCC程序包(3dsmax,maya等)具有相同的行为,在这些程序包中它们进行完整的旋转而不会表现出任何奇怪的行为。
编辑:
对于那些想尝试一下数学的人,我决定创建一个真正的简约版本,该版本能够重现所解释的问题:
import math
from ctypes import c_void_p
import numpy as np
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import glm
class Camera():
def __init__(
self,
eye=None, target=None, up=None,
fov=None, near=0.1, far=100000
):
self.eye = eye or glm.vec3(0, 0, 1)
self.target = target or glm.vec3(0, 0, 0)
self.up = up or glm.vec3(0, 1, 0)
self.original_up = glm.vec3(self.up)
self.fov = fov or glm.radians(45)
self.near = near
self.far = far
def update(self, aspect):
self.view = glm.lookAt(
self.eye, self.target, self.up
)
self.projection = glm.perspective(
self.fov, aspect, self.near, self.far
)
def rotate_target(self, delta):
right = glm.normalize(glm.cross(self.target - self.eye, self.up))
M = glm.mat4(1)
M = glm.translate(M, self.eye)
M = glm.rotate(M, delta.y, right)
M = glm.rotate(M, delta.x, self.up)
M = glm.translate(M, -self.eye)
self.target = glm.vec3(M * glm.vec4(self.target, 1.0))
def rotate_around_target(self, target, delta):
right = glm.normalize(glm.cross(self.target - self.eye, self.up))
amount = (right * delta.y + self.up * delta.x)
M = glm.mat4(1)
M = glm.rotate(M, amount.z, glm.vec3(0, 0, 1))
M = glm.rotate(M, amount.y, glm.vec3(0, 1, 0))
M = glm.rotate(M, amount.x, glm.vec3(1, 0, 0))
self.eye = glm.vec3(M * glm.vec4(self.eye, 1.0))
self.target = target
self.up = self.original_up
def rotate_around_origin(self, delta):
return self.rotate_around_target(glm.vec3(0), delta)
class GlutController():
FPS = 0
ORBIT = 1
def __init__(self, camera, velocity=100, velocity_wheel=100):
self.velocity = velocity
self.velocity_wheel = velocity_wheel
self.camera = camera
def glut_mouse(self, button, state, x, y):
self.mouse_last_pos = glm.vec2(x, y)
self.mouse_down_pos = glm.vec2(x, y)
if button == GLUT_LEFT_BUTTON:
self.mode = self.FPS
elif button == GLUT_RIGHT_BUTTON:
self.mode = self.ORBIT
def glut_motion(self, x, y):
pos = glm.vec2(x, y)
move = self.mouse_last_pos - pos
self.mouse_last_pos = pos
if self.mode == self.FPS:
self.camera.rotate_target(move * 0.005)
elif self.mode == self.ORBIT:
self.camera.rotate_around_origin(move * 0.005)
class MyWindow:
def __init__(self, w, h):
self.width = w
self.height = h
glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(w, h)
glutCreateWindow('OpenGL Window')
self.startup()
glutReshapeFunc(self.reshape)
glutDisplayFunc(self.display)
glutMouseFunc(self.controller.glut_mouse)
glutMotionFunc(self.controller.glut_motion)
glutIdleFunc(self.idle_func)
def startup(self):
glEnable(GL_DEPTH_TEST)
aspect = self.width / self.height
self.camera = Camera(
eye=glm.vec3(10, 10, 10),
target=glm.vec3(0, 0, 0),
up=glm.vec3(0, 1, 0)
)
self.model = glm.mat4(1)
self.controller = GlutController(self.camera)
def run(self):
glutMainLoop()
def idle_func(self):
glutPostRedisplay()
def reshape(self, w, h):
glViewport(0, 0, w, h)
self.width = w
self.height = h
def display(self):
self.camera.update(self.width / self.height)
glClearColor(0.2, 0.3, 0.3, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(glm.degrees(self.camera.fov), self.width / self.height, self.camera.near, self.camera.far)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
e = self.camera.eye
t = self.camera.target
u = self.camera.up
gluLookAt(e.x, e.y, e.z, t.x, t.y, t.z, u.x, u.y, u.z)
glColor3f(1, 1, 1)
glBegin(GL_LINES)
for i in range(-5, 6):
if i == 0:
continue
glVertex3f(-5, 0, i)
glVertex3f(5, 0, i)
glVertex3f(i, 0, -5)
glVertex3f(i, 0, 5)
glEnd()
glBegin(GL_LINES)
glColor3f(1, 0, 0)
glVertex3f(-5, 0, 0)
glVertex3f(5, 0, 0)
glColor3f(0, 1, 0)
glVertex3f(0, -5, 0)
glVertex3f(0, 5, 0)
glColor3f(0, 0, 1)
glVertex3f(0, 0, -5)
glVertex3f(0, 0, 5)
glEnd()
glutSwapBuffers()
if __name__ == '__main__':
window = MyWindow(800, 600)
window.run()
答案 0 :(得分:2)
我建议围绕视图空间中的枢轴进行旋转
您必须知道视图矩阵(V
)。由于视图矩阵是用self.eye
,self.target
和self.up
编码的,因此必须由lookAt
计算:
V = glm.lookAt(self.eye, self.target, self.up)
计算视图空间中的pivot
,旋转角度和旋转轴。在这种情况下,轴是向右旋转的方向,其中y轴必须翻转:
pivot = glm.vec3(V * glm.vec4(target.x, target.y, target.z, 1))
axis = glm.vec3(-delta.y, -delta.x, 0)
angle = glm.length(delta)
设置旋转矩阵R
,并计算围绕枢轴RP
的比率矩阵。最后通过旋转矩阵变换视图矩阵(V
)。结果是新的视图矩阵NV
:
R = glm.rotate( glm.mat4(1), angle, axis )
RP = glm.translate(glm.mat4(1), pivot) * R * glm.translate(glm.mat4(1), -pivot)
NV = RP * V
从新视图矩阵self.eye
解码self.target
,self.up
和NV
:
C = glm.inverse(NV)
targetDist = glm.length(self.target - self.eye)
self.eye = glm.vec3(C[3])
self.target = self.eye - glm.vec3(C[2]) * targetDist
self.up = glm.vec3(C[1])
方法rotate_around_target_view
的完整编码:
def rotate_around_target_view(self, target, delta):
V = glm.lookAt(self.eye, self.target, self.up)
pivot = glm.vec3(V * glm.vec4(target.x, target.y, target.z, 1))
axis = glm.vec3(-delta.y, -delta.x, 0)
angle = glm.length(delta)
R = glm.rotate( glm.mat4(1), angle, axis )
RP = glm.translate(glm.mat4(1), pivot) * R * glm.translate(glm.mat4(1), -pivot)
NV = RP * V
C = glm.inverse(NV)
targetDist = glm.length(self.target - self.eye)
self.eye = glm.vec3(C[3])
self.target = self.eye - glm.vec3(C[2]) * targetDist
self.up = glm.vec3(C[1])
最后,它可以绕世界原点和眼睛位置甚至任何其他点旋转。
def rotate_around_origin(self, delta):
return self.rotate_around_target_view(glm.vec3(0), delta)
def rotate_target(self, delta):
return self.rotate_around_target_view(self.eye, delta)
或者,可以在模型的世界空间中执行旋转。解决方案非常相似。
旋转是在世界空间中完成的,因此不必将轴转换为视图空间,并且将旋转应用于视图矩阵(NV = V * RP
)之前:
def rotate_around_target_world(self, target, delta):
V = glm.lookAt(self.eye, self.target, self.up)
pivot = target
axis = glm.vec3(-delta.y, -delta.x, 0)
angle = glm.length(delta)
R = glm.rotate( glm.mat4(1), angle, axis )
RP = glm.translate(glm.mat4(1), pivot) * R * glm.translate(glm.mat4(1), -pivot)
NV = V * RP
C = glm.inverse(NV)
targetDist = glm.length(self.target - self.eye)
self.eye = glm.vec3(C[3])
self.target = self.eye - glm.vec3(C[2]) * targetDist
self.up = glm.vec3(C[1])
def rotate_around_origin(self, delta):
return self.rotate_around_target_world(glm.vec3(0), delta)
当然,两种解决方案都可以结合使用。通过垂直(上下)拖动,视图可以在其水平轴上旋转。通过水平拖动(左右),模型(世界)可以绕其(上)轴旋转:
def rotate_around_target(self, target, delta):
if abs(delta.x) > 0:
self.rotate_around_target_world(target, glm.vec3(delta.x, 0.0, 0.0))
if abs(delta.y) > 0:
self.rotate_around_target_view(target, glm.vec3(0.0, delta.y, 0.0))
考虑到问题的原始代码,为了实现最小程度的侵入性方法,我将提出以下建议:
在操作之后,视图的目标应该是函数target
的输入参数rotate_around_target
。
水平移动鼠标应使视图围绕世界的向上矢量旋转
垂直鼠标移动应使视图围绕当前水平轴倾斜
我想到了以下方法:
计算当前视线(los
),向上矢量(up
)和水平轴(right
)
通过将向上矢量投影到由原始向上矢量和当前视线给定的平面上,使向上矢量垂直。这是Gram–Schmidt orthogonalization的唐。
围绕当前水平轴倾斜。这意味着los
和up
绕right
轴旋转。
围绕up矢量旋转。 los
和right
绕up
旋转。
计算设置向上并计算眼睛和目标位置,其中目标由输入参数target设置:
def rotate_around_target(self, target, delta):
# get directions
los = self.target - self.eye
losLen = glm.length(los)
right = glm.normalize(glm.cross(los, self.up))
up = glm.cross(right, los)
# upright up vector (Gram–Schmidt orthogonalization)
fix_right = glm.normalize(glm.cross(los, self.original_up))
UPdotX = glm.dot(fix_right, up)
up = glm.normalize(up - UPdotX * fix_right)
right = glm.normalize(glm.cross(los, up))
los = glm.cross(up, right)
# tilt around horizontal axis
RHor = glm.rotate(glm.mat4(1), delta.y, right)
up = glm.vec3(RHor * glm.vec4(up, 0.0))
los = glm.vec3(RHor * glm.vec4(los, 0.0))
# rotate around up vector
RUp = glm.rotate(glm.mat4(1), delta.x, up)
right = glm.vec3(RUp * glm.vec4(right, 0.0))
los = glm.vec3(RUp * glm.vec4(los, 0.0))
# set eye, target and up
self.eye = target - los * losLen
self.target = target
self.up = up
答案 1 :(得分:1)
有那么多重新发明轮子的方法吗?这是一个很好的选择(改编自《 Opengl Development Cookbook》(M.M。Movania,第2章)中的目标相机概念):
首先创建新的方向(旋转)矩阵(已更新以使用累积的鼠标增量)
# global variables somewhere appropriate (or class variables)
mouseX = 0.0
mouseY = 0.0
def rotate_around_target(self, target, delta):
global mouseX
global mouseY
mouseX += delta.x/5.0
mouseY += delta.y/5.0
glm::mat4 M = glm::mat4(1)
M = glm::rotate(M, delta.z, glm::vec3(0, 0, 1))
M = glm::rotate(M, mouseX , glm::vec3(0, 1, 0))
M = glm::rotate(M, mouseY, glm::vec3(1, 0, 0))
使用距离获取向量,然后通过当前旋转矩阵转换该向量
self.target = target
float distance = glm::distance(self.target, self.eye)
glm::vec3 T = glm::vec3(0, 0, distance)
T = glm::vec3(M*glm::vec4(T, 0.0f))
通过将平移矢量添加到目标位置来获取新的相机眼睛位置
self.eye = self.target + T
重新计算正交基础(您只需计算其中的UP向量)
# assuming self.original_up = glm::vec3(0, 1, 0)
self.up = glm::vec3(M*glm::vec4(self.original_up, 0.0f))
# or
self.up = glm::vec3(M*glm::vec4(glm::vec3(0, 1, 0), 0.0f))
5 ...然后您可以通过使用lookAt函数更新视图矩阵来进行尝试
self.view = glm.lookAt( self.eye, self.target, self.up)
对于我到目前为止发现的这类变换问题/解决方案,这是最简单的概念。我在C / C ++中对其进行了测试,并刚刚为您修改为pyopengl语法(我希望是这样)。让我们知道它进展如何(或没有)。
答案 2 :(得分:1)
以下是该线程提供的所有答案的简短摘要:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import glm
class Camera():
def __init__(
self,
eye=None, target=None, up=None,
fov=None, near=0.1, far=100000
):
self.eye = eye or glm.vec3(0, 0, 1)
self.target = target or glm.vec3(0, 0, 0)
self.up = up or glm.vec3(0, 1, 0)
self.original_up = glm.vec3(self.up)
self.fov = fov or glm.radians(45)
self.near = near
self.far = far
def update(self, aspect):
self.view = glm.lookAt(
self.eye, self.target, self.up
)
self.projection = glm.perspective(
self.fov, aspect, self.near, self.far
)
def zoom(self, *args):
delta = -args[1] * 0.1
distance = glm.length(self.target - self.eye)
self.eye = self.target + (self.eye - self.target) * (delta + 1)
def load_projection(self):
width = glutGet(GLUT_WINDOW_WIDTH)
height = glutGet(GLUT_WINDOW_HEIGHT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(glm.degrees(self.fov), width / height, self.near, self.far)
def load_modelview(self):
e = self.eye
t = self.target
u = self.up
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(e.x, e.y, e.z, t.x, t.y, t.z, u.x, u.y, u.z)
class CameraSkatic(Camera):
def rotate_around_target(self, target, delta):
M = glm.mat4(1)
M = glm.rotate(M, delta.x, glm.vec3(0, 1, 0))
M = glm.rotate(M, delta.y, glm.vec3(1, 0, 0))
self.target = target
T = glm.vec3(0, 0, glm.distance(self.target, self.eye))
T = glm.vec3(M * glm.vec4(T, 0.0))
self.eye = self.target + T
self.up = glm.vec3(M * glm.vec4(self.original_up, 1.0))
def rotate_around_origin(self, delta):
return self.rotate_around_target(glm.vec3(0), delta)
class CameraBPL(Camera):
def rotate_target(self, delta):
right = glm.normalize(glm.cross(self.target - self.eye, self.up))
M = glm.mat4(1)
M = glm.translate(M, self.eye)
M = glm.rotate(M, delta.y, right)
M = glm.rotate(M, delta.x, self.up)
M = glm.translate(M, -self.eye)
self.target = glm.vec3(M * glm.vec4(self.target, 1.0))
def rotate_around_target(self, target, delta):
right = glm.normalize(glm.cross(self.target - self.eye, self.up))
amount = (right * delta.y + self.up * delta.x)
M = glm.mat4(1)
M = glm.rotate(M, amount.z, glm.vec3(0, 0, 1))
M = glm.rotate(M, amount.y, glm.vec3(0, 1, 0))
M = glm.rotate(M, amount.x, glm.vec3(1, 0, 0))
self.eye = glm.vec3(M * glm.vec4(self.eye, 1.0))
self.target = target
self.up = self.original_up
def rotate_around_origin(self, delta):
return self.rotate_around_target(glm.vec3(0), delta)
class CameraRabbid76_v1(Camera):
def rotate_around_target_world(self, target, delta):
V = glm.lookAt(self.eye, self.target, self.up)
pivot = target
axis = glm.vec3(-delta.y, -delta.x, 0)
angle = glm.length(delta)
R = glm.rotate(glm.mat4(1), angle, axis)
RP = glm.translate(glm.mat4(1), pivot) * R * glm.translate(glm.mat4(1), -pivot)
NV = V * RP
C = glm.inverse(NV)
targetDist = glm.length(self.target - self.eye)
self.eye = glm.vec3(C[3])
self.target = self.eye - glm.vec3(C[2]) * targetDist
self.up = glm.vec3(C[1])
def rotate_around_target_view(self, target, delta):
V = glm.lookAt(self.eye, self.target, self.up)
pivot = glm.vec3(V * glm.vec4(target.x, target.y, target.z, 1))
axis = glm.vec3(-delta.y, -delta.x, 0)
angle = glm.length(delta)
R = glm.rotate(glm.mat4(1), angle, axis)
RP = glm.translate(glm.mat4(1), pivot) * R * glm.translate(glm.mat4(1), -pivot)
NV = RP * V
C = glm.inverse(NV)
targetDist = glm.length(self.target - self.eye)
self.eye = glm.vec3(C[3])
self.target = self.eye - glm.vec3(C[2]) * targetDist
self.up = glm.vec3(C[1])
def rotate_around_target(self, target, delta):
if abs(delta.x) > 0:
self.rotate_around_target_world(target, glm.vec3(delta.x, 0.0, 0.0))
if abs(delta.y) > 0:
self.rotate_around_target_view(target, glm.vec3(0.0, delta.y, 0.0))
def rotate_around_origin(self, delta):
return self.rotate_around_target(glm.vec3(0), delta)
def rotate_target(self, delta):
return self.rotate_around_target(self.eye, delta)
class CameraRabbid76_v2(Camera):
def rotate_around_target(self, target, delta):
# get directions
los = self.target - self.eye
losLen = glm.length(los)
right = glm.normalize(glm.cross(los, self.up))
up = glm.cross(right, los)
# upright up vector (Gram–Schmidt orthogonalization)
fix_right = glm.normalize(glm.cross(los, self.original_up))
UPdotX = glm.dot(fix_right, up)
up = glm.normalize(up - UPdotX * fix_right)
right = glm.normalize(glm.cross(los, up))
los = glm.cross(up, right)
# tilt around horizontal axis
RHor = glm.rotate(glm.mat4(1), delta.y, right)
up = glm.vec3(RHor * glm.vec4(up, 0.0))
los = glm.vec3(RHor * glm.vec4(los, 0.0))
# rotate around up vector
RUp = glm.rotate(glm.mat4(1), delta.x, up)
right = glm.vec3(RUp * glm.vec4(right, 0.0))
los = glm.vec3(RUp * glm.vec4(los, 0.0))
# set eye, target and up
self.eye = target - los * losLen
self.target = target
self.up = up
def rotate_around_origin(self, delta):
return self.rotate_around_target(glm.vec3(0), delta)
def rotate_target(self, delta):
return self.rotate_around_target(self.eye, delta)
class GlutController():
FPS = 0
ORBIT = 1
def __init__(self, camera, velocity=100, velocity_wheel=100):
self.velocity = velocity
self.velocity_wheel = velocity_wheel
self.camera = camera
def glut_mouse(self, button, state, x, y):
self.mouse_last_pos = glm.vec2(x, y)
self.mouse_down_pos = glm.vec2(x, y)
if button == GLUT_LEFT_BUTTON:
self.mode = self.FPS
elif button == GLUT_RIGHT_BUTTON:
self.mode = self.ORBIT
def glut_motion(self, x, y):
pos = glm.vec2(x, y)
move = self.mouse_last_pos - pos
self.mouse_last_pos = pos
if self.mode == self.FPS:
self.camera.rotate_target(move * 0.005)
elif self.mode == self.ORBIT:
self.camera.rotate_around_origin(move * 0.005)
def glut_mouse_wheel(self, *args):
self.camera.zoom(*args)
def render_text(x, y, text):
glColor3f(1, 1, 1)
glRasterPos2f(x, y)
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, text.encode("utf-8"))
def draw_plane_yup():
glColor3f(1, 1, 1)
glBegin(GL_LINES)
for i in range(-5, 6):
if i == 0:
continue
glVertex3f(-5, 0, i)
glVertex3f(5, 0, i)
glVertex3f(i, 0, -5)
glVertex3f(i, 0, 5)
glEnd()
glBegin(GL_LINES)
glColor3f(1, 1, 1)
glVertex3f(-5, 0, 0)
glVertex3f(0, 0, 0)
glVertex3f(0, 0, -5)
glVertex3f(0, 0, 0)
glColor3f(1, 0, 0)
glVertex3f(0, 0, 0)
glVertex3f(5, 0, 0)
glColor3f(0, 1, 0)
glVertex3f(0, 0, 0)
glVertex3f(0, 5, 0)
glColor3f(0, 0, 1)
glVertex3f(0, 0, 0)
glVertex3f(0, 0, 5)
glEnd()
def draw_plane_zup():
glColor3f(1, 1, 1)
glBegin(GL_LINES)
for i in range(-5, 6):
if i == 0:
continue
glVertex3f(-5, 0, i)
glVertex3f(5, 0, i)
glVertex3f(i, -5, 0)
glVertex3f(i, 5, 0)
glEnd()
glBegin(GL_LINES)
glColor3f(1, 1, 1)
glVertex3f(-5, 0, 0)
glVertex3f(0, 0, 0)
glVertex3f(0, -5, 0)
glVertex3f(0, 0, 0)
glColor3f(1, 0, 0)
glVertex3f(0, 0, 0)
glVertex3f(5, 0, 0)
glColor3f(0, 1, 0)
glVertex3f(0, 0, 0)
glVertex3f(0, 0, 5)
glColor3f(0, 0, 1)
glVertex3f(0, 0, 0)
glVertex3f(0, 5, 0)
glEnd()
def line(p0, p1, color=None):
c = color or glm.vec3(1, 1, 1)
glColor3f(c.x, c.y, c.z)
glVertex3f(p0.x, p0.y, p0.z)
glVertex3f(p1.x, p1.y, p1.z)
def grid(segment_count=10, spacing=1, yup=True):
size = segment_count * spacing
right = glm.vec3(1, 0, 0)
forward = glm.vec3(0, 0, 1) if yup else glm.vec3(0, 1, 0)
x_axis = right * size
z_axis = forward * size
data = []
i = -segment_count
glBegin(GL_LINES)
while i <= segment_count:
p0 = -x_axis + forward * i * spacing
p1 = x_axis + forward * i * spacing
line(p0, p1)
p0 = -z_axis + right * i * spacing
p1 = z_axis + right * i * spacing
line(p0, p1)
i += 1
glEnd()
def axis(size=1.0, yup=True):
right = glm.vec3(1, 0, 0)
forward = glm.vec3(0, 0, 1) if yup else glm.vec3(0, 1, 0)
x_axis = right * size
z_axis = forward * size
y_axis = glm.cross(forward, right) * size
glBegin(GL_LINES)
line(x_axis, glm.vec3(0, 0, 0), glm.vec3(1, 0, 0))
line(y_axis, glm.vec3(0, 0, 0), glm.vec3(0, 1, 0))
line(z_axis, glm.vec3(0, 0, 0), glm.vec3(0, 0, 1))
glEnd()
class MyWindow:
def __init__(self, w, h):
self.width = w
self.height = h
glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(w, h)
glutCreateWindow('OpenGL Window')
self.startup()
glutReshapeFunc(self.reshape)
glutDisplayFunc(self.display)
glutMouseFunc(self.controller.glut_mouse)
glutMotionFunc(self.controller.glut_motion)
glutMouseWheelFunc(self.controller.glut_mouse_wheel)
glutKeyboardFunc(self.keyboard_func)
glutIdleFunc(self.idle_func)
def keyboard_func(self, *args):
try:
key = args[0].decode("utf8")
if key == "\x1b":
glutLeaveMainLoop()
if key in ['1', '2', '3', '4']:
if key == '1':
self.index_camera = "Skatic"
elif key == '2':
self.index_camera = "BPL"
elif key == '3':
self.index_camera = "Rabbid76_v1"
elif key == '4':
self.index_camera = "Rabbid76_v2"
self.camera = self.cameras[self.index_camera]
self.controller.camera = self.camera
if key in ['o', 'p']:
self.camera.eye = glm.vec3(0, 10, 10)
self.camera.target = glm.vec3(0, 0, 0)
if key == 'o':
self.yup = True
# self.camera.up = glm.vec3(0, 0, 1)
elif key == 'p':
self.yup = False
# self.camera.up = glm.vec3(0, 1, 0)
self.camera.target = glm.vec3(0, 0, 0)
except Exception as e:
import traceback
traceback.print_exc()
def startup(self):
glEnable(GL_DEPTH_TEST)
aspect = self.width / self.height
params = {
"eye": glm.vec3(0, 100, 100),
"target": glm.vec3(0, 0, 0),
"up": glm.vec3(0, 1, 0)
}
self.cameras = {
"Skatic": CameraSkatic(**params),
"BPL": CameraBPL(**params),
"Rabbid76_v1": CameraRabbid76_v1(**params),
"Rabbid76_v2": CameraRabbid76_v2(**params)
}
self.index_camera = "BPL"
self.yup = True
self.camera = self.cameras[self.index_camera]
self.model = glm.mat4(1)
self.controller = GlutController(self.camera)
def run(self):
glutMainLoop()
def idle_func(self):
glutPostRedisplay()
def reshape(self, w, h):
glViewport(0, 0, w, h)
self.width = w
self.height = h
def display(self):
self.camera.update(self.width / self.height)
glClearColor(0.2, 0.3, 0.3, 1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.camera.load_projection()
self.camera.load_modelview()
glLineWidth(5)
axis(size=70, yup=self.yup)
glLineWidth(1)
grid(segment_count=7, spacing=10, yup=self.yup)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(-1, 1, -1, 1, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
info = "\n".join([
"1: Skatic Camera",
"2: BPL Camera",
"3: Rabbid76 Camera (version1)",
"4: Rabbid76 Camera (version2)",
"o: RHS Scene Y-UP",
"p: RHS Scene Z-UP",
])
render_text(-1.0, 1.0 - 0.1, info)
render_text(-1.0, -1.0, "{} camera is active, scene is {}".format(self.index_camera, "Y-UP" if self.yup else "Z-UP"))
glutSwapBuffers()
if __name__ == '__main__':
window = MyWindow(800, 600)
window.run()