protected final 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 (newLeft.equals(Vector3f.ZERO)) {
            if (direction.x != 0) {
                newLeft.set(direction.y, -direction.x, 0f).normalizeLocal();
            } else {
                newLeft.set(0f, direction.z, -direction.y).normalizeLocal();
            }
            if (logger.isLoggable(Level.INFO)) {
                logger.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 (direction.equals(Vector3f.ZERO)) {
            direction.set(Vector3f.UNIT_Z);
            if (logger.isLoggable(Level.INFO)) {
                logger.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.

@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
jme3-jbullet/src/main/java/com/jme3/bullet/control/BetterCharacterControl.java