// 線形補間 public static QuaternionKeyframe Lerp(QuaternionKeyframe from, QuaternionKeyframe to, Vector2 t) { return(new QuaternionKeyframe( Mathf.Lerp(from.time, to.time, t.x), Quaternion.Slerp(from.value, to.value, t.y) )); }
//计算四元数的插值 void _hermiteInterpolateQuaternion(QuaternionKeyframe frame, QuaternionKeyframe nextFrame, float t, float dur, Quaternion calcOut) { Quaternion p0 = frame.value; Vector4 tan0 = frame.outTangent; Quaternion p1 = nextFrame.value; Vector4 tan1 = nextFrame.inTangent; float t2 = t * t; float t3 = t2 * t; float a = 2.0f * t3 - 3.0f * t2 + 1.0f; float b = t3 - 2.0f * t2 + t; float c = t3 - t2; float d = -2.0f * t3 + 3.0f * t2; float t0 = tan0.x, t1 = tan1.x; if (/*__JS__ */ !float.IsInfinity(t0) && !float.IsInfinity(t1)) { calcOut.x = a * p0.x + b * t0 * dur + c * t1 * dur + d * p1.x; } else { calcOut.x = p0.x; } t0 = tan0.y; t1 = tan1.y; if (/*__JS__ */ !float.IsInfinity(t0) && !float.IsInfinity(t1)) { calcOut.y = a * p0.y + b * t0 * dur + c * t1 * dur + d * p1.y; } else { calcOut.y = p0.y; } t0 = tan0.z; t1 = tan1.z; if (/*__JS__ */ !float.IsInfinity(t0) && !float.IsInfinity(t1)) { calcOut.z = a * p0.z + b * t0 * dur + c * t1 * dur + d * p1.z; } else { calcOut.z = p0.z; } t0 = tan0.w; t1 = tan1.w; if (/*__JS__ */ !float.IsInfinity(t0) && !float.IsInfinity(t1)) { calcOut.w = a * p0.w + b * t0 * dur + c * t1 * dur + d * p1.w; } else { calcOut.w = p0.w; } }
// あるボーンに含まれるキーフレを抽出 // これは回転のみ void CreateKeysForRotation(MMD.VMD.VMDFormat format, AnimationClip clip, string current_bone, string bone_path, int interpolationQuality) { try { List <MMD.VMD.VMDFormat.Motion> mlist = format.motion_list.motion[current_bone]; int keyframeCount = GetKeyframeCount(mlist, 3, interpolationQuality); QuaternionKeyframe[] r_keys = new QuaternionKeyframe[keyframeCount]; QuaternionKeyframe r_prev_key = null; int ir = 0; for (int i = 0; i < mlist.Count; i++) { const float tick_time = 1.0f / 30.0f; float tick = mlist[i].flame_no * tick_time; Quaternion rotation = mlist[i].rotation; QuaternionKeyframe r_cur_key = new QuaternionKeyframe(tick, rotation); QuaternionKeyframe.AddBezierKeyframes(mlist[i].interpolation, 3, r_prev_key, r_cur_key, interpolationQuality, ref r_keys, ref ir); r_prev_key = r_cur_key; } Keyframe[] rx_keys = null; Keyframe[] ry_keys = null; Keyframe[] rz_keys = null; ToKeyframesForRotation(r_keys, ref rx_keys, ref ry_keys, ref rz_keys); AnimationCurve curve_x = new AnimationCurve(rx_keys); AnimationCurve curve_y = new AnimationCurve(ry_keys); AnimationCurve curve_z = new AnimationCurve(rz_keys); // ここで回転オイラー角をセット(補間はクォータニオン) #if !UNITY_4_2 //4.3以降 AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(bone_path, typeof(Transform), "localEulerAngles.x"), curve_x); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(bone_path, typeof(Transform), "localEulerAngles.y"), curve_y); AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(bone_path, typeof(Transform), "localEulerAngles.z"), curve_z); #else AnimationUtility.SetEditorCurve(clip, bone_path, typeof(Transform), "localEulerAngles.x", curve_x); AnimationUtility.SetEditorCurve(clip, bone_path, typeof(Transform), "localEulerAngles.y", curve_y); AnimationUtility.SetEditorCurve(clip, bone_path, typeof(Transform), "localEulerAngles.z", curve_z); #endif } catch (KeyNotFoundException) { //Debug.LogError("互換性のないボーンが読み込まれました:" + bone_path); } }
// ベジェを線形補間で近似したキーフレームを追加する public static void AddBezierKeyframes(byte[] interpolation, int type, QuaternionKeyframe prev_keyframe, QuaternionKeyframe cur_keyframe, int interpolationQuality, ref QuaternionKeyframe[] keyframes, ref int index) { if (prev_keyframe == null || IsLinear(interpolation, type)) { keyframes[index++] = cur_keyframe; } else { Vector2 bezierHandleA = GetBezierHandle(interpolation, type, 0); Vector2 bezierHandleB = GetBezierHandle(interpolation, type, 1); int sampleCount = interpolationQuality; for (int j = 0; j < sampleCount; j++) { float t = (j + 1) / (float)sampleCount; Vector2 sample = SampleBezier(bezierHandleA, bezierHandleB, t); keyframes[index++] = QuaternionKeyframe.Lerp(prev_keyframe, cur_keyframe, sample); } } }