gpt4 book ai didi

python - PyOpenGL 将 View 坐标转换为用于 ArcBall 导航的对象坐标

转载 作者:太空宇宙 更新时间:2023-11-03 15:48:34 27 4
gpt4 key购买 nike

我正在按照本教程进行 3d 轨迹球导航:

https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Arcball

我设法执行了所有步骤并且导航正常,但我似乎无法理解教程中的最后一步:

An extra trick is converting the rotation axis from camera coordinates to object coordinates. It's useful when the camera and object are placed differently. For instace, if you rotate the object by 90° on the Y axis ("turn its head" to the right), then perform a vertical move with your mouse, you make a rotation on the camera X axis, but it should become a rotation on the Z axis (plane barrel roll) for the object. By converting the axis in object coordinates, the rotation will respect that the user work in camera coordinates (WYSIWYG). To transform from camera to object coordinates, we take the inverse of the MV matrix (from the MVP matrix triplet).

问题是,当我在第一步中转动模型时,旋转轴也进行了变换,但它们没有与我的“相机 View ”对齐。当然,我希望我的旋转轴始终与我的相机 View 对齐。

有人可以给我建议如何解决它吗?在教程中有一段代码,但没有太多解释它实际在做什么,而且我只会说 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()

最佳答案

The problem is that when i turn the model in the first step axis of rotation transform as well and they are not aligned with my "camera view". Of course I would like to keep my rotation axes always aligned with my camera view.

在渲染中,场景的每个网格通常由模型矩阵、 View 矩阵和投影矩阵进行变换。

  • 投影矩阵:
    投影矩阵描述了从场景的 3D 点到视口(viewport)的 2D 点的映射。

  • 查看矩阵:
    View 矩阵描述了观察场景的方向和位置。 View 矩阵从世界空间转换到 View (眼睛)空间。

  • 模型矩阵:
    模型矩阵定义场景中网格的位置、方向和相对大小。模型矩阵将顶点位置从网格变换到世界空间。


如果你想在 View 空间中围绕一个轴旋转 szene,你必须执行以下操作:

  • 通过在新的旋转操作之前完成的所有旋转和平移来转换模型。

  • 应用新的旋转操作。

  • 应用 View 翻译

  • 应用投影矩阵


大小 OpenGL 固定功能管道有一个矩阵堆栈,这个操作必须以相反的顺序进行。

例如请参阅 glMultMatrix 的文档:

glMultMatrix multiplies the current matrix with the one specified using m, and replaces the current matrix with the product.

在 OpenGL 中,每种矩阵模式都有一个矩阵堆栈(参见 glMatrixMode)。矩阵模式是 GL_MODELVIEWGL_PROJECTIONGL_TEXTURE

首先,您必须在分离的投影矩阵堆栈上设置投影矩阵:

glMatrixMode( GL_PROJECTION );
gluPerspective(45, (display[0]/display[1]), 0.1, 30000.0)

接下来创建模型矩阵

a = (GLfloat * 16)()
modelMat = glGetFloatv(GL_MODELVIEW_MATRIX, a)

在主循环中初始化模型 View 矩阵:

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)

设置 View 并应用新的模型矩阵:

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

关于python - PyOpenGL 将 View 坐标转换为用于 ArcBall 导航的对象坐标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48337750/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com