c++ - Opengl: Keeping Arcball camera up-vector alligned with y-axis -


i'm trying mimic way camera rotates in maya. arcball in maya aligned with y-axis. no matter up-vector pointing, it's still rotated or registered it's up-vector along y-axis.

i've been able implement arcball in opengl using c++ , qt. can't figure out how keep it's up-vector aligned. i've been able keep aligned @ times code below:

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(); } 

this works until position @ 90-degrees, right vector changes , inverted.

so instead i've been maintaining total rotation (in quaternions) , rotating original positions (up, right, pos) it. works best keep coherent, can't align up-vector y-axis. below function rotation.

void ccamera::setrot (qquaternion q) {     tot = tot * q;      position  = tot.rotatedvector(positionoriginal);      upvector = tot.rotatedvector(upvectororiginal);     upvector.normalize();      rightvector  = tot.rotatedvector(rightvectororiginal);     rightvector.normalize(); } 

the qquaternion q generated axis-angle pair derived mouse drag. i'm confident done correctly. rotation fine, doesn't keep orientation aligned.

i've noticed in chosen implementation, dragging in corners provides rotation around view direction, , can realign up-vector straighten out world's y-axis direction. if figure out how roll 2 rotations each time make sure it's straight. however, i'm not sure how go this.

the reason isn't working because maya's camera manipulation in viewport not use arcball interface. want maya's tumble command. best resource i've found explaining this document professor orr's computer graphics class.

moving mouse left , right corresponds azimuth angle, , specifies rotation around world space y axis. moving mouse , down corresponds elevation angle, , specifies rotation around view space x axis. goal generate new world-to-view matrix, extract new camera orientation , eye position matrix, based on you've parameterized camera.

start current world-to-view matrix. next, need define pivot point in world space. pivot point work begin with, , can simplest use world origin.

recall pure rotation matrices generate rotations centered around origin. means rotate around arbitrary pivot point, first translate origin, perform rotation, , translate back. remember transformation composition happens right left, negative translation origin goes on far right:

translate(pivotposition) * rotate(anglex, angley, anglez) * translate(-pivotposition) 

we can use calculate azimuth rotation component, rotation around world y axis:

azimuthrotation = translate(pivotposition) * rotatey(angley) * translate(-pivotposition) 

we have little additional work elevation rotation component, because happens in view space, around view space x axis:

elevationrotation = translate(worldtoviewmatrix * pivotposition) * rotatex(anglex) * translate(worldtoviewmatrix * -pivotposition) 

we can new view matrix with:

newworldtoviewmatrix = elevationrotation * worldtoviewmatrix * azimuthrotation 

now have new worldtoview matrix, we're left having extract new world space position , orientation view matrix. this, want viewtoworld matrix, inverse of worldtoview matrix.

neworientation = transpose(mat3(newworldtoviewmatrix)) newposition = -((neworientation * newworldtoviewmatrix).column(3)) 

at point, have elements separated. if camera parameterized you're storing quaternion orientation, need rotation matrix -> quaternion conversion. of course, maya going convert euler angles display in channel box, dependent on camera's rotation order (note math tumbling doesn't change when rotation order changes, way rotation matrix -> euler angles conversion done).

here's sample implementation in python:

#!/usr/bin/env python  import numpy np math import *  def translate(amount):     'make translation matrix, move `amount`'     t = np.matrix(np.eye(4))     t[3] = amount.t     t[3, 3] = 1     return t.t  def rotatex(amount):     'make rotation matrix, rotates around x axis `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 rotation matrix, rotates around y axis `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 rotation matrix, rotates around z axis `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 xyz rotation matrix, `pivot` center of rotation'     m = rotatex(x) * rotatey(y) * rotatez(z)      = 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 euler angles 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 euler angles 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 camera orientation.  in case original         # orientation built xyz euler angles.  orientation top         # 3x3 xyz rotation matrix view-to-world matrix, , can more         # thought of world space orientation.         self.orientation = \             (rotatez(rz) * rotatey(ry) * rotatex(rx))          # position point in world space camera.         self.position = worldpos          # construct world-to-view matrix, inverse of         # view-to-world matrix.         self.view = self.orientation.t * translate(-self.position)          # coi "center of interest".  defines point coi         # units in front of camera, pivot tumble         # operation.         self.coi = coi      def tumble(self, azimuth, elevation):         '''tumble camera around center of interest.          azimuth number of radians rotate around world-space y axis.         elevation number of radians rotate around view-space x axis.         '''         # find world space pivot point.  view position in world         # space minus view direction vector scaled center of         # interest distance.         pivotpos = self.position - (self.coi * self.orientation.t[2]).t          # construct azimuth , elevation transformation matrices         azimuthmatrix = rotate(0, -azimuth, 0, pivotpos)          elevationmatrix = rotate(elevation, 0, 0, self.view * pivotpos)          # new view matrix         self.view = elevationmatrix * self.view * azimuthmatrix          # extract orientation new view matrix         self.orientation = np.matrix(self.view).t         self.orientation.t[3] = [0, 0, 0, 1]          # extract 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) 

Comments

Popular posts from this blog

c# - DetailsView in ASP.Net - How to add another column on the side/add a control in each row? -

javascript - firefox memory leak -

Trying to import CSV file to a SQL Server database using asp.net and c# - can't find what I'm missing -