Exemplo n.º 1
0
  /**
   * 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;
  }