public static string ToStringTrimed(this Assimp.Quaternion q) { string d = "+0.000;-0.000"; // "0.00"; int pamt = 8; return(q.X.ToString(d).PadRight(pamt) + ", " + q.Y.ToString(d).PadRight(pamt) + ", " + q.Z.ToString(d).PadRight(pamt) + "w " + q.W.ToString(d).PadRight(pamt)); }
private Matrix4 CalcInterpolatedRotation(float animationTime, NodeAnimation channel) { Matrix4x4 matrix; if (channel.ScalingKeysCount == 1) { matrix = channel.RotationKeys[0].Value.GetMatrix(); } var rotateIndex = FindRotation(animationTime, channel); var nextRotateIndex = rotateIndex + 1; if (nextRotateIndex < channel.RotationKeysCount) { var rotateKey = channel.RotationKeys[rotateIndex]; var nextRotateKey = channel.RotationKeys[nextRotateIndex]; var deltaTime = nextRotateKey.Time - rotateKey.Time; var factor = (animationTime - rotateKey.Time) / deltaTime; matrix = Quaternion.Slerp(rotateKey.Value, nextRotateKey.Value, factor).GetMatrix(); } else { matrix = channel.RotationKeys[0].Value.GetMatrix(); } return(FromMatrix(matrix)); }
static System.Numerics.Quaternion ConvertQuat(Assimp.Quaternion Q) { NumMatrix4x4.Decompose(ConvertMatrix(new AssMatrix4x4(Q.GetMatrix())), out Vector3 _S, out System.Numerics.Quaternion Quat, out Vector3 _T); return(Quat); // return new System.Numerics.Quaternion(Q.X, Q.Y, Q.Z, Q.W); }
Assimp.Quaternion nlerp(Assimp.Quaternion a, Assimp.Quaternion b, float blend) { //cout << a.w + a.x + a.y + a.z << endl; a.Normalize(); b.Normalize(); Assimp.Quaternion result; float dot_product = a.X * b.X + a.Y * b.Y + a.Z * b.Z + a.W * b.W; float one_minus_blend = 1.0f - blend; if (dot_product < 0.0f) { result.X = a.X * one_minus_blend + blend * -b.X; result.Y = a.Y * one_minus_blend + blend * -b.Y; result.Z = a.Z * one_minus_blend + blend * -b.Z; result.W = a.W * one_minus_blend + blend * -b.W; } else { result.X = a.X * one_minus_blend + blend * b.X; result.Y = a.Y * one_minus_blend + blend * b.Y; result.Z = a.Z * one_minus_blend + blend * b.Z; result.W = a.W * one_minus_blend + blend * b.W; } result.Normalize(); return(result); }
private static Vector3 ToEulerAngles(Assimp.Quaternion q) { Vector3 angles; double sinr_cosp = 2 * (q.W * q.X + q.Y * q.Z); double cosr_cosp = 1 - 2 * (q.X * q.X + q.Y * q.Y); angles.X = (float)Math.Atan2(sinr_cosp, cosr_cosp); double sinp = 2 * (q.W * q.Y - q.Z * q.X); if (Math.Abs(sinp) >= 1) { angles.Y = (float)(Math.Sign(sinp) * Math.PI / 2); } else { angles.Y = (float)Math.Asin(sinp); } double siny_cosp = 2 * (q.W * q.Z + q.X * q.Y); double cosy_cosp = 1 - 2 * (q.Y * q.Y + q.Z * q.Z); angles.Z = (float)Math.Atan2(siny_cosp, cosy_cosp); return(angles); }
private aiMatrix4x4 InterpolateRotation(double time, NodeAnimationChannel channel) { aiQuaternion rotation; if (channel.RotationKeyCount == 1) { rotation = channel.RotationKeys[0].Value; } else { uint frameIndex = 0; for (uint i = 0; i < channel.RotationKeyCount - 1; i++) { if (time < (float)channel.RotationKeys[(int)(i + 1)].Time) { frameIndex = i; break; } } QuaternionKey currentFrame = channel.RotationKeys[(int)frameIndex]; QuaternionKey nextFrame = channel.RotationKeys[(int)((frameIndex + 1) % channel.RotationKeyCount)]; double delta = (time - (float)currentFrame.Time) / (float)(nextFrame.Time - currentFrame.Time); aiQuaternion start = currentFrame.Value; aiQuaternion end = nextFrame.Value; rotation = aiQuaternion.Slerp(start, end, (float)delta); rotation.Normalize(); } return(rotation.GetMatrix()); }
public static Vector3D FromQ2(Assimp.Quaternion q1) { float sqw = q1.W * q1.W; float sqx = q1.X * q1.X; float sqy = q1.Y * q1.Y; float sqz = q1.Z * q1.Z; float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor float test = q1.X * q1.W - q1.Y * q1.Z; Vector3D v; if (test > 0.4995f * unit) { // singularity at north pole v.Y = 2f * (float)Math.Atan2(q1.Y, q1.X); v.X = (float)Math.PI / 2; v.Z = 0; return(NormalizeAngles(v * (float)(180 / Math.PI))); } if (test < -0.4995f * unit) { // singularity at south pole v.Y = -2f * (float)Math.Atan2(q1.Y, q1.X); v.X = -(float)Math.PI / 2; v.Z = 0; return(NormalizeAngles(v * (float)(180 / Math.PI))); } Quaternion q = new Assimp.Quaternion(q1.W, q1.Z, q1.X, q1.Y); v.Y = (float)Math.Atan2(2f * q.X * q.W + 2f * q.Y * q.Z, 1 - 2f * (q.Z * q.Z + q.W * q.W)); // Yaw v.X = (float)Math.Asin(2f * (q.X * q.Z - q.W * q.Y)); // Pitch v.Z = (float)Math.Atan2(2f * q.X * q.Y + 2f * q.Z * q.W, 1 - 2f * (q.Y * q.Y + q.Z * q.Z)); // Roll return(NormalizeAngles(v * (float)(180 / Math.PI))); }
// quat4 -> (roll, pitch, yaw) private static void QuatToEulerXyz(ref Quaternion q1, out Vector3 outVector) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ double sqw = q1.W * q1.W; double sqx = q1.X * q1.X; double sqy = q1.Y * q1.Y; double sqz = q1.Z * q1.Z; double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor double test = q1.X * q1.Y + q1.Z * q1.W; if (test > 0.499 * unit) // singularity at north pole { outVector.Z = (float)(2 * Math.Atan2(q1.X, q1.W)); outVector.Y = (float)(Math.PI / 2); outVector.X = 0; return; } if (test < -0.499 * unit) // singularity at south pole { outVector.Z = (float)(-2 * Math.Atan2(q1.X, q1.W)); outVector.Y = (float)(-Math.PI / 2); outVector.X = 0; return; } outVector.Z = (float)Math.Atan2(2 * q1.Y * q1.W - 2 * q1.X * q1.Z, sqx - sqy - sqz + sqw); outVector.Y = (float)Math.Asin(2 * test / unit); outVector.X = (float)Math.Atan2(2 * q1.X * q1.W - 2 * q1.Y * q1.Z, -sqx + sqy - sqz + sqw); }
// T O M G (convert for use with MonoGame) - QUATERNION public static XNA.Quaternion ToMg(this Assimp.Quaternion aq) { var m = aq.GetMatrix(); var n = m.ToMgTransposed(); var q = XNA.Quaternion.CreateFromRotationMatrix(n); return(q); }
private OpenTK.Quaternion TKQuaternion(Assimp.Quaternion rot) { OpenTK.Quaternion quat = new OpenTK.Quaternion(); quat.X = rot.X; quat.Y = rot.Y; quat.Z = rot.Z; quat.W = rot.W; return quat; }
public static OpenTK.Quaternion TKQuaternion(Assimp.Quaternion rot) { OpenTK.Quaternion quat = new OpenTK.Quaternion(); quat.X = rot.X; quat.Y = rot.Y; quat.Z = rot.Z; quat.W = rot.W; return(quat); }
public static Assimp.Quaternion ToQuaternion(this SlimDX.Quaternion q) { Assimp.Quaternion ret = new Assimp.Quaternion(); ret.W = q.W; ret.X = q.X; ret.Y = q.Y; ret.Z = q.Z; return(ret); }
public static Assimp.Quaternion convertQuaternion(OpenTK.Quaternion localQuat) { Assimp.Quaternion q = new Assimp.Quaternion(); q.X = localQuat.X; q.Y = localQuat.Y; q.Z = localQuat.Z; q.W = localQuat.W; return(q); }
Matrix GetMatrix(Vector3D pscale, Vector3D pPosition, Assimp.Quaternion pRot) { // create the combined transformation matrix var mat = new Matrix4x4(pRot.GetMatrix()); mat.A1 *= pscale.X; mat.B1 *= pscale.X; mat.C1 *= pscale.X; mat.A2 *= pscale.Y; mat.B2 *= pscale.Y; mat.C2 *= pscale.Y; mat.A3 *= pscale.Z; mat.B3 *= pscale.Z; mat.C3 *= pscale.Z; mat.A4 = pPosition.X; mat.B4 = pPosition.Y; mat.C4 = pPosition.Z; return(mat.ToMatrix()); }
IEnumerable <Frame> GetFrames(NodeAnimationChannel nch) { var m = new[] { nch.PositionKeyCount, nch.RotationKeyCount, nch.ScalingKeyCount }.Max(); for (int i = 0; i < m; i++) { var pos = new Vector3D(); var scale = new Vector3D(1); var rot = new Assimp.Quaternion(1, 0, 0, 0); if (nch.HasPositionKeys) { if (i < nch.PositionKeyCount) { pos = nch.PositionKeys[i].Value; } else { pos = nch.PositionKeys.Last().Value; } } if (nch.HasRotationKeys) { if (i < nch.RotationKeyCount) { rot = nch.RotationKeys[i].Value; } else { rot = nch.RotationKeys.Last().Value; } } if (nch.HasScalingKeys) { if (i < nch.ScalingKeyCount) { scale = nch.ScalingKeys[i].Value; } else { scale = nch.ScalingKeys.Last().Value; } } yield return(new Frame() { pos = pos, rot = rot, scal = scale }); } yield break; }
public Assimp.Vector3D GetAssimpPoint() { Matrix4x4 pos = converter.Matrix3DToAssimpMatrix4x4(Matrix[Session.CurrentSession.CurrentProject.CurrentModel3D.Animation.Tick]); Assimp.Vector3D translation = new Assimp.Vector3D(); Assimp.Quaternion rot = new Assimp.Quaternion(); // Get the Absolute positions pos.DecomposeNoScaling(out rot, out translation); // TODO : Get back to relative position return translation / delta[Session.CurrentSession.CurrentProject.CurrentModel3D.Animation.Tick]; }
/// <summary> /// Build a transformation matrix from rotation, scaling and translation components. /// The transformation order is scaling, rotation, translation (left to right). /// </summary> /// <param name="presentRotation"></param> /// <param name="presentScaling"></param> /// <param name="presentPosition"></param> /// <param name="outMatrix"></param> private static void BuildTransform(ref Quaternion presentRotation, ref Vector3D presentScaling, ref Vector3D presentPosition, out Matrix outMatrix) { // build a transformation matrix from it var mat = new Matrix4x4(presentRotation.GetMatrix()); mat.A1 *= presentScaling.X; mat.B1 *= presentScaling.X; mat.C1 *= presentScaling.X; mat.A2 *= presentScaling.Y; mat.B2 *= presentScaling.Y; mat.C2 *= presentScaling.Y; mat.A3 *= presentScaling.Z; mat.B3 *= presentScaling.Z; mat.C3 *= presentScaling.Z; mat.A4 = presentPosition.X; mat.B4 = presentPosition.Y; mat.C4 = presentPosition.Z; outMatrix = AssimpConv.ConvertTransform(mat); }
public static Vector3 ToEulerAngles(Assimp.Quaternion q) { float PI = (float)Math.PI; // Store the Euler angles in radians Vector3 pitchYawRoll = new Vector3(); double sqw = q.W * q.W; double sqx = q.X * q.X; double sqy = q.Y * q.Y; double sqz = q.Z * q.Z; // If quaternion is normalised the unit is one, otherwise it is the correction factor double unit = sqx + sqy + sqz + sqw; double test = q.X * q.Y + q.Z * q.W; if (test > 0.499f * unit) { // Singularity at north pole pitchYawRoll.Y = 2f * (float)Math.Atan2(q.X, q.W); // Yaw pitchYawRoll.X = PI * 0.5f; // Pitch pitchYawRoll.Z = 0f; // Roll return(pitchYawRoll); } else if (test < -0.499f * unit) { // Singularity at south pole pitchYawRoll.Y = -2f * (float)Math.Atan2(q.X, q.W); // Yaw pitchYawRoll.X = -PI * 0.5f; // Pitch pitchYawRoll.Z = 0f; // Roll return(pitchYawRoll); } pitchYawRoll.Y = (float)Math.Atan2(2 * q.Y * q.W - 2 * q.X * q.Z, sqx - sqy - sqz + sqw); // Yaw pitchYawRoll.X = (float)Math.Asin(2 * test / unit); // Pitch pitchYawRoll.Z = (float)Math.Atan2(2 * q.X * q.W - 2 * q.Y * q.Z, -sqx + sqy - sqz + sqw); // Roll return(pitchYawRoll); }
public static Quaternion ToXna(Assimp.Quaternion quaternion) { return(new Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W)); }
private void UpdateUi(Matrix4x4 mat, bool diffAgainstBaseMatrix) { // use assimp math data structures because they have Decompose() // the decomposition algorithm is not very sophisticated - it basically extracts translation // and row scaling factors and then converts the rest to a quaternion. // question: what if the matrix is non-invertible? the algorithm then yields // at least one scaling factor as zero, further results are undefined. We // therefore catch this case by checking the determinant and inform the user // that the results may be wrong. checkBoxNonStandard.Checked = Math.Abs(mat.Determinant()) < 1e-5; Vector3D scale; Quaternion rot; Vector3D trans; mat.Decompose(out scale, out rot, out trans); // translation textBoxTransX.Text = trans.X.ToString(Format); textBoxTransY.Text = trans.Y.ToString(Format); textBoxTransZ.Text = trans.Z.ToString(Format); // scaling - simpler view mode for uniform scalings var isUniform = Math.Abs(scale.X - scale.Y) < 1e-5 && Math.Abs(scale.X - scale.Z) < 1e-5; textBoxScaleX.Text = scale.X.ToString(Format); textBoxScaleY.Text = scale.Y.ToString(Format); textBoxScaleZ.Text = scale.Z.ToString(Format); textBoxScaleY.Visible = !isUniform; textBoxScaleZ.Visible = !isUniform; labelScalingX.Visible = !isUniform; labelScalingY.Visible = !isUniform; labelScalingZ.Visible = !isUniform; if (diffAgainstBaseMatrix) { const double epsilon = 1e-5f; if (Math.Abs(scale.X-_scale.X) > epsilon) { labelScalingX.ForeColor = ColorIsAnimated; textBoxScaleX.ForeColor = ColorIsAnimated; } if (Math.Abs(scale.Y - _scale.Y) > epsilon) { labelScalingY.ForeColor = ColorIsAnimated; textBoxScaleY.ForeColor = ColorIsAnimated; } if (Math.Abs(scale.Z - _scale.Z) > epsilon) { labelScalingZ.ForeColor = ColorIsAnimated; textBoxScaleZ.ForeColor = ColorIsAnimated; } if (Math.Abs(trans.X - _trans.X) > epsilon) { labelTranslationX.ForeColor = ColorIsAnimated; textBoxTransX.ForeColor = ColorIsAnimated; } if (Math.Abs(trans.Y - _trans.Y) > epsilon) { labelTranslationY.ForeColor = ColorIsAnimated; textBoxTransY.ForeColor = ColorIsAnimated; } if (Math.Abs(trans.Z - _trans.Z) > epsilon) { labelTranslationZ.ForeColor = ColorIsAnimated; textBoxTransZ.ForeColor = ColorIsAnimated; } } else { labelScalingX.ForeColor = ColorNotAnimated; textBoxScaleX.ForeColor = ColorNotAnimated; labelScalingY.ForeColor = ColorNotAnimated; textBoxScaleY.ForeColor = ColorNotAnimated; labelScalingZ.ForeColor = ColorNotAnimated; textBoxScaleZ.ForeColor = ColorNotAnimated; labelTranslationX.ForeColor = ColorNotAnimated; textBoxTransX.ForeColor = ColorNotAnimated; labelTranslationY.ForeColor = ColorNotAnimated; textBoxTransY.ForeColor = ColorNotAnimated; labelTranslationZ.ForeColor = ColorNotAnimated; textBoxTransZ.ForeColor = ColorNotAnimated; _scale = scale; _trans = trans; _rot = rot; } // rotation - more complicated because the display mode can be changed _rotCurrent = rot; SetRotation(diffAgainstBaseMatrix); }
public void Evaluate(float dt, Dictionary<string, Bone> bones) { dt *= TicksPerSecond; var time = 0.0f; if (Duration > 0.0f) { time = dt % Duration; } for (int i = 0; i < Channels.Count; i++) { var channel = Channels[i]; if (!bones.ContainsKey(channel.Name)) { Console.WriteLine("Did not find the bone node " + channel.Name); continue; } // interpolate position keyframes var pPosition = new Vector3D(); if (channel.PositionKeys.Count > 0) { var frame = (time >= LastTime) ? LastPositions[i].Item1 : 0; while (frame < channel.PositionKeys.Count - 1) { if (time < channel.PositionKeys[frame + 1].Time) { break; } frame++; } if (frame >= channel.PositionKeys.Count) { frame = 0; } var nextFrame = (frame + 1) % channel.PositionKeys.Count; var key = channel.PositionKeys[frame]; var nextKey = channel.PositionKeys[nextFrame]; var diffTime = nextKey.Time - key.Time; if (diffTime < 0.0) { diffTime += Duration; } if (diffTime > 0.0) { var factor = (float)((time - key.Time) / diffTime); pPosition = key.Value + (nextKey.Value - key.Value) * factor; } else { pPosition = key.Value; } LastPositions[i].Item1 = frame; } // interpolate rotation keyframes var pRot = new Assimp.Quaternion(1, 0, 0, 0); if (channel.RotationKeys.Count > 0) { var frame = (time >= LastTime) ? LastPositions[i].Item2 : 0; while (frame < channel.RotationKeys.Count - 1) { if (time < channel.RotationKeys[frame + 1].Time) { break; } frame++; } if (frame >= channel.RotationKeys.Count) { frame = 0; } var nextFrame = (frame + 1) % channel.RotationKeys.Count; var key = channel.RotationKeys[frame]; var nextKey = channel.RotationKeys[nextFrame]; key.Value.Normalize(); nextKey.Value.Normalize(); var diffTime = nextKey.Time - key.Time; if (diffTime < 0.0) { diffTime += Duration; } if (diffTime > 0) { var factor = (float)((time - key.Time) / diffTime); pRot = Assimp.Quaternion.Slerp(key.Value, nextKey.Value, factor); } else { pRot = key.Value; } LastPositions[i].Item1= frame; } // interpolate scale keyframes var pscale = new Vector3D(1); if (channel.ScalingKeys.Count > 0) { var frame = (time >= LastTime) ? LastPositions[i].Item3 : 0; while (frame < channel.ScalingKeys.Count - 1) { if (time < channel.ScalingKeys[frame + 1].Time) { break; } frame++; } if (frame >= channel.ScalingKeys.Count) { frame = 0; } LastPositions[i].Item3 = frame; } // create the combined transformation matrix var mat = new Matrix4x4(pRot.GetMatrix()); mat.A1 *= pscale.X; mat.B1 *= pscale.X; mat.C1 *= pscale.X; mat.A2 *= pscale.Y; mat.B2 *= pscale.Y; mat.C2 *= pscale.Y; mat.A3 *= pscale.Z; mat.B3 *= pscale.Z; mat.C3 *= pscale.Z; mat.A4 = pPosition.X; mat.B4 = pPosition.Y; mat.C4 = pPosition.Z; // transpose to get DirectX style matrix mat.Transpose(); bones[channel.Name].LocalTransform = mat.ToMatrix(); } LastTime = time; }
private static Quaternion ConvertQuaternion(Assimp.Quaternion value) { // Assimp quaternions are stored in wxyz order return(new Quaternion(value.X, value.Y, value.Z, value.W)); }
private void UpdateUi(Matrix4x4 mat, bool diffAgainstBaseMatrix) { // use assimp math data structures because they have Decompose() // the decomposition algorithm is not very sophisticated - it basically extracts translation // and row scaling factors and then converts the rest to a quaternion. // question: what if the matrix is non-invertible? the algorithm then yields // at least one scaling factor as zero, further results are undefined. We // therefore catch this case by checking the determinant and inform the user // that the results may be wrong. checkBoxNonStandard.Checked = Math.Abs(mat.Determinant()) < 1e-5; Vector3D scale; Quaternion rot; Vector3D trans; mat.Decompose(out scale, out rot, out trans); // translation textBoxTransX.Text = trans.X.ToString(Format); textBoxTransY.Text = trans.Y.ToString(Format); textBoxTransZ.Text = trans.Z.ToString(Format); // scaling - simpler view mode for uniform scalings var isUniform = Math.Abs(scale.X - scale.Y) < 1e-5 && Math.Abs(scale.X - scale.Z) < 1e-5; textBoxScaleX.Text = scale.X.ToString(Format); textBoxScaleY.Text = scale.Y.ToString(Format); textBoxScaleZ.Text = scale.Z.ToString(Format); textBoxScaleY.Visible = !isUniform; textBoxScaleZ.Visible = !isUniform; labelScalingX.Visible = !isUniform; labelScalingY.Visible = !isUniform; labelScalingZ.Visible = !isUniform; if (diffAgainstBaseMatrix) { const double epsilon = 1e-5f; if (Math.Abs(scale.X - _scale.X) > epsilon) { labelScalingX.ForeColor = ColorIsAnimated; textBoxScaleX.ForeColor = ColorIsAnimated; } if (Math.Abs(scale.Y - _scale.Y) > epsilon) { labelScalingY.ForeColor = ColorIsAnimated; textBoxScaleY.ForeColor = ColorIsAnimated; } if (Math.Abs(scale.Z - _scale.Z) > epsilon) { labelScalingZ.ForeColor = ColorIsAnimated; textBoxScaleZ.ForeColor = ColorIsAnimated; } if (Math.Abs(trans.X - _trans.X) > epsilon) { labelTranslationX.ForeColor = ColorIsAnimated; textBoxTransX.ForeColor = ColorIsAnimated; } if (Math.Abs(trans.Y - _trans.Y) > epsilon) { labelTranslationY.ForeColor = ColorIsAnimated; textBoxTransY.ForeColor = ColorIsAnimated; } if (Math.Abs(trans.Z - _trans.Z) > epsilon) { labelTranslationZ.ForeColor = ColorIsAnimated; textBoxTransZ.ForeColor = ColorIsAnimated; } } else { labelScalingX.ForeColor = ColorNotAnimated; textBoxScaleX.ForeColor = ColorNotAnimated; labelScalingY.ForeColor = ColorNotAnimated; textBoxScaleY.ForeColor = ColorNotAnimated; labelScalingZ.ForeColor = ColorNotAnimated; textBoxScaleZ.ForeColor = ColorNotAnimated; labelTranslationX.ForeColor = ColorNotAnimated; textBoxTransX.ForeColor = ColorNotAnimated; labelTranslationY.ForeColor = ColorNotAnimated; textBoxTransY.ForeColor = ColorNotAnimated; labelTranslationZ.ForeColor = ColorNotAnimated; textBoxTransZ.ForeColor = ColorNotAnimated; _scale = scale; _trans = trans; _rot = rot; } // rotation - more complicated because the display mode can be changed _rotCurrent = rot; SetRotation(diffAgainstBaseMatrix); }
private static void AddRotationAtKeyframe(List <QuaternionKey> Keys, int keyframe, Assimp.Quaternion value, double framerate = 30.0) { double frametick = 1.0 / framerate; double keyframeTime = frametick * keyframe; Keys.Add(new QuaternionKey(keyframeTime, value)); }
/// <summary> /// Build a transformation matrix from rotation, scaling and translation components. /// The transformation order is scaling, rotation, translation (left to right). /// </summary> /// <param name="presentRotation"></param> /// <param name="presentScaling"></param> /// <param name="presentPosition"></param> /// <param name="outMatrix"></param> private static void BuildTransform(ref Quaternion presentRotation, ref Vector3D presentScaling, ref Vector3D presentPosition, out Matrix4 outMatrix) { // build a transformation matrix from it var mat = new Matrix4x4(presentRotation.GetMatrix()); mat.A1 *= presentScaling.X; mat.B1 *= presentScaling.X; mat.C1 *= presentScaling.X; mat.A2 *= presentScaling.Y; mat.B2 *= presentScaling.Y; mat.C2 *= presentScaling.Y; mat.A3 *= presentScaling.Z; mat.B3 *= presentScaling.Z; mat.C3 *= presentScaling.Z; mat.A4 = presentPosition.X; mat.B4 = presentPosition.Y; mat.C4 = presentPosition.Z; outMatrix = AssimpToOpenTk.FromMatrix(ref mat); }
/// <summary> /// Evaluate animation channels at a given time /// </summary> /// <param name="pTime">Time, in seconds. If the time exceeds the animation's /// duration value, it will be looped.</param> /// <param name="isInEndPosition">A problem with automatic looping (and the /// way how assimp handles animation duration) is that evaluating the /// animation at a time that is exactly the animation duration might wrap /// over to the first key frame (i.e. due to numerical inaccuracies). Setting /// this parameter to true causes the pTime value to be ignored and the /// last set of key frames to be taken.</param> public void Evaluate(double pTime, bool isInEndPosition) { // extract ticks per second. Assume default value if not given // every following time calculation happens in ticks pTime *= _ticksPerSecond; // map into anim's duration double time = 0.0f; if (_animation.DurationInTicks > 0.0) { time = pTime % _animation.DurationInTicks; } // calculate the transformations for each animation channel for (int a = 0; a < _animation.NodeAnimationChannelCount; a++) { var channel = _animation.NodeAnimationChannels[a]; var presentPosition = new Vector3D(0, 0, 0); var presentRotation = new Quaternion(1, 0, 0, 0); var presentScaling = new Vector3D(1, 1, 1); if (isInEndPosition) { if (channel.PositionKeyCount > 0) { presentPosition = channel.PositionKeys.Last().Value; _lastPositions[a].Item1 = channel.PositionKeyCount - 1; } if (channel.RotationKeyCount > 0) { presentRotation = channel.RotationKeys.Last().Value; _lastPositions[a].Item2 = channel.RotationKeyCount - 1; } if (channel.ScalingKeyCount > 0) { presentScaling = channel.ScalingKeys.Last().Value; _lastPositions[a].Item3 = channel.ScalingKeyCount - 1; } BuildTransform(ref presentRotation, ref presentScaling, ref presentPosition, out _currentTransforms[a]); continue; } // ******** Position ***** if (channel.PositionKeyCount > 0) { // Look for present frame number. Search from last position if time is after the last time, else from beginning // Should be much quicker than always looking from start for the average use case. var frame = (time >= _lastTime) ? _lastPositions[a].Item1 : 0; while (frame < channel.PositionKeyCount - 1) { if (time < channel.PositionKeys[frame + 1].Time) { break; } frame++; } // interpolate between this frame's value and next frame's value var nextFrame = (frame + 1) % channel.PositionKeyCount; var key = channel.PositionKeys[frame]; var nextKey = channel.PositionKeys[nextFrame]; var diffTime = nextKey.Time - key.Time; if (diffTime < 0.0) { diffTime += _animation.DurationInTicks; } if (diffTime > 0) { var factor = (float)((time - key.Time) / diffTime); presentPosition = key.Value + (nextKey.Value - key.Value) * factor; } else { presentPosition = key.Value; } _lastPositions[a].Item1 = frame; } // ******** Rotation ********* if (channel.RotationKeyCount > 0) { var frame = (time >= _lastTime) ? _lastPositions[a].Item2 : 0; while (frame < channel.RotationKeyCount - 1) { if (time < channel.RotationKeys[frame + 1].Time) { break; } frame++; } // interpolate between this frame's value and next frame's value var nextFrame = (frame + 1) % channel.RotationKeyCount; var key = channel.RotationKeys[frame]; var nextKey = channel.RotationKeys[nextFrame]; double diffTime = nextKey.Time - key.Time; if (diffTime < 0.0) { diffTime += _animation.DurationInTicks; } if (diffTime > 0) { var factor = (float)((time - key.Time) / diffTime); presentRotation = Quaternion.Slerp(key.Value, nextKey.Value, factor); } else { presentRotation = key.Value; } _lastPositions[a].Item2 = frame; } // ******** Scaling ********** if (channel.ScalingKeyCount > 0) { var frame = (time >= _lastTime) ? _lastPositions[a].Item3 : 0; while (frame < channel.ScalingKeyCount - 1) { if (time < channel.ScalingKeys[frame + 1].Time) { break; } frame++; } // TODO: (thom) interpolation maybe? This time maybe even logarithmic, not linear presentScaling = channel.ScalingKeys[frame].Value; _lastPositions[a].Item3 = frame; } BuildTransform(ref presentRotation, ref presentScaling, ref presentPosition, out _currentTransforms[a]); } _lastTime = time; }
public static GameObject Load(string meshPath, float scaleX = 1, float scaleY = 1, float scaleZ = 1) { if (!File.Exists(meshPath)) { return(null); } AssimpContext importer = new AssimpContext(); Scene scene = importer.ImportFile(meshPath); if (scene == null) { return(null); } string parentDir = Directory.GetParent(meshPath).FullName; // Materials List <UnityEngine.Material> uMaterials = new List <Material>(); if (scene.HasMaterials) { foreach (var m in scene.Materials) { UnityEngine.Material uMaterial = new UnityEngine.Material(Shader.Find("Standard")); // Albedo if (m.HasColorDiffuse) { Color color = new Color( m.ColorDiffuse.R, m.ColorDiffuse.G, m.ColorDiffuse.B, m.ColorDiffuse.A ); uMaterial.color = color; } // Emission if (m.HasColorEmissive) { Color color = new Color( m.ColorEmissive.R, m.ColorEmissive.G, m.ColorEmissive.B, m.ColorEmissive.A ); uMaterial.SetColor("_EmissionColor", color); uMaterial.EnableKeyword("_EMISSION"); } // Reflectivity if (m.HasReflectivity) { uMaterial.SetFloat("_Glossiness", m.Reflectivity); } // Texture if (false && m.HasTextureDiffuse) { Texture2D uTexture = new Texture2D(2, 2); string texturePath = Path.Combine(parentDir, m.TextureDiffuse.FilePath); byte[] byteArray = File.ReadAllBytes(texturePath); bool isLoaded = uTexture.LoadImage(byteArray); if (!isLoaded) { throw new Exception("Cannot find texture file: " + texturePath); } uMaterial.SetTexture("_MainTex", uTexture); } uMaterials.Add(uMaterial); } } // Mesh List <MeshMaterialBinding> uMeshAndMats = new List <MeshMaterialBinding>(); if (scene.HasMeshes) { foreach (var m in scene.Meshes) { List <Vector3> uVertices = new List <Vector3>(); List <Vector3> uNormals = new List <Vector3>(); List <Vector2> uUv = new List <Vector2>(); List <int> uIndices = new List <int>(); // Vertices if (m.HasVertices) { foreach (var v in m.Vertices) { uVertices.Add(new Vector3(-v.X, v.Y, v.Z)); } } // Normals if (m.HasNormals) { foreach (var n in m.Normals) { uNormals.Add(new Vector3(-n.X, n.Y, n.Z)); } } // Triangles if (m.HasFaces) { foreach (var f in m.Faces) { // Ignore degenerate faces if (f.IndexCount == 1 || f.IndexCount == 2) { continue; } for (int i = 0; i < (f.IndexCount - 2); i++) { uIndices.Add(f.Indices[i + 2]); uIndices.Add(f.Indices[i + 1]); uIndices.Add(f.Indices[0]); } } } // Uv (texture coordinate) if (m.HasTextureCoords(0)) { foreach (var uv in m.TextureCoordinateChannels[0]) { uUv.Add(new Vector2(uv.X, uv.Y)); } } UnityEngine.Mesh uMesh = new UnityEngine.Mesh(); uMesh.vertices = uVertices.ToArray(); uMesh.normals = uNormals.ToArray(); uMesh.triangles = uIndices.ToArray(); uMesh.uv = uUv.ToArray(); uMeshAndMats.Add(new MeshMaterialBinding(m.Name, uMesh, uMaterials[m.MaterialIndex])); } } // Create GameObjects from nodes GameObject NodeToGameObject(Node node) { GameObject uOb = new GameObject(node.Name); // Set Mesh if (node.HasMeshes) { foreach (var mIdx in node.MeshIndices) { var uMeshAndMat = uMeshAndMats[mIdx]; GameObject uSubOb = new GameObject(uMeshAndMat.MeshName); uSubOb.AddComponent <MeshFilter>(); uSubOb.AddComponent <MeshRenderer>(); uSubOb.AddComponent <MeshCollider>(); uSubOb.GetComponent <MeshFilter>().mesh = uMeshAndMat.Mesh; uSubOb.GetComponent <MeshRenderer>().material = uMeshAndMat.Material; uSubOb.transform.SetParent(uOb.transform, true); uSubOb.transform.localScale = new Vector3(scaleX, scaleY, scaleZ); } } // Transform // Decompose Assimp transform into scale, rot and translaction Assimp.Vector3D aScale = new Assimp.Vector3D(); Assimp.Quaternion aQuat = new Assimp.Quaternion(); Assimp.Vector3D aTranslation = new Assimp.Vector3D(); node.Transform.Decompose(out aScale, out aQuat, out aTranslation); // Convert Assimp transfrom into Unity transform and set transformation of game object UnityEngine.Quaternion uQuat = new UnityEngine.Quaternion(aQuat.X, aQuat.Y, aQuat.Z, aQuat.W); var euler = uQuat.eulerAngles; uOb.transform.localScale = new UnityEngine.Vector3(aScale.X, aScale.Y, aScale.Z); uOb.transform.localPosition = new UnityEngine.Vector3(aTranslation.X, aTranslation.Y, aTranslation.Z); uOb.transform.localRotation = UnityEngine.Quaternion.Euler(euler.x, -euler.y, euler.z); if (node.HasChildren) { foreach (var cn in node.Children) { var uObChild = NodeToGameObject(cn); uObChild.transform.SetParent(uOb.transform, false); } } return(uOb); } return(NodeToGameObject(scene.RootNode));; }
static void recurseNode(Assimp.Scene scn, Node node, StringBuilder scenesb, Matrix4x4 matrix) { Console.WriteLine("Scanning node " + node.Name); foreach (var mindex in node.MeshIndices) { var m = scn.Meshes[mindex]; string name = usednames.Contains(m.Name) ? (m.Name + (unnamed++).ToString()) : m.Name; var sb = new StringBuilder(); if (!File.Exists(outfile + "/" + name + ".mesh3d")) { var vertexinfos = new List <VertexInfo>(); var indices = m.GetIndices(); for (int i = 0; i < indices.Length; i++) { int f = indices[i]; var vp = m.Vertices[f]; var vn = m.Normals[f]; var vt = (m.TextureCoordinateChannels.Length == 0 || m.TextureCoordinateChannels[0].Count <= f) ? new Assimp.Vector3D(0) : m.TextureCoordinateChannels[0][f]; var vi = new VertexInfo() { Position = new Vector3(vp.X, vp.Y, vp.Z), Normal = new Vector3(vn.X, vn.Y, vn.Z), UV = new Vector2(vt.X, vt.Y) }; vertexinfos.Add(vi); } if (doublefaced) { for (int i = indices.Length - 1; i >= 0; i--) { int f = indices[i]; var vp = m.Vertices[f]; var vn = m.Normals[f]; var vt = (m.TextureCoordinateChannels.Length == 0 || m.TextureCoordinateChannels[0].Count <= f) ? new Assimp.Vector3D(0) : m.TextureCoordinateChannels[0][f]; var vi = new VertexInfo() { Position = new Vector3(vp.X, vp.Y, vp.Z), Normal = new Vector3(vn.X, vn.Y, vn.Z), UV = new Vector2(vt.X, vt.Y) }; vertexinfos.Add(vi); } } var element = new Object3dManager(vertexinfos); Console.WriteLine("Saving " + outfile + "/" + name + ".raw"); element.SaveRawWithTangents(outfile + "/" + name + ".raw"); string matname = matdict[m.MaterialIndex]; scenesb.AppendLine("mesh3d " + outfile + "/" + name + ".mesh3d"); sb.AppendLine("lodlevel"); sb.AppendLine("start 0.0"); sb.AppendLine("end 99999.0"); sb.AppendLine("info3d " + outfile + "/" + name + ".raw"); sb.AppendLine("material " + matname); sb.AppendLine(); } sb.AppendLine("instance"); Assimp.Vector3D pvec, pscl; Assimp.Quaternion pquat; var a = new Assimp.Quaternion(new Vector3D(1, 0, 0), MathHelper.DegreesToRadians(-90)).GetMatrix(); var a2 = Matrix4x4.FromScaling(new Vector3D(0.01f)); (matrix * node.Transform * new Assimp.Matrix4x4(a) * a2).Decompose(out pscl, out pquat, out pvec); var q1 = new OpenTK.Quaternion(pquat.X, pquat.Y, pquat.Z, pquat.W).Inverted(); var m1 = Matrix4.CreateFromQuaternion(q1); m1[2, 0] = -m1[2, 0]; m1[2, 1] = -m1[2, 1]; m1[0, 2] = -m1[0, 2]; m1[1, 2] = -m1[1, 2]; var q2 = m1.ExtractRotation(true); sb.AppendLine(string.Format("translate {0} {1} {2}", ftos(pvec.X), ftos(pvec.Y), ftos(pvec.Z))); sb.AppendLine(string.Format("rotate {0} {1} {2} {3}", ftos(q1.X), ftos(q1.Y), ftos(q1.Z), ftos(q1.W))); sb.AppendLine(string.Format("scale {0} {1} {2}", ftos(pscl.X), ftos(pscl.Y), ftos(pscl.Z))); if (!File.Exists(outfile + "/" + name + ".mesh3d")) { Console.WriteLine("Saving " + outfile + "/" + name + ".mesh3d"); File.WriteAllText(outfile + "/" + name + ".mesh3d", sb.ToString()); } else { Console.WriteLine("Extending " + outfile + "/" + name + ".mesh3d"); File.AppendAllText(outfile + "/" + name + ".mesh3d", sb.ToString()); } } foreach (var c in node.Children) { if (c != node) { recurseNode(scn, c, scenesb, matrix * node.Transform); } } }
private static SharpDX.Mathematics.Quaternion ConvertQuaternion(Assimp.Quaternion value) { // Assimp quaternions are stored in wxyz order return(new SharpDX.Mathematics.Quaternion(value.X, value.Y, value.Z, value.W)); }
public Assimp.Quaternion GetAssimpRotation() { Matrix4x4 pos = converter.Matrix3DToAssimpMatrix4x4(Matrix[Session.CurrentSession.CurrentProject.CurrentModel3D.Animation.Tick]); Assimp.Vector3D posTranslation = new Assimp.Vector3D(); Assimp.Quaternion posRot = new Assimp.Quaternion(); pos.DecomposeNoScaling(out posRot, out posTranslation); return posRot; }
// quat4 -> (roll, pitch, yaw) private static void QuatToEulerXyz(ref Quaternion q1, out Vector3 outVector) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ double sqw = q1.W*q1.W; double sqx = q1.X*q1.X; double sqy = q1.Y*q1.Y; double sqz = q1.Z*q1.Z; double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor double test = q1.X*q1.Y + q1.Z*q1.W; if (test > 0.499*unit) { // singularity at north pole outVector.Z = (float)(2 * Math.Atan2(q1.X, q1.W)); outVector.Y = (float)(Math.PI / 2); outVector.X = 0; return; } if (test < -0.499*unit) { // singularity at south pole outVector.Z = (float)(-2 * Math.Atan2(q1.X, q1.W)); outVector.Y = (float)(-Math.PI / 2); outVector.X = 0; return; } outVector.Z = (float)Math.Atan2(2 * q1.Y * q1.W - 2 * q1.X * q1.Z, sqx - sqy - sqz + sqw); outVector.Y = (float)Math.Asin(2 * test / unit); outVector.X = (float)Math.Atan2(2 * q1.X * q1.W - 2 * q1.Y * q1.Z, -sqx + sqy - sqz + sqw); }
public static System.Numerics.Quaternion ToNumerics(this Quaternion value) { return(new System.Numerics.Quaternion(value.X, value.Y, value.Z, value.W)); }
public static Quaternion ToQuaternion(Assimp.Quaternion q) { return(new Quaternion(q.X, q.Y, q.Z, q.W)); }
public static System.Numerics.Quaternion ToSystemQuaternion(this Assimp.Quaternion quat) { return(new System.Numerics.Quaternion(quat.X, quat.Y, quat.Z, quat.W)); }