I've ported the arcball classes I've been using from vb.net to the iPhone using objective C++, but now I'm having a problem. When I rotate my object, everything is fine. As soon as I pan the view, my center of rotation is no longer at the center of my objects origin like it used to be. Ideally, I'd like to be able to set where in the objects frame of reference the rotation point is. I'm not sure where in the arcball routines I'd need to make changes to do this. The implementation I've based mine off of is found at the below link:
http://www.codeproject.com/KB/openGL/Tao_Arcball.aspx
I've made some small modification to how it behaves and converted it to a touch interface, but how it acts is still the same as this implementation as far as the problem I'm having is concerned.
These links explain some more of the math behind quaternions and matrix rotations:
http://www.j3d.org/matrix_faq/matrfaq_latest.html http://www.gamedev.net/reference/articles/article1095.asp http://en.wikipedia.org/wiki/Quaternion_rotation
The main part of the code that I imagine would have to be modified is below (in vb.net):
Public WriteOnly Property Rotation() As Quat4f
Set(ByVal value As Quat4f)
Dim n, s As Single
Dim xs, ys, zs As Single
Dim wx, wy, wz As Single
Dim xx, xy, xz As Single
Dim yy, yz, zz As Single
M = New Single(3, 3) {}
n = (value.x * value.x) + (value.y * value.y) + (value.z * value.z) + (value.w * value.w)
s = If((n > 0.0f), 2.0f / n, 0.0f)
xs = value.x * s
ys = value.y * s
zs = value.z * s
wx = value.w * xs
wy = value.w * ys
wz = value.w * zs
xx = value.x * xs
xy = value.x * ys
xz = value.x * zs
yy = value.y * ys
yz = value.y * zs
zz = value.z * zs
' rotation
M(0, 0) = 1.0f - (yy + zz)
M(0, 1) = xy - wz
M(0, 2) = xz + wy
M(1, 0) = xy + wz
M(1, 1) = 1.0f - (xx + zz)
M(1, 2) = yz - wx
M(2, 0) = xz - wy
M(2, 1) = yz + wx
M(2, 2) = 1.0f - (xx + yy)
M(3, 3) = 1.0f
' translation (pan)
M(0, 3) = pan_Renamed.x
M(1, 3) = pan_Renamed.y
' scale (zoom)
For i As Integer = 0 To 2
For j As Integer = 0 To 2
M(i, j) *= scl
Next j
Next i
End Set
End Property
I've almost figured out how to do this. I've gotten to the point that I can set the center of rotation for my Arcball, but now I've run into another problem. When I apply the transformations to do rotation about a specified center point, there are two problems:
The model jumps to a different location. I'd like to keep the model at the exact same location and orientation.
The model scales about the new center point, but I'd like to have the model scale about the point that is the average of where the user touches with two fingers.
For number 2, I think I know how to do it, but I'll need to figure out number 1 in order to make number 2 work properly. For number 2, I can just project the average touch point to a plane that is parallel to the near plane but goes through the origin of the part, then make that my center of rotation until the user lifts their fingers up. Any ideas on number 1? The code that I use for changing the center of rotation is below:
glTranslatef(panVector.x, panVector.y, 0); //panVector is a variable that keeps track of the user panning the model
glMultMatrixf(arcballMatrix); //arcball matrix is the 16 element rotation/scale matrix that controls the model orientation
glTranslatef(-centerOfRotation.x, -centerOfRotation.y, -centerOfRotation.z); //centerOfRotation is a point that is set where I want the center of rotation to be
Just for your information, OpenGL applies matrix transformations in reverse order because of how its stacks work. So in my code, the bottom line will be executed first, then on up from there. Effectively it moves the model so its center of rotation is at the origin, then it rotates/scales, then it translates the model where it needs to go for panning.
The problem I believe I'm running into is that I need to add centerOfRotation back when I do my panning, but the problem is that once the model rotates, the centerOfRotation point needs to be transformed somehow to be in a different model space. Before I rotate the model it works fine, but once rotations are introduced, everything blows up.
OK, I finally figured out what was going on. The worst part is that I was doing it correctly the whole time. The only problem I was having was my triangle ray intersection algorithm was returning the wrong point. I fixed that issue and now the controls perform as expected, the center of rotation never moves on the screen, the model just moves so the origin stays in the same location. The code to do the transformation was what I mentioned in the original post:
glTranslatef(panVector.x, panVector.y, 0); //panVector is a variable that keeps track of the user panning the model
glMultMatrixf(arcballMatrix); //arcball matrix is the 16 element rotation/scale matrix that controls the model orientation
glTranslatef(-centerOfRotation.x, -centerOfRotation.y, -centerOfRotation.z); //centerOfRotation is a point that is set where I want the center of rotation to be