MinieLibrary/src/main/java/com/jme3/bullet/control/BetterCharacterControl.java
/**
     * This method works similar to Camera.lookAt but where lookAt sets the
     * priority on the direction, this method sets the priority on the up vector
     * so that the result direction vector and rotation is guaranteed to be
     * perpendicular to the up vector.
     *
     * @param rotation The rotation to set the result on or null to create a new
     * Quaternion, this will be set to the new "z-forward" rotation if not null
     * @param direction The direction to base the new look direction on, will be
     * set to the new direction
     * @param worldUpVector The up vector to use, the result direction will be
     * perpendicular to this
     */
This method works similar to Camera.lookAt but where lookAt sets the
priority on the direction, this method sets the priority on the up vector
so that the result direction vector and rotation is guaranteed to be
perpendicular to the up vector.

@param rotation The rotation to set the result on or null to create a new
Quaternion, this will be set to the new "z-forward" rotation if not null
@param direction The direction to base the new look direction on, will be
set to the new direction
@param worldUpVector The up vector to use, the result direction will be
perpendicular to this
This method works similar to Camera . lookAt but where lookAt sets the priority on the direction this method sets the priority on the up vector so that the result direction vector and rotation is guaranteed to be perpendicular to the up vector . @param rotation The rotation to set the result on or null to create a new Quaternion this will be set to the new " z - forward " rotation if not null @param direction The direction to base the new look direction on will be set to the new direction @param worldUpVector The up vector to use the result direction will be perpendicular to this
protected void calculateNewForward(Quaternion rotation,
            Vector3f direction, Vector3f worldUpVector) {
        if (direction == null) {
            return;
        }
        TempVars vars = TempVars.get();
        Vector3f newLeft = vars.vect1;
        Vector3f newLeftNegate = vars.vect2;
        newLeft.set(worldUpVector).crossLocal(direction).normalizeLocal();
        if (MyVector3f.isZero(newLeft)) {
            if (direction.x != 0) {
                newLeft.set(direction.y, -direction.x, 0f).normalizeLocal();
            } else {
                newLeft.set(0f, direction.z, -direction.y).normalizeLocal();
            }
            logger2.log(Level.INFO, "Zero left for direction {0}, up {1}",
                    new Object[]{direction, worldUpVector});
        }
        newLeftNegate.set(newLeft).negateLocal();
        direction.set(worldUpVector).crossLocal(newLeftNegate).normalizeLocal();
        if (MyVector3f.isZero(direction)) {
            direction.set(0f, 0f, 1f);
            logger2.log(Level.INFO, "Zero left for left {0}, up {1}",
                    new Object[]{newLeft, worldUpVector});
        }
        if (rotation != null) {
            rotation.fromAxes(newLeft, worldUpVector, direction);
        }
        vars.release();
    }
protected void calculateNewForward ( Quaternion rotation , Vector3f direction , Vector3f worldUpVector ) { if ( direction == null ) { return ; } TempVars vars = TempVars . get ( ) ; Vector3f newLeft = vars . vect1 ; Vector3f newLeftNegate = vars . vect2 ; newLeft . set ( worldUpVector ) . crossLocal ( direction ) . normalizeLocal ( ) ; if ( MyVector3f . isZero ( newLeft ) ) { if ( direction . x != 0 ) { newLeft . set ( direction . y , - direction . x , 0f ) . normalizeLocal ( ) ; } else { newLeft . set ( 0f , direction . z , - direction . y ) . normalizeLocal ( ) ; } logger2 . log ( Level . INFO , "Zero left for direction {0}, up {1}" , new Object [ ] { direction , worldUpVector } ) ; } newLeftNegate . set ( newLeft ) . negateLocal ( ) ; direction . set ( worldUpVector ) . crossLocal ( newLeftNegate ) . normalizeLocal ( ) ; if ( MyVector3f . isZero ( direction ) ) { direction . set ( 0f , 0f , 1f ) ; logger2 . log ( Level . INFO , "Zero left for left {0}, up {1}" , new Object [ ] { newLeft , worldUpVector } ) ; } if ( rotation != null ) { rotation . fromAxes ( newLeft , worldUpVector , direction ) ; } vars . release ( ) ; }
This method works similar to Camera.lookAt but where lookAt sets the
 priority on the direction, this method sets the priority on the up vector
 so that the result direction vector and rotation is guaranteed to be
 perpendicular to the up vector.
This method works similar to Camera . lookAt but where lookAt sets the priority on the direction this method sets the priority on the up vector so that the result direction vector and rotation is guaranteed to be perpendicular to the up vector .