コード例 #1
0
ファイル: BufferAccessor.cs プロジェクト: t5ujiri/UniVRM
        //
        // 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();
                }
            }
        }
コード例 #2
0
 public void SkipFrame(int skipFrames)
 {
     In  = In.Skip(skipFrames);
     Out = Out.Skip(skipFrames);
 }
コード例 #3
0
 public static void Add <T>(this VertexBuffer v, string key, T[] list) where T : struct
 {
     v.Add(key, BufferAccessor.Create(list));
 }
コード例 #4
0
        // 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();
                        }
                    }
                }
            }
        }
コード例 #5
0
ファイル: Animation.cs プロジェクト: vrm-c/UniVRM_1_0
        /// <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);
        }
コード例 #6
0
        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);
        }