我基本上是想模仿相机在Maya中旋转的方式。Maya中的导航球始终与y轴对齐。所以无论上方向向量指向哪里,它仍然沿着y轴旋转或与它的上方向向量配准。
我已经能够使用C++和Qt在OpenGL中实现is arcball。但我想不出怎么让它保持向上向量对齐。我已经能够通过下面的代码使它保持对齐:
void ArcCamera::setPos (Vector3 np)
{
Vector3 up(0, 1, 0);
Position = np;
ViewDir = (ViewPoint - Position); ViewDir.normalize();
RightVector = ViewDir ^ up; RightVector.normalize();
UpVector = RightVector ^ ViewDir; UpVector.normalize();
}这一直持续到位置在90度,然后右向量改变,一切都颠倒了。
因此,我一直保持总旋转(以四元数为单位),并通过它旋转原始位置(向上,向右,向后)。这最好地保持了所有东西的连贯性,但现在我根本不能将向上向量与y轴对齐。下面是旋转的函数。
void CCamera::setRot (QQuaternion q)
{
tot = tot * q;
Position = tot.rotatedVector(PositionOriginal);
UpVector = tot.rotatedVector(UpVectorOriginal);
UpVector.normalize();
RightVector = tot.rotatedVector(RightVectorOriginal);
RightVector.normalize();
}QQuaternion Q是从鼠标拖动导出的轴角度对生成的。我相信这是正确的。旋转本身很好,只是不能保持方向对齐。
我注意到,在我选择的实现中,拖动角提供了围绕我的视图方向的旋转,并且我总是可以重新对齐向上向量,以拉直到世界的y轴方向。因此,如果我能计算出滚动多少,我可能会每次做两个旋转,以确保它们都是直的。然而,我不确定该怎么做。
发布于 2016-01-04 12:05:58
此操作不起作用的原因是因为Maya在视口中的摄影机操纵不使用arcball界面。您想要做的是Maya's tumble command。我找到的最好的解释资源是this document from Professor Orr's Computer Graphics class。
向左和向右移动鼠标对应于方位角,并指定围绕世界空间Y轴的旋转。上下移动鼠标对应于仰角,并指定围绕视图空间X轴的旋转。我们的目标是生成新的世界视图矩阵,然后根据相机的参数化方式,从该矩阵中提取新的相机方向和眼睛位置。
从当前的世界到视图矩阵开始。接下来,我们需要定义世界空间中的轴心点。任何轴心点都可以开始工作,并且使用世界原点可以是最简单的。
回想一下,纯旋转矩阵生成以原点为中心的旋转。这意味着要围绕任意轴心点旋转,首先要平移到原点,执行旋转,然后再平移回来。还请记住,变换合成是从右到左进行的,因此到达原点的负转换位于最右侧:
translate(pivotPosition) * rotate(angleX, angleY, angleZ) * translate(-pivotPosition)我们可以用它来计算方位角旋转分量,它是围绕世界Y轴的旋转:
azimuthRotation = translate(pivotPosition) * rotateY(angleY) * translate(-pivotPosition)我们必须为elevation旋转组件做一些额外的工作,因为它发生在视图空间中,围绕视图空间X轴:
elevationRotation = translate(worldToViewMatrix * pivotPosition) * rotateX(angleX) * translate(worldToViewMatrix * -pivotPosition)然后,我们可以使用以下命令获得新的视图矩阵:
newWorldToViewMatrix = elevationRotation * worldToViewMatrix * azimuthRotation现在我们有了新的worldToView矩阵,剩下的工作就是从视图矩阵中提取新的世界空间位置和方向。为此,我们需要viewToWorld矩阵,它是worldToView矩阵的逆。
newOrientation = transpose(mat3(newWorldToViewMatrix))
newPosition = -((newOrientation * newWorldToViewMatrix).column(3))在这一点上,我们分离了元素。如果您的摄影机是参数化的,因此您只需存储一个四元数来表示方向,则只需执行旋转矩阵->四元数转换。当然,Maya将转换为Euler角度以显示在通道盒中,这将取决于摄影机的旋转顺序(请注意,旋转顺序更改时翻滚的数学不会更改,只是旋转矩阵-> Euler角度转换的完成方式)。
下面是一个用Python实现的示例:
#!/usr/bin/env python
import numpy as np
from math import *
def translate(amount):
'Make a translation matrix, to move by `amount`'
t = np.matrix(np.eye(4))
t[3] = amount.T
t[3, 3] = 1
return t.T
def rotateX(amount):
'Make a rotation matrix, that rotates around the X axis by `amount` rads'
c = cos(amount)
s = sin(amount)
return np.matrix([
[1, 0, 0, 0],
[0, c,-s, 0],
[0, s, c, 0],
[0, 0, 0, 1],
])
def rotateY(amount):
'Make a rotation matrix, that rotates around the Y axis by `amount` rads'
c = cos(amount)
s = sin(amount)
return np.matrix([
[c, 0, s, 0],
[0, 1, 0, 0],
[-s, 0, c, 0],
[0, 0, 0, 1],
])
def rotateZ(amount):
'Make a rotation matrix, that rotates around the Z axis by `amount` rads'
c = cos(amount)
s = sin(amount)
return np.matrix([
[c,-s, 0, 0],
[s, c, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
])
def rotate(x, y, z, pivot):
'Make a XYZ rotation matrix, with `pivot` as the center of the rotation'
m = rotateX(x) * rotateY(y) * rotateZ(z)
I = np.matrix(np.eye(4))
t = (I-m) * pivot
m[0, 3] = t[0, 0]
m[1, 3] = t[1, 0]
m[2, 3] = t[2, 0]
return m
def eulerAnglesZYX(matrix):
'Extract the Euler angles from an ZYX rotation matrix'
x = atan2(-matrix[1, 2], matrix[2, 2])
cy = sqrt(1 - matrix[0, 2]**2)
y = atan2(matrix[0, 2], cy)
sx = sin(x)
cx = cos(x)
sz = cx * matrix[1, 0] + sx * matrix[2, 0]
cz = cx * matrix[1, 1] + sx * matrix[2, 1]
z = atan2(sz, cz)
return np.array((x, y, z),)
def eulerAnglesXYZ(matrix):
'Extract the Euler angles from an XYZ rotation matrix'
z = atan2(matrix[1, 0], matrix[0, 0])
cy = sqrt(1 - matrix[2, 0]**2)
y = atan2(-matrix[2, 0], cy)
sz = sin(z)
cz = cos(z)
sx = sz * matrix[0, 2] - cz * matrix[1, 2]
cx = cz * matrix[1, 1] - sz * matrix[0, 1]
x = atan2(sx, cx)
return np.array((x, y, z),)
class Camera(object):
def __init__(self, worldPos, rx, ry, rz, coi):
# Initialize the camera orientation. In this case the original
# orientation is built from XYZ Euler angles. orientation is the top
# 3x3 XYZ rotation matrix for the view-to-world matrix, and can more
# easily be thought of as the world space orientation.
self.orientation = \
(rotateZ(rz) * rotateY(ry) * rotateX(rx))
# position is a point in world space for the camera.
self.position = worldPos
# Construct the world-to-view matrix, which is the inverse of the
# view-to-world matrix.
self.view = self.orientation.T * translate(-self.position)
# coi is the "center of interest". It defines a point that is coi
# units in front of the camera, which is the pivot for the tumble
# operation.
self.coi = coi
def tumble(self, azimuth, elevation):
'''Tumble the camera around the center of interest.
Azimuth is the number of radians to rotate around the world-space Y axis.
Elevation is the number of radians to rotate around the view-space X axis.
'''
# Find the world space pivot point. This is the view position in world
# space minus the view direction vector scaled by the center of
# interest distance.
pivotPos = self.position - (self.coi * self.orientation.T[2]).T
# Construct the azimuth and elevation transformation matrices
azimuthMatrix = rotate(0, -azimuth, 0, pivotPos)
elevationMatrix = rotate(elevation, 0, 0, self.view * pivotPos)
# Get the new view matrix
self.view = elevationMatrix * self.view * azimuthMatrix
# Extract the orientation from the new view matrix
self.orientation = np.matrix(self.view).T
self.orientation.T[3] = [0, 0, 0, 1]
# Now extract the new view position
negEye = self.orientation * self.view
self.position = -(negEye.T[3]).T
self.position[3, 0] = 1
np.set_printoptions(precision=3)
pos = np.matrix([[5.321, 5.866, 4.383, 1]]).T
orientation = radians(-60), radians(40), 0
coi = 1
camera = Camera(pos, *orientation, coi=coi)
print 'Initial attributes:'
print np.round(np.degrees(eulerAnglesXYZ(camera.orientation)), 3)
print np.round(camera.position, 3)
print 'Attributes after tumbling:'
camera.tumble(azimuth=radians(-40), elevation=radians(-60))
print np.round(np.degrees(eulerAnglesXYZ(camera.orientation)), 3)
print np.round(camera.position, 3)发布于 2013-05-14 15:43:05
从一开始跟踪你的视图和右向量,并用旋转矩阵更新它们。然后计算你的向上向量。
https://stackoverflow.com/questions/16536416
复制相似问题