Gimbal lock – ShiVa Engine

Gimbal lock

ShiVa internally handles rotations as quaternions. But this is no use to you since ShiVa script only returns Euler values. Manipulating these values directly can lead to unwanted results if not done properly. Glitches known as Gimbal Lock may become visible.
To work with truly free rotations, either
a) work exclusively in local space like object.rotateToAxisAngle ( hObj, 0, 0, 1, 180, object.kLocalSpace, 0.04 ) or
b) use a dummy in the rotational center of the object with a rotation of 0,0,0. The workflow looks as follows:
1. create helper at the rotation center (“object root”)
2. Loop every frame:
2.1 parent object to helper
2.2 rotate helper by the amount you want
2.3 unparent object from helper
2.4 reset helper to 0,0,0 rotation
The following function shows how to move a character on top of a sphere with no gimbal lock whatsoever:

--------------------------------------------------------------------------------
function main.onEnterFrame (  )
--------------------------------------------------------------------------------
if not this.boxman ( ) then return nil end
local bx,by,bz = object.getTranslation ( this.boxman ( ), object.kGlobalSpace )
------- MOVEMENT OF THE CHARACTER -----------------------------------------------
    -- update scene virtual planet gravity
    local speed = 2 -- movement speed
    -- get the origin
    local x,y,z = 0,0,0
    x,y,z = this.planet1x ( ),this.planet1y ( ),this.planet1z ( )
    local rx,ry,rz ,ux,uy,uz= this.removeGimbalLock ( x,y,z )
    -- 1. set up a dummy at the center of your planet
    -- set the dummy location
    object.setTranslation ( this.hDummy ( ), x,y,z, object.kGlobalSpace )
    object.setRotation ( this.hDummy ( ),0,0,0, object.kGlobalSpace )
    -- 2.1. parent your boxman to that dummy
    object.setParent        ( this.boxman ( ), this.hDummy ( ), true )
    -- 2.2. rotate the dummy (take care of spaces.
    -- since your character can be looking at any direction,
    -- you would have to rotate around the local x axis of the boxman,
    -- translated into global space)
    local Xbx, Xby, Xbz = object.getXAxis ( this.boxman( ), object.kGlobalSpace )
    object.rotateAxisAngle ( this.hDummy(), Xbx, Xby, Xbz, -rz*speed, object.kLocalSpace )
    local Zbx, Zby, Zbz = object.getZAxis ( this.boxman( ), object.kGlobalSpace )
    object.rotateAxisAngle ( this.hDummy(), Zbx, Zby, Zbz, rx*speed, object.kLocalSpace )
    -- 2.3. unparent the boxman from the dummy (setParent with nil)
    object.setParent( this.boxman ( ), nil, true )
    -- update animations
    if this.rotatex ( )~=0 or this.rotatey ( )~=0 or this.rotatez ( )~=0 then
        -- animate
        object.sendEvent ( this.boxman ( ), "boxman", "onChangeAnim", 1 )
    else
        -- dont animate
        object.sendEvent ( this.boxman ( ), "boxman", "onChangeAnim", 0 )
    end
--------------------------------------------------------------------------------
end
--------------------------------------------------------------------------------



Need more answers?

  • slackBanner