You may be in a situation where you need to be able to precisely rotate one ObjectReference around another ObjectReference. This proved to be somewhat challenging if you are not familiar with rotation matricies (like me).
This function takes in an akOrigin (the ObjectReference to act as the center) and an akObject (the ObjectReference you want to be rotated). Note that this function returns a float[3] array; it does not perform the actual rotation. It returns a new set of X, Y, Z worldspace coordinates in the [0], [1], and [2] elements of the array that correspond to the coordinates your reference should be located at, once it's been rotated by the degrees you specified in the function call. You will need to create a new array to accept the return of this function. Once you have the coordinates returned by this function, you can call whatever movement function you like at that point (most likely SplineTranslateTo) using whatever parameters you choose.
Rotates a point (coordinates of akObject) offset from the center of rotation (akOrigin) by the supplied degrees fAngleX, fAngleY, fAngleZ, and returns the new desired position of the point.
Spoiler
float[] function GetPosXYZRotateAroundRef(ObjectReference akOrigin, ObjectReference akObject, float fAngleX, float fAngleY, float fAngleZ)
;-----------\
;Description \ Author: Chesko
;----------------------------------------------------------------
;Rotates a point (coordinates of akObject) offset from the center of
;rotation (akOrigin) by the supplied degrees fAngleX, fAngleY,
;fAngleZ, and returns the new desired position of the point.
;-------------\
;Return Values \
;----------------------------------------------------------------
; fNewPos[0] = The new X position of the point
; fNewPos[1] = The new Y position of the point
; fNewPos[2] = The new Z position of the point
; |1 0 0 |
;Rx(t) = |0 cos(t) -sin(t) |
; |0 sin(t) cos(t) |
;
; |cos(t) 0 sin(t) |
;Ry(t) = |0 1 0 |
; |-sin(t) 0 cos(t) |
;
; |cos(t) -sin(t) 0 |
;Rz(t) = |sin(t) cos(t) 0 |
; |0 0 1 |
;R * v = Rv, where R = rotation matrix, v = column vector of point [ x y z ], Rv = column vector of point after rotation
fAngleZ = -(fAngleZ) ;Invert Z angle to account for the game's interpretation of Z rotation
float myOriginPosX = akOrigin.GetPositionX()
float myOriginPosY = akOrigin.GetPositionY()
float myOriginPosZ = akOrigin.GetPositionZ()
float fInitialX = akObject.GetPositionX() - myOriginPosX
float fInitialY = akObject.GetPositionY() - myOriginPosY
float fInitialZ = akObject.GetPositionZ() - myOriginPosZ
float fNewX
float fNewY
float fNewZ
;Objects in Skyrim are rotated in order of Z, Y, X, so we will do that here as well.
;Z-axis rotation matrix
float fVectorX = fInitialX
float fVectorY = fInitialY
float fVectorZ = fInitialZ
fNewX = (fVectorX * cos(fAngleZ)) + (fVectorY * sin(-fAngleZ)) + (fVectorZ * 0)
fNewY = (fVectorX * sin(fAngleZ)) + (fVectorY * cos(fAngleZ)) + (fVectorZ * 0)
fNewZ = (fVectorX * 0) + (fVectorY * 0) + (fVectorZ * 1)
;Y-axis rotation matrix
fVectorX = fNewX
fVectorY = fNewY
fVectorZ = fNewZ
fNewX = (fVectorX * cos(fAngleY)) + (fVectorY * 0) + (fVectorZ * sin(fAngleY))
fNewY = (fVectorX * 0) + (fVectorY * 1) + (fVectorZ * 0)
fNewZ = (fVectorX * sin(-fAngleY)) + (fVectorY * 0) + (fVectorZ * cos(fAngleY))
;X-axis rotation matrix
fVectorX = fNewX
fVectorY = fNewY
fVectorZ = fNewZ
fNewX = (fVectorX * 1) + (fVectorY * 0) + (fVectorZ * 0)
fNewY = (fVectorX * 0) + (fVectorY * cos(fAngleX)) + (fVectorZ * sin(-fAngleX))
fNewZ = (fVectorX * 0) + (fVectorY * sin(fAngleX)) + (fVectorZ * cos(fAngleX))
;Return result
float[] fNewPos = new float[3]
fNewPos[0] = fNewX + myOriginPosX
fNewPos[1] = fNewY + myOriginPosY
fNewPos[2] = fNewZ + myOriginPosZ
return fNewPos
endFunction
Example:
float[] myNewPos = new float[3]
myNewPos = GetPosXYZRotateAroundRef(PlayerRef, myCabbage, 25.0, 0.0, 0.0) ;Find out where myCabbage would be if rotated 25.0 degrees on the X axis around the Player.
myCabbage.SplineTranslateTo(myNewPos[0], myNewPos[1], myNewPos[2], 0.0, 0.0, 0.0, 1.0, 200.0) ;Move the cabbage to the new rotated position
Minor update. Made a change that inverts the Z angle before computation, to account for the game's interpretation of z-rotation (it's backwards). I can't edit the pastebin post, so make sure you get your code from the post up top. If you want to add the change yourself, just change:
;R * v = Rv, where R = rotation matrix, v = column vector of point [ x y z ], Rv = column vector of point after rotation
to
;R * v = Rv, where R = rotation matrix, v = column vector of point [ x y z ], Rv = column vector of point after rotation
fAngleZ = -(fAngleZ)
...since '(fVectorZ * 0)' will always equal 0 regardless of fVectorZ's value (and other such instances)?
Forum formatting: You can retain formatting, but you have to turn off the WYSIWYG editor with the light switch looking thingy in the upper left when posting/editing.
Spoiler
float[] function GetPosXYZRotateAroundRef(ObjectReference akOrigin, ObjectReference akObject, float fAngleX, float fAngleY, float fAngleZ)
;-----------\
;Description \ Author: Chesko
;----------------------------------------------------------------
;Rotates a point (coordinates of akObject) offset from the center of
;rotation (akOrigin) by the supplied degrees fAngleX, fAngleY,
;fAngleZ, and returns the new desired position of the point.
;-------------\
;Return Values \
;----------------------------------------------------------------
; fNewPos[0] = The new X position of the point
; fNewPos[1] = The new Y position of the point
; fNewPos[2] = The new Z position of the point
; |1 0 0 |
;Rx(t) = |0 cos(t) -sin(t) |
; |0 sin(t) cos(t) |
;
; |cos(t) 0 sin(t) |
;Ry(t) = |0 1 0 |
; |-sin(t) 0 cos(t) |
;
; |cos(t) -sin(t) 0 |
;Rz(t) = |sin(t) cos(t) 0 |
; |0 0 1 |
;R * v = Rv, where R = rotation matrix, v = column vector of point [ x y z ], Rv = column vector of point after rotation
fAngleZ = -(fAngleZ) ;Invert Z angle to account for the game's interpretation of Z rotation'
float myOriginPosX = akOrigin.GetPositionX()
float myOriginPosY = akOrigin.GetPositionY()
float myOriginPosZ = akOrigin.GetPositionZ()
float fInitialX = akObject.GetPositionX() - myOriginPosX
float fInitialY = akObject.GetPositionY() - myOriginPosY
float fInitialZ = akObject.GetPositionZ() - myOriginPosZ
float fNewX
float fNewY
float fNewZ
;Objects in Skyrim are rotated in order of Z, Y, X, so we will do that here as well.
;Z-axis rotation matrix
float fVectorX = fInitialX
float fVectorY = fInitialY
float fVectorZ = fInitialZ
fNewX = (fVectorX * cos(fAngleZ)) + (fVectorY * sin(-fAngleZ))
fNewY = (fVectorX * sin(fAngleZ)) + (fVectorY * cos(fAngleZ))
fNewZ = fVectorZ
;Y-axis rotation matrix
fVectorX = fNewX
fVectorY = fNewY
fVectorZ = fNewZ
fNewX = (fVectorX * cos(fAngleY)) + (fVectorZ * sin(fAngleY))
fNewY = fVectorY
fNewZ = (fVectorX * sin(-fAngleY)) + (fVectorZ * cos(fAngleY))
;X-axis rotation matrix
fVectorX = fNewX
fVectorY = fNewY
fVectorZ = fNewZ
fNewX = fVectorX
fNewY = (fVectorY * cos(fAngleX)) + (fVectorZ * sin(-fAngleX))
fNewZ = (fVectorY * sin(fAngleX)) + (fVectorZ * cos(fAngleX))
;Return result
float[] fNewPos = new float[3]
fNewPos[0] = fNewX + myOriginPosX
fNewPos[1] = fNewY + myOriginPosY
fNewPos[2] = fNewZ + myOriginPosZ
return fNewPos
endFunction
Code will lose its indentation if it's copied out of a post, but not if you quote to view it with that switch toggled to off. Also, if you want to kill the pink, find the '/" that starts a string and close it with another '/".
Very cool function! Thanks for sharing, Chesko
Edited by JustinOther, 07 October 2012 - 04:51 PM.
JustinOther - yes, there are several parts of the matrix multiplication that could be condensed. I left it verbose such that I could debug it in case something came up, and for algebraic clarity. And I don't think the additional time cost means very much in this case. And thanks for reposting the well-formatted version. (Make sure to add the line that inverses the z-angle!)
Small note - you shouldn't have to allocate the array before calling the function, since the function allocates a new one anyway and returns it (the one you allocate before calling the function gets garbage collected).