Spatial functions and snippets
Jump to navigation
Jump to search
This pages aims to present a few useful snippets for working with spatial transformations and computations in Skyrim.
Rotation matrix[edit | edit source]
This code is useful if you want to compute the position that results from a translation from an origin, then a rotation around that origin. This is useful if, for example, you want to place something on an "orbit" around another object. It was created by Chesko.
;-----------\
;Description \ Author: Chesko
;----------------------------------------------------------------
;Rotates a point (akObject offset from the center of
;rotation (akOrigin) by the supplied degrees fAngleX, fAngleY,
;fAngleZ, and returns the new 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
;Provided angles must follow Bethesda's conventions (CW Z angle for example).
float[] function GetPosXYZRotateAroundRef(ObjectReference akOrigin, ObjectReference akObject, float fAngleX, float fAngleY, float fAngleZ)
fAngleX = -(fAngleX)
fAngleY = -(fAngleY)
fAngleZ = -(fAngleZ)
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
endFunctionYou may have to modify it to suit your needs.
- myOriginPosX/Y/Z define the origin, the point from which we translate from and around which we rotate.
- fVectorX/Y/Z define the translation from the origin.
- fAngleX/Y/Z define the angles for the rotation around the origin.
Function to find angles from one reference to another (ie angles to face)[edit | edit source]
;Skyrim uses right hand coordinate system (X=Eastings, Y=Northings - and up!)
;Skyrim uses left handed XYZ global angles
;Skyrim undergoes ZYX angle calculations (ie in that order)
;Roll not supported!
;Assumes mesh in nif is 'facing' the 'Y' axis
float[] function getAnglesToFaceRef(ObjectReference origin, ObjectReference target)
float deltaX=target.GetPositionX()-origin.GetPositionX()
float deltaY=target.GetPositionY()-origin.GetPositionY()
float deltaZ=target.GetPositionZ()-origin.GetPositionZ()
float localAngleX=atan2(-deltaZ, math.sqrt((deltaX*deltaX)+(deltaY*deltaY))) ; pitch
float localAngleY=0 ; roll - keeping this as zero, other values will break this
float localAngleZ=RPDefault_Math.atan2(deltaX, deltaY) ; yaw
float globalAngleX=localAngleX*Math.Cos(localAngleZ)+localAngleY*Math.Sin(localAngleZ)
float globalAngleY=localAngleY*Math.Cos(localAngleZ)-localAngleX*Math.Sin(localAngleZ)
float globalAngleZ=localAngleZ ; same as local
float[] toReturn=new float[3]
toReturn[0]=globalAngleX
toReturn[1]=globalAngleY
toReturn[2]=globalAngleZ
return toReturn
endfunction