// // ArraySegment<byte> を新規に確保して置き換える // public void Append(BufferAccessor a, int offset = -1) { if (AccessorType != a.AccessorType) { System.Console.WriteLine(AccessorType.ToString() + "!=" + a.AccessorType.ToString()); throw new Exception("different AccessorType"); } // UNSIGNED_SHORT <-> UNSIGNED_INT の変換を許容して処理を続行 // 統合メッシュのprimitiveのIndexBufferが65,535(ushort.MaxValue)を超える場合や、変換前にindexBuffer.ComponetTypeがushortとuint混在する場合など if (ComponentType != a.ComponentType) { switch (a.ComponentType) { //ushort to uint case AccessorValueType.UNSIGNED_SHORT: { var src = SpanLike.Wrap <UInt16>(a.Bytes).Slice(0, a.Count); var bytes = new byte[src.Length * 4]; var dst = SpanLike.Wrap <UInt32>(new ArraySegment <byte>(bytes)); for (int i = 0; i < src.Length; ++i) { dst[i] = (uint)src[i]; } var accessor = new BufferAccessor(new ArraySegment <byte>(bytes), AccessorValueType.UNSIGNED_INT, AccessorVectorType.SCALAR, a.Count); a = accessor; break; } //uint to ushort (おそらく通ることはない) case AccessorValueType.UNSIGNED_INT: { var src = SpanLike.Wrap <UInt32>(a.Bytes).Slice(0, a.Count); var bytes = new byte[src.Length * 2]; var dst = SpanLike.Wrap <UInt16>(new ArraySegment <byte>(bytes)); for (int i = 0; i < src.Length; ++i) { dst[i] = (ushort)src[i]; } var accessor = new BufferAccessor(new ArraySegment <byte>(bytes), ComponentType, AccessorVectorType.SCALAR, a.Count); a = accessor; break; } default: throw new Exception("Cannot Convert ComponentType"); } } // 連結した新しいバッファを確保 var oldLength = Bytes.Count; ToByteLength(oldLength + a.Bytes.Count); // 後ろにコピー Buffer.BlockCopy(a.Bytes.Array, a.Bytes.Offset, Bytes.Array, Bytes.Offset + oldLength, a.Bytes.Count); Count += a.Count; if (offset > 0) { // 後半にoffsetを足す switch (ComponentType) { case AccessorValueType.UNSIGNED_SHORT: { var span = SpanLike.Wrap <UInt16>(Bytes.Slice(oldLength)); var ushortOffset = (ushort)offset; for (int i = 0; i < span.Length; ++i) { span[i] += ushortOffset; } } break; case AccessorValueType.UNSIGNED_INT: { var span = SpanLike.Wrap <UInt32>(Bytes.Slice(oldLength)); var uintOffset = (uint)offset; for (int i = 0; i < span.Length; ++i) { span[i] += uintOffset; } } break; default: throw new NotImplementedException(); } } }
public void SkipFrame(int skipFrames) { In = In.Skip(skipFrames); Out = Out.Skip(skipFrames); }
public static void Add <T>(this VertexBuffer v, string key, T[] list) where T : struct { v.Add(key, BufferAccessor.Create(list)); }
// Meshを連結する。SingleMesh で使う public static void Append(this Mesh mesh, VertexBuffer vertices, BufferAccessor indices, List <Submesh> submeshes, List <MorphTarget> targets, int[] jointIndexMap, int rootIndex = -1, Matrix4x4 matrix = default(Matrix4x4)) { var lastCount = mesh.VertexBuffer != null ? mesh.VertexBuffer.Count : 0; // index buffer if (mesh.IndexBuffer == null) { var accessor = new BufferAccessor(new ArraySegment <byte>(new byte[0]), AccessorValueType.UNSIGNED_INT, indices.AccessorType, 0); mesh.IndexBuffer = accessor; mesh.IndexBuffer.Append(indices, 0); } else { mesh.IndexBuffer.Append(indices, lastCount); } { var submeshOffset = mesh.SubmeshTotalDrawCount; for (int i = 0; i < submeshes.Count; ++i) { var submesh = submeshes[i]; mesh.Submeshes.Add(new Submesh(submeshOffset, submesh.DrawCount, submesh.Material)); submeshOffset += submesh.DrawCount; } } // vertex buffer var vertexOffset = 0; if (mesh.VertexBuffer == null) { mesh.VertexBuffer = vertices; } else { vertexOffset = mesh.VertexBuffer.Count; mesh.VertexBuffer.Append(vertices); } if (jointIndexMap != null && mesh.VertexBuffer.Joints != null && mesh.VertexBuffer.Weights != null) { // JOINT index 参照の修正 var joints = SpanLike.Wrap <SkinJoints>(mesh.VertexBuffer.Joints.Bytes).Slice(vertexOffset); var weights = SpanLike.Wrap <Vector4>(mesh.VertexBuffer.Weights.Bytes).Slice(vertexOffset); FixSkinJoints(joints, weights, jointIndexMap); } else { var position = SpanLike.Wrap <Vector3>(mesh.VertexBuffer.Positions.Bytes).Slice(vertexOffset); var normal = SpanLike.Wrap <Vector3>(mesh.VertexBuffer.Normals.Bytes).Slice(vertexOffset); var joints = mesh.VertexBuffer.GetOrCreateJoints().Slice(vertexOffset); var weights = mesh.VertexBuffer.GetOrCreateWeights().Slice(vertexOffset); // Nodeの姿勢を反映して // JOINT と WEIGHT を追加する FixNoSkinJoints(joints, weights, rootIndex, position, normal, matrix); } // morph target foreach (var target in targets) { if (string.IsNullOrEmpty(target.Name)) { continue; } foreach (var kv in target.VertexBuffer) { if (kv.Value.Count != target.VertexBuffer.Count) { throw new Exception("different length"); } } var found = mesh.MorphTargets.FirstOrDefault(x => x.Name == target.Name); if (found == null) { // targetの前に0を足す found = new MorphTarget(target.Name); found.VertexBuffer = target.VertexBuffer.CloneWithOffset(lastCount); mesh.MorphTargets.Add(found); foreach (var kv in found.VertexBuffer) { if (kv.Value.Count != mesh.VertexBuffer.Count) { throw new Exception(); } } } else { found.VertexBuffer.Resize(lastCount); // foundの後ろにtargetを足す found.VertexBuffer.Append(target.VertexBuffer); foreach (var kv in found.VertexBuffer) { if (kv.Value.Count != mesh.VertexBuffer.Count) { throw new Exception(); } } } } }
/// <summary> /// モーションの基本姿勢を basePose ベースに再計算する /// /// basePose は Humanoid.CopyNodes が必用 ! /// </summary> public Animation RebaseAnimation(Humanoid basePose) { var map = NodeMap.ToDictionary(kv => kv.Key, kv => new List <Quaternion>()); var hipsPositions = new List <Vector3>(); foreach (var(seconds, keyframes) in KeyFramesGroupBySeconds()) { // モーション適用 SetTime(seconds); Root.CalcWorldMatrix(); foreach (var keyframe in keyframes) { if (!keyframe.Node.HumanoidBone.HasValue || keyframe.Node.HumanoidBone.Value == HumanoidBones.unknown) { continue; } // ローカル回転を算出する var t = basePose[keyframe.Node].Rotation; var w = keyframe.Node.Rotation; var w_from_t = w * Quaternion.Inverse(t); // parent var key = keyframe.Node.HumanoidBone.Value; var curve = map[keyframe.Node]; if (key != HumanoidBones.hips) { if (basePose[key].Parent == null) { throw new Exception(); } var parent_t = basePose[key].Parent.Rotation; var parent_w = keyframe.Node.Parent.Rotation; var parent_w_from_t = parent_w * Quaternion.Inverse(parent_t); var r = Quaternion.Inverse(parent_w_from_t) * w_from_t; curve.Add(r); } else { // hips curve.Add(w_from_t); hipsPositions.Add(keyframe.Node.Translation); } } } var dst = new Animation(Name + ".tpose"); foreach (var kv in map) { if (!kv.Value.Any()) { continue; } var bone = kv.Key.HumanoidBone.Value; var inCurve = NodeMap[kv.Key].Curves[AnimationPathType.Rotation].In; if (inCurve.Count != kv.Value.Count) { throw new Exception(); } var nodeAnimation = new NodeAnimation(); nodeAnimation.Curves.Add(AnimationPathType.Rotation, new CurveSampler { In = inCurve, Out = BufferAccessor.Create(kv.Value.ToArray()), }); if (bone == HumanoidBones.hips) { nodeAnimation.Curves.Add(AnimationPathType.Translation, new CurveSampler { In = inCurve, Out = BufferAccessor.Create(hipsPositions.ToArray()), }); } dst.AddCurve(kv.Key, nodeAnimation); } return(dst); }
static Animation LoadAnimation(string name, Bvh.Bvh bvh, Model model, float scalingFactor) { var animation = new Animation(name); Dictionary <string, BvhNodeCurves> pathMap = new Dictionary <string, BvhNodeCurves>(); for (int i = 0; i < bvh.Channels.Length; ++i) { var channel = bvh.Channels[i]; if (!bvh.TryGetPathWithPropertyFromChannel(channel, out Bvh.Bvh.PathWithProperty prop)) { throw new Exception(); } if (!pathMap.TryGetValue(prop.Path, out BvhNodeCurves curves)) { curves = new BvhNodeCurves(); pathMap.Add(prop.Path, curves); } curves.Set(prop.Property, channel); } // setup time var timeBytes = new byte[Marshal.SizeOf(typeof(float)) * bvh.FrameCount]; var timeSpan = SpanLike.Wrap <Single>(new ArraySegment <byte>(timeBytes)); var now = 0.0; for (int i = 0; i < timeSpan.Length; ++i, now += bvh.FrameTime.TotalSeconds) { timeSpan[i] = (float)now; } var times = new BufferAccessor(new ArraySegment <byte>(timeBytes), AccessorValueType.FLOAT, AccessorVectorType.SCALAR, bvh.FrameCount); foreach (var(key, nodeCurve) in pathMap) { var node = Model.GetNode(model.Root, key); var bvhNode = GetNode(bvh.Root, key); var curve = new NodeAnimation(); if (nodeCurve.LocalPositionX != null) { var values = new byte[Marshal.SizeOf(typeof(Vector3)) * nodeCurve.LocalPositionX.Keys.Length]; var span = SpanLike.Wrap <Vector3>(new ArraySegment <byte>(values)); for (int i = 0; i < nodeCurve.LocalPositionX.Keys.Length; ++i) { span[i] = new Vector3 { X = nodeCurve.LocalPositionX.Keys[i] * scalingFactor, Y = nodeCurve.LocalPositionY.Keys[i] * scalingFactor, Z = nodeCurve.LocalPositionZ.Keys[i] * scalingFactor, }; } var sampler = new CurveSampler { In = times, Out = new BufferAccessor(new ArraySegment <byte>(values), AccessorValueType.FLOAT, AccessorVectorType.VEC3, span.Length) }; curve.Curves.Add(AnimationPathType.Translation, sampler); } if (nodeCurve.EulerX != null) { var values = new byte[Marshal.SizeOf(typeof(Quaternion)) * nodeCurve.EulerX.Keys.Length]; var span = SpanLike.Wrap <Quaternion>(new ArraySegment <byte>(values)); Func <Quaternion, BvhNodeCurves, int, Quaternion> getRot = (q, c, i) => q; foreach (var ch in bvhNode.Channels) { var tmp = getRot; switch (ch) { case Channel.Xrotation: getRot = (_, c, i) => { return(tmp(_, c, i) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, ToRad(c.EulerX.Keys[i]))); }; break; case Channel.Yrotation: getRot = (_, c, i) => { return(tmp(_, c, i) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, ToRad(c.EulerY.Keys[i]))); }; break; case Channel.Zrotation: getRot = (_, c, i) => { return(tmp(_, c, i) * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, ToRad(c.EulerZ.Keys[i]))); }; break; default: // throw new NotImplementedException(); break; } } for (int i = 0; i < nodeCurve.EulerX.Keys.Length; ++i) { span[i] = getRot(Quaternion.Identity, nodeCurve, i); } var sampler = new CurveSampler { In = times, Out = new BufferAccessor(new ArraySegment <byte>(values), AccessorValueType.FLOAT, AccessorVectorType.VEC4, span.Length) }; curve.Curves.Add(AnimationPathType.Rotation, sampler); } animation.AddCurve(node, curve); } return(animation); }