Spatial functions and snippets

From the CreationKit Wiki
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
endFunction

You 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

See also[edit | edit source]