我正在关注3D教程中的弧球导航:
https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Arcball
我设法执行了所有步骤和导航工作,但我似乎无法理解教程的最后一步:
额外的技巧是从相机坐标转换旋转轴 对象坐标。当相机和物体相同时,它很有用 放置不同。对于instace,如果您将对象旋转90° Y轴(“向右转”),然后执行垂直 用鼠标移动,你在相机X轴上旋转,但它 应该成为Z轴(平面滚筒)的旋转 宾语。通过转换对象坐标中的轴,旋转 将尊重用户在相机坐标(WYSIWYG)工作。至 从相机到物体坐标的转换,我们采取相反的方式 MV矩阵(来自MVP矩阵三元组)。
问题在于,当我在第一步旋转轴转换模型时,它们也不与我的“相机视图”对齐。当然我想让我的旋转轴始终与我的相机视图保持一致。
有人可以给我一个如何解决的建议吗?在教程中有一个代码,但没有太多解释它实际上在做什么,而且我只会说Python。
谢谢你, 雅各布
我的代码:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import math
import os
import numpy as np
size = 30
speed = 500
amplitude_amplificator = 80
color_table = ((1,0,0),
(0,1,0),
(0,0,1),
(1,1,0),
(1,0,1),
(0,1,1),
(1,0.5,0),
(0.5,1,0),
(0.5,1,0.5),
(0,0.5,0)
)
locations = ((0,-975, 0),
(0, 975, 0),
(-1273,-975, 0),
(-1273, 975, 0),
(-2482, -975, 0),
(-2482, 975, 0),
(-3737, -975, 0),
(-3737, 975, 0)
)
lines = ((0,2),
(2, 4),
(4, 6),
(1, 3),
(3, 5),
(5, 7),
(0, 1),
(2, 3),
(4, 5),
(6, 7),
)
amplitudes = ((3.38829249165602, 2.38305866657961, 2.52151563664636),
(5.08487438107113, 2.36432294667884, 3.0843991148654),
(3.44312569856563, 1.23112415468012, 1.29869765112226),
(4.0421066637935, 1.40655294535107, 1.36083778879317),
(3.78074337117764, 0.648255908566916, 0.752239154016233),
(5.08887133464996, 0.607037324785205, 0.543523234321567),
(4.49095206021647, 0.432732677308301, 2.18289872563964),
(5.14707697114171, 0.335119576625248, 2.15666871777855)
)
phases = ((-146.873017352057,0,-95.316526141321),
(-149.008372080797, 5.24886681104675, 78.3075732082314),
(-148.241584335287, 5.54327579087787, -118.279685417256),
(-151.844141596427, 6.48705235395368, -113.246406750217),
(-148.14233553496, 27.9523171503408, 65.8254568277543),
(-157.058723259828, 38.8760924034639, 85.2339573112435),
(-153.417593784393, -120.329988461629, 16.0421535833842),
(-156.779107376825, 83.2350395893582, 10.7592173681729)
)
# DRAW CUBE
def Cube(po,si,co):
POS = (
(po[0]+si, po[1]-si, po[2]-si),
(po[0]+si, po[1]+si, po[2]-si),
(po[0]-si, po[1]+si, po[2]-si),
(po[0]-si, po[1]-si, po[2]-si),
(po[0]+si, po[1]-si, po[2]+si),
(po[0]+si, po[1]+si, po[2]+si),
(po[0]-si, po[1]-si, po[2]+si),
(po[0]-si, po[1]+si, po[2]+si)
)
edges = (
(0,1),
(0,3),
(0,4),
(2,1),
(2,3),
(2,7),
(6,3),
(6,4),
(6,7),
(5,1),
(5,4),
(5,7)
)
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glColor3f(co[0],co[1],co[2])
glVertex3fv(POS[vertex])
glEnd()
#DRAW ORIGINAL SHAPE IN LINES
def Line_orig(po):
glBegin(GL_LINES)
for edge in po:
for vertex in edge:
glVertex3fv(locations[vertex])
glEnd()
#Hemisphere mapping
def map_hemisphere(x,y):
z = math.sqrt(abs(1-math.pow(x,2)-math.pow(y,2)))
return z
# Calculate angle of two spatial vectors
def angle_calculation(a,b):
r = math.degrees(math.acos((np.dot(a, b))/(np.linalg.norm(a)*np.linalg.norm(b))))
return r
def main():
mouse_pressed = 0
pygame.init()
display = (1200,800)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
gluPerspective(45, (display[0]/display[1]), 0.1, 30000.0)
glTranslatef(0,0.0,-10000)
#glRotatef(90, 1, 0, 0)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
time = pygame.time.get_ticks()/1000
norm_mouse_pos = (2*pygame.mouse.get_pos()[0]/display[0]-1,2*pygame.mouse.get_pos()[1]/display[1]-1,map_hemisphere(2*pygame.mouse.get_pos()[0]/display[0]-1,2*pygame.mouse.get_pos()[1]/display[1]-1))
if pygame.mouse.get_pressed()[0]==1:
if mouse_pressed == 0:
mouse_pressed = 1
clear = lambda: os.system('cls')
clear()
p1 = (norm_mouse_pos[0],norm_mouse_pos[1],map_hemisphere(norm_mouse_pos[0],norm_mouse_pos[1]))
print(p1)
else:
p2 = (norm_mouse_pos[0],norm_mouse_pos[1],map_hemisphere(norm_mouse_pos[0],norm_mouse_pos[1]))
cist = np.cross(p1, p2)
print(angle_calculation(p1,p2))
glRotatef( angle_calculation(p1,p2) , -cist[0] , cist[1] , cist[2] )
else:
mouse_pressed = 0
# Translation of the model via keyboard handling
keys=pygame.key.get_pressed()
if keys[K_w]:
glTranslatef(0, 100, 0)
if keys[K_s]:
glTranslatef(0, -100, 0)
if keys[K_a]:
glTranslatef(-100, 0, 0)
if keys[K_d]:
glTranslatef(100, 0, 0)
# Drawing the Cubes at Nodes Loactions
for item, el in enumerate(locations):
Cube((el[0] + amplitudes[item][0]*math.sin(time + phases[item][0]*(3.1415927/180))*amplitude_amplificator,
el[1] + amplitudes[item][1]*math.sin(time + phases[item][1]*(3.1415927/180))*amplitude_amplificator,
el[2] + amplitudes[item][2]*math.sin(time + phases[item][2]*(3.1415927/180))*amplitude_amplificator
), size, color_table[item])
# Drawing the Original Shapes (Specified nodes in Lines Tuple)
Line_orig(lines)
# Drawing the Deformed Shape
glBegin(GL_LINES)
for edge in lines:
for vertex in edge:
glVertex3fv((locations[vertex][0] + amplitudes[vertex][0]*math.sin(time + phases[vertex][0]*(3.1415927/180))*amplitude_amplificator,
locations[vertex][1] + amplitudes[vertex][1]*math.sin(time + phases[vertex][1]*(3.1415927/180))*amplitude_amplificator ,
locations[vertex][2] + amplitudes[vertex][2]*math.sin(time + phases[vertex][2]*(3.1415927/180))*amplitude_amplificator,
))
glEnd()
# OpenGL Management
pygame.display.flip()
pygame.time.wait(10)
main()
答案 0 :(得分:2)
问题在于,当我在第一步旋转轴转换模型时,它们也不与我的“相机视图”对齐。当然我想让我的旋转轴始终与我的相机视图保持一致。
在渲染中,场景的每个网格通常由模型矩阵,视图矩阵和投影矩阵进行变换。
投影矩阵:
投影矩阵描述了从场景的3D点到视口的2D点的映射。
查看矩阵:
视图矩阵描述了查看场景的方向和位置。视图矩阵从wolrd空间转换为视图(眼睛)空间。
模型矩阵:
模型矩阵定义场景中网格的位置,方向和相对大小。模型矩阵将顶点位置从网格转换为世界空间。
如果要围绕视图空间中的轴旋转szene,则必须执行以下操作:
通过在新的旋转操作之前完成的所有旋转和平移来转换模型。
应用新的旋转操作。
应用视图翻译
应用投影矩阵
OpenGL固定功能管道的大小有一个矩阵堆栈,这个操作必须按相反的顺序完成。
e.g。请参阅glMultMatrix
的文档:
glMultMatrix
将当前矩阵与使用m
指定的矩阵相乘,并将当前矩阵替换为产品。
在OpenGL中,每种矩阵模式都有一个矩阵堆栈(参见glMatrixMode
)。矩阵模式为GL_MODELVIEW
,GL_PROJECTION
和GL_TEXTURE
。
首先,您必须在分离的投影矩阵堆栈上设置投影矩阵:
glMatrixMode( GL_PROJECTION );
gluPerspective(45, (display[0]/display[1]), 0.1, 30000.0)
接下来创建一个模型矩阵
a = (GLfloat * 16)()
modelMat = glGetFloatv(GL_MODELVIEW_MATRIX, a)
在主循环中初始化模型视图矩阵:
glMatrixMode( GL_MODELVIEW );
glLoadIdentity()
计算新的轮换和翻译:
axis = (p2[0]- p1[0], p2[1]- p1[1])
glRotatef( angle_calculation(p1,p2), axis[1], axis[0], 0 )
将模型矩阵乘以先前的模型矩阵并存储组合模型矩阵:
glMultMatrixf( modelMat )
modelMat = glGetFloatv(GL_MODELVIEW_MATRIX, a)
设置视图并应用新的模型矩阵:
glLoadIdentity()
glTranslatef(0,0.0,-10000)
glMultMatrixf( modelMat )
最终代码可能如下所示:
.....
glMatrixMode( GL_PROJECTION );
gluPerspective(45, (display[0]/display[1]), 0.1, 30000.0)
a = (GLfloat * 16)()
modelMat = glGetFloatv(GL_MODELVIEW_MATRIX, a)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity()
norm_mouse_pos = (2*pygame.mouse.get_pos()[0]/display[0]-1,2*pygame.mouse.get_pos()[1]/display[1]-1,map_hemisphere(2*pygame.mouse.get_pos()[0]/display[0]-1,2*pygame.mouse.get_pos()[1]/display[1]-1))
if pygame.mouse.get_pressed()[0]==1:
if mouse_pressed == 0:
mouse_pressed = 1
clear = lambda: os.system('cls')
clear()
p1 = (norm_mouse_pos[0],norm_mouse_pos[1],map_hemisphere(norm_mouse_pos[0],norm_mouse_pos[1]))
else:
p2 = (norm_mouse_pos[0],norm_mouse_pos[1],map_hemisphere(norm_mouse_pos[0],norm_mouse_pos[1]))
cist = np.cross(p1, p2)
axis = (p2[0]- p1[0], p2[1]- p1[1])
glRotatef( angle_calculation(p1,p2) , axis[1] , axis[0] , 0 )
else:
mouse_pressed = 0
# Translation of the model via keyboard handling
keys=pygame.key.get_pressed()
if keys[K_w]:
glTranslatef(0, 100, 0)
if keys[K_s]:
glTranslatef(0, -100, 0)
if keys[K_a]:
glTranslatef(-100, 0, 0)
if keys[K_d]:
glTranslatef(100, 0, 0)
glMultMatrixf( modelMat )
modelMat = glGetFloatv(GL_MODELVIEW_MATRIX, a)
glLoadIdentity()
glTranslatef(0,0.0,-10000)
glMultMatrixf( modelMat )
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
.....
有时会出现“ValueError:math domain error”,因为如果值在[-1,1]范围内,则仅定义值的反余弦值。将值限制在此范围(min(1,max(cos_a,-1))
):
def angle_calculation(a,b):
cos_a = np.dot(a, b) / (np.linalg.norm(a)*np.linalg.norm(b))
r = math.degrees(math.acos( min(1,max(cos_a,-1)) ))
return r