/** * <code>rotateUpTo</code> is a utility function that alters the local rotation to point the Y * axis in the direction given by newUp. * * @param newUp the up vector to use - assumed to be a unit vector. */ public void rotateUpTo(Vector3f newUp) { TempVars vars = TempVars.get(); Vector3f compVecA = vars.vect1; Quaternion q = vars.quat1; // First figure out the current up vector. Vector3f upY = compVecA.set(Vector3f.UNIT_Y); Quaternion rot = localTransform.getRotation(); rot.multLocal(upY); // get angle between vectors float angle = upY.angleBetween(newUp); // figure out rotation axis by taking cross product Vector3f rotAxis = upY.crossLocal(newUp).normalizeLocal(); // Build a rotation quat and apply current local rotation. q.fromAngleNormalAxis(angle, rotAxis); q.mult(rot, rot); vars.release(); setTransformRefresh(); }
private void rotate(final float f) { final Quaternion q = new Quaternion().fromAngleAxis(FastMath.PI * f, Vector3f.UNIT_Y); q.multLocal(viewDirection); setViewDirection(viewDirection); }
/** * This method calculates the value of the curves as a bone track between the specified frames. * * @param targetIndex the index of the target for which the method calculates the tracks * IMPORTANT! Aet to -1 (or any negative number) if you want to load spatial animation. * @param localTranslation the local translation of the object/bone that will be animated by the * track * @param localRotation the local rotation of the object/bone that will be animated by the track * @param localScale the local scale of the object/bone that will be animated by the track * @param startFrame the first frame of tracks (inclusive) * @param stopFrame the last frame of the tracks (inclusive) * @param fps frame rate (frames per second) * @param spatialTrack this flag indicates if the track belongs to a spatial or to a bone; the * difference is important because it appears that bones in blender have the same type of * coordinate system (Y as UP) as jme while other features have different one (Z is UP) * @return bone track for the specified bone */ public Track calculateTrack( int targetIndex, BoneContext boneContext, Vector3f localTranslation, Quaternion localRotation, Vector3f localScale, int startFrame, int stopFrame, int fps, boolean spatialTrack) { if (calculatedTrack == null) { // preparing data for track int framesAmount = stopFrame - startFrame; float timeBetweenFrames = 1.0f / fps; float[] times = new float[framesAmount + 1]; Vector3f[] translations = new Vector3f[framesAmount + 1]; float[] translation = new float[3]; Quaternion[] rotations = new Quaternion[framesAmount + 1]; float[] quaternionRotation = new float[] { localRotation.getX(), localRotation.getY(), localRotation.getZ(), localRotation.getW(), }; float[] eulerRotation = localRotation.toAngles(null); Vector3f[] scales = new Vector3f[framesAmount + 1]; float[] scale = new float[] {localScale.x, localScale.y, localScale.z}; float degreeToRadiansFactor = 1; if (blenderVersion < 250) { // in blender earlier than 2.50 the values are stored in degrees degreeToRadiansFactor *= FastMath.DEG_TO_RAD * 10; // the values in blender are divided by 10, so we need to mult it here } int yIndex = 1, zIndex = 2; boolean swapAxes = spatialTrack && fixUpAxis; if (swapAxes) { yIndex = 2; zIndex = 1; } boolean eulerRotationUsed = false, queternionRotationUsed = false; // calculating track data for (int frame = startFrame; frame <= stopFrame; ++frame) { boolean translationSet = false; translation[0] = translation[1] = translation[2] = 0; int index = frame - startFrame; times[index] = index * timeBetweenFrames; // start + (frame - 1) * timeBetweenFrames; for (int j = 0; j < bezierCurves.length; ++j) { double value = bezierCurves[j].evaluate(frame, BezierCurve.Y_VALUE); switch (bezierCurves[j].getType()) { // LOCATION case AC_LOC_X: translation[0] = (float) value; translationSet = true; break; case AC_LOC_Y: if (swapAxes && value != 0) { value = -value; } translation[yIndex] = (float) value; translationSet = true; break; case AC_LOC_Z: translation[zIndex] = (float) value; translationSet = true; break; // EULER ROTATION case OB_ROT_X: eulerRotationUsed = true; eulerRotation[0] = (float) value * degreeToRadiansFactor; break; case OB_ROT_Y: eulerRotationUsed = true; if (swapAxes && value != 0) { value = -value; } eulerRotation[yIndex] = (float) value * degreeToRadiansFactor; break; case OB_ROT_Z: eulerRotationUsed = true; eulerRotation[zIndex] = (float) value * degreeToRadiansFactor; break; // SIZE case AC_SIZE_X: scale[0] = (float) value; break; case AC_SIZE_Y: scale[yIndex] = (float) value; break; case AC_SIZE_Z: scale[zIndex] = (float) value; break; // QUATERNION ROTATION (used with bone animation) case AC_QUAT_W: queternionRotationUsed = true; quaternionRotation[3] = (float) value; break; case AC_QUAT_X: queternionRotationUsed = true; quaternionRotation[0] = (float) value; break; case AC_QUAT_Y: queternionRotationUsed = true; if (swapAxes && value != 0) { value = -value; } quaternionRotation[yIndex] = (float) value; break; case AC_QUAT_Z: quaternionRotation[zIndex] = (float) value; break; default: LOGGER.log(Level.WARNING, "Unknown ipo curve type: {0}.", bezierCurves[j].getType()); } } if (translationSet) { translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2])); } else { translations[index] = new Vector3f(); } if (boneContext != null) { if (boneContext.getBone().getParent() == null && boneContext.is(BoneContext.NO_LOCAL_LOCATION)) { float temp = translations[index].z; translations[index].z = -translations[index].y; translations[index].y = temp; } } if (queternionRotationUsed) { rotations[index] = new Quaternion( quaternionRotation[0], quaternionRotation[1], quaternionRotation[2], quaternionRotation[3]); } else { rotations[index] = new Quaternion().fromAngles(eulerRotation); } scales[index] = new Vector3f(scale[0], scale[1], scale[2]); } if (spatialTrack) { calculatedTrack = new SpatialTrack(times, translations, rotations, scales); } else { calculatedTrack = new BoneTrack(targetIndex, times, translations, rotations, scales); } if (queternionRotationUsed && eulerRotationUsed) { LOGGER.warning( "Animation uses both euler and quaternion tracks for rotations. Quaternion rotation is applied. Make sure that this is what you wanted!"); } } return calculatedTrack; }