示例#1
0
文件: Skin.cs 项目: unitycoder/UniVRM
 public override string ToString()
 {
     if (InverseMatrices != null)
     {
         var sb       = new StringBuilder();
         var matrices = SpanLike.Wrap <Matrix4x4>(InverseMatrices.Bytes);
         var count    = 0;
         // var rootMatrix = Matrix4x4.Identity;
         // if (Root != null)
         // {
         //     rootMatrix = Root.InverseMatrix;
         // }
         for (int i = 0; i < matrices.Length; ++i)
         {
             var m = matrices[i] * Joints[i].Matrix;
             if (!IsIdentity(m))
             {
                 ++count;
             }
         }
         if (count > 0)
         {
             sb.Append($"{count}/{Joints.Count} is not normalized");
         }
         else
         {
             sb.Append($"{Joints.Count} joints normalized");
         }
         return(sb.ToString());
     }
     else
     {
         return($"{Joints.Count} joints without InverseMatrices");
     }
 }
示例#2
0
        // Joints用
        public UShort4[] GetAsUShort4()
        {
            if (AccessorType != AccessorVectorType.VEC4)
            {
                throw new InvalidOperationException("not vec4");
            }
            switch (ComponentType)
            {
            case AccessorValueType.UNSIGNED_SHORT:
                return(SpanLike.Wrap <UShort4>(Bytes).ToArray());

            case AccessorValueType.UNSIGNED_BYTE:
            {
                var array = new UShort4[Count];
                var span  = SpanLike.Wrap <Byte4>(Bytes);
                for (int i = 0; i < span.Length; ++i)
                {
                    array[i].X = span[i].X;
                    array[i].Y = span[i].Y;
                    array[i].Z = span[i].Z;
                    array[i].W = span[i].W;
                }
                return(array);
            }

            default:
                throw new NotImplementedException();
            }
        }
示例#3
0
文件: Skin.cs 项目: unitycoder/UniVRM
        void Apply(VertexBuffer vertexBuffer)
        {
            var dstPosition = SpanLike.Wrap <Vector3>(vertexBuffer.Positions.Bytes);

            // Span<Vector3> emptyNormal = stackalloc Vector3[0];
            Apply(vertexBuffer, dstPosition, vertexBuffer.Normals != null ? SpanLike.Wrap <Vector3>(vertexBuffer.Normals.Bytes) : default);
        }
示例#4
0
        // Index用
        public int[] GetAsIntArray()
        {
            if (AccessorType != AccessorVectorType.SCALAR)
            {
                throw new InvalidOperationException("not scalar");
            }
            switch (ComponentType)
            {
            case AccessorValueType.UNSIGNED_SHORT:
            {
                var span  = SpanLike.Wrap <UInt16>(Bytes);
                var array = new int[span.Length];
                for (int i = 0; i < span.Length; ++i)
                {
                    array[i] = span[i];
                }
                return(array);
            }

            case AccessorValueType.UNSIGNED_INT:
                return(SpanLike.Wrap <Int32>(Bytes).ToArray());

            default:
                throw new NotImplementedException();
            }
        }
示例#5
0
            List <ValueTuple <int, Triangle> > > SplitTriangles(Mesh src)
        {
            var triangles     = src.Triangles.ToArray();
            var morphUseCount = new int[triangles.Length];

            // 各モーフ
            foreach (var morph in src.MorphTargets)
            {
                if (morph.VertexBuffer.Count == 0)
                {
                    // 無効
                    continue;
                }
                // POSITIONが使っているtriangleのカウンターをアップさせる
                var positions = SpanLike.Wrap <Vector3>(morph.VertexBuffer.Positions.Bytes);
                for (int i = 0; i < triangles.Length; ++i)
                {
                    ref var triangle = ref triangles[i];
                    if (positions[triangle.Item2.Vertex0] != Vector3.Zero)
                    {
                        ++morphUseCount[i];
                    }
                    if (positions[triangle.Item2.Vertex1] != Vector3.Zero)
                    {
                        ++morphUseCount[i];
                    }
                    if (positions[triangle.Item2.Vertex2] != Vector3.Zero)
                    {
                        ++morphUseCount[i];
                    }
                }
            }
示例#6
0
 static void ReverseX(BufferAccessor ba)
 {
     if (ba.ComponentType != AccessorValueType.FLOAT)
     {
         throw new Exception();
     }
     if (ba.AccessorType == AccessorVectorType.VEC3)
     {
         var span = SpanLike.Wrap <Vector3>(ba.Bytes);
         for (int i = 0; i < span.Length; ++i)
         {
             span[i] = span[i].ReverseX();
         }
     }
     else if (ba.AccessorType == AccessorVectorType.MAT4)
     {
         var span = SpanLike.Wrap <Matrix4x4>(ba.Bytes);
         for (int i = 0; i < span.Length; ++i)
         {
             span[i] = span[i].ReverseX();
         }
     }
     else
     {
         throw new NotImplementedException();
     }
 }
示例#7
0
 public SpanLike <T> GetSpan <T>(bool checkStride = true) where T : struct
 {
     if (checkStride && Marshal.SizeOf(typeof(T)) != Stride)
     {
         throw new Exception("different sizeof(T) with stride");
     }
     return(SpanLike.Wrap <T>(Bytes));
 }
示例#8
0
文件: Skin.cs 项目: unitycoder/UniVRM
        /// <summary>
        /// BoneSkinningもしくはMorphTargetの適用
        /// <summary>
        public void Skinning(VertexBuffer vertexBuffer = null)
        {
            m_indexOfRoot = (ushort)Joints.IndexOf(Root);
            var addRoot = Root != null && m_indexOfRoot == ushort.MaxValue;

            if (addRoot)
            {
                m_indexOfRoot = (ushort)Joints.Count;
                Joints.Add(Root);
            }

            if (m_matrices == null)
            {
                m_matrices = new Matrix4x4[Joints.Count];
            }

            if (InverseMatrices == null)
            {
                CalcInverseMatrices();
            }
            else
            {
                if (addRoot)
                {
                    var inverseArray = SpanLike.Wrap <Matrix4x4>(InverseMatrices.Bytes).ToArray();
                    var concat       = inverseArray.Concat(new[] { Root.InverseMatrix }).ToArray();
                    InverseMatrices.Assign(concat);
                }
            }

            var inverse = InverseMatrices.GetSpan <Matrix4x4>();

            // if (Root != null)
            // {
            //     var rootInverse = Root.InverseMatrix;
            //     var root = Root.Matrix;
            //     for (int i = 0; i < m_matrices.Length; ++i)
            //     {
            //         m_matrices[i] = inverse[i] * Joints[i].Matrix * rootInverse;
            //     }
            // }
            // else
            {
                for (int i = 0; i < m_matrices.Length; ++i)
                {
                    var inv = i < inverse.Length ? inverse[i] : Joints[i].InverseMatrix;
                    m_matrices[i] = inv * Joints[i].Matrix;
                }
            }

            if (vertexBuffer != null)
            {
                Apply(vertexBuffer);
            }
        }
示例#9
0
        public SpanLike <SkinJoints> GetOrCreateJoints()
        {
            var buffer = Joints;

            if (buffer == null)
            {
                buffer = new BufferAccessor(
                    new ArraySegment <byte>(new byte[Marshal.SizeOf(typeof(SkinJoints)) * Count]),
                    AccessorValueType.UNSIGNED_SHORT,
                    AccessorVectorType.VEC4, Count);
                Add(JointKey, buffer);
            }
            return(SpanLike.Wrap <SkinJoints>(buffer.Bytes));
        }
示例#10
0
        public SpanLike <Vector4> GetOrCreateWeights()
        {
            var buffer = Weights;

            if (buffer == null)
            {
                buffer = new BufferAccessor(
                    new ArraySegment <byte>(new byte[Marshal.SizeOf(typeof(Vector4)) * Count]),
                    AccessorValueType.FLOAT,
                    AccessorVectorType.VEC4, Count);
                Add(WeightKey, buffer);
            }
            return(SpanLike.Wrap <Vector4>(buffer.Bytes));
        }
示例#11
0
        public static BufferAccessor Create <T>(T[] list) where T : struct
        {
            var t     = typeof(T);
            var bytes = new byte[list.Length * Marshal.SizeOf(t)];
            var span  = SpanLike.Wrap <T>(new ArraySegment <byte>(bytes));

            for (int i = 0; i < list.Length; ++i)
            {
                span[i] = list[i];
            }
            AccessorValueType  componentType = default(AccessorValueType);
            AccessorVectorType accessorType  = default(AccessorVectorType);

            if (t == typeof(Vector2))
            {
                componentType = AccessorValueType.FLOAT;
                accessorType  = AccessorVectorType.VEC2;
            }
            else if (t == typeof(Vector3))
            {
                componentType = AccessorValueType.FLOAT;
                accessorType  = AccessorVectorType.VEC3;
            }
            else if (t == typeof(Vector4))
            {
                componentType = AccessorValueType.FLOAT;
                accessorType  = AccessorVectorType.VEC4;
            }
            else if (t == typeof(Quaternion))
            {
                componentType = AccessorValueType.FLOAT;
                accessorType  = AccessorVectorType.VEC4;
            }
            else if (t == typeof(SkinJoints))
            {
                componentType = AccessorValueType.UNSIGNED_SHORT;
                accessorType  = AccessorVectorType.VEC4;
            }
            else if (t == typeof(int))
            {
                componentType = AccessorValueType.UNSIGNED_INT;
                accessorType  = AccessorVectorType.SCALAR;
            }
            else
            {
                throw new NotImplementedException();
            }
            return(new BufferAccessor(
                       new ArraySegment <byte>(bytes), componentType, accessorType, list.Length));
        }
示例#12
0
        // Weigt用
        public Vector4[] GetAsVector4()
        {
            if (AccessorType != AccessorVectorType.VEC4)
            {
                throw new InvalidOperationException("not vec4");
            }
            switch (ComponentType)
            {
            case AccessorValueType.FLOAT:
                return(SpanLike.Wrap <Vector4>(Bytes).ToArray());

            default:
                throw new NotImplementedException();
            }
        }
示例#13
0
 /// <summary>
 /// UVのVを反転する。 => V = 1.0 - V
 /// </summary>
 static void UVVerticalFlip(this Model model)
 {
     foreach (var g in model.MeshGroups)
     {
         foreach (var m in g.Meshes)
         {
             var uv = m.VertexBuffer.TexCoords;
             if (uv != null)
             {
                 var span = SpanLike.Wrap <Vector2>(uv.Bytes);
                 for (int i = 0; i < span.Length; ++i)
                 {
                     span[i] = span[i].UVVerticalFlip();
                 }
             }
         }
     }
 }
示例#14
0
        // Skin.Normalize
        public static void ApplyRotationAndScaling(this Mesh mesh, Matrix4x4 m)
        {
            m.Translation = Vector3.Zero;

            var position = SpanLike.Wrap <Vector3>(mesh.VertexBuffer.Positions.Bytes);
            var normal   = SpanLike.Wrap <Vector3>(mesh.VertexBuffer.Normals.Bytes);

            for (int i = 0; i < position.Length; ++i)
            {
                {
                    var dst = Vector4.Transform(new Vector4(position[i], 1), m);
                    position[i] = new Vector3(dst.X, dst.Y, dst.Z);
                }
                {
                    var dst = Vector4.Transform(new Vector4(normal[i], 0), m);
                    normal[i] = new Vector3(dst.X, dst.Y, dst.Z);
                }
            }
        }
示例#15
0
        public List <int> GetAsIntList()
        {
            if (AccessorType != AccessorVectorType.SCALAR)
            {
                throw new InvalidOperationException("not scalar");
            }
            switch (ComponentType)
            {
            case AccessorValueType.UNSIGNED_SHORT:
            {
                var span  = SpanLike.Wrap <UInt16>(Bytes);
                var array = new List <int>(Count);
                if (span.Length != Count)
                {
                    for (int i = 0; i < Count; ++i)
                    {
                        array.Add(span[i]);
                    }
                }
                else
                {
                    // Spanが動かない?WorkAround
                    var bytes  = Bytes.ToArray();
                    var offset = 0;
                    for (int i = 0; i < Count; ++i)
                    {
                        array.Add(BitConverter.ToUInt16(bytes, offset));
                        offset += 2;
                    }
                }
                return(array);
            }

            case AccessorValueType.UNSIGNED_INT:
                return(SpanLike.Wrap <Int32>(Bytes).ToArray().ToList());

            default:
                throw new NotImplementedException();
            }
        }
示例#16
0
文件: Skin.cs 项目: unitycoder/UniVRM
        public void CalcInverseMatrices()
        {
            // var root = Root;
            // if (root == null)
            // {
            //     root = Joints[0].Ancestors().Last();
            // }
            // root.CalcWorldMatrix(Matrix4x4.Identity, true);

            // calc inverse bind matrices
            var matricesBytes = new Byte[Marshal.SizeOf(typeof(Matrix4x4)) * Joints.Count];
            var matrices      = SpanLike.Wrap <Matrix4x4>(new ArraySegment <byte>(matricesBytes));

            for (int i = 0; i < Joints.Count; ++i)
            {
                // var w = Joints[i].Matrix;
                // Matrix4x4.Invert(w, out Matrix4x4 inv);
                if (Joints[i] != null)
                {
                    matrices[i] = Joints[i].InverseMatrix;
                }
            }
            InverseMatrices = new BufferAccessor(new ArraySegment <byte>(matricesBytes), AccessorValueType.FLOAT, AccessorVectorType.MAT4, Joints.Count);
        }
示例#17
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);
        }
示例#18
0
        /// <summary>
        /// * Position, Normal の Z座標に -1 を乗算する
        /// * Rotation => Axis Angle に分解 => Axis の Z座標に -1 を乗算。Angle に -1 を乗算
        /// * Triangle の index を 0, 1, 2 から 2, 1, 0 に反転する
        /// </summary>
        static void ReverseAxisAndFlipTriangle(this Model model, Reverser reverser, bool ignoreVrm)
        {
            foreach (var g in model.MeshGroups)
            {
                foreach (var m in g.Meshes)
                {
                    foreach (var(k, v) in m.VertexBuffer)
                    {
                        if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
                        {
                            reverser.ReverseBuffer(v);
                        }
                        else if (k == VertexBuffer.TangentKey)
                        {
                            // I don't know
                        }
                    }

                    switch (m.IndexBuffer.ComponentType)
                    {
                    case AccessorValueType.UNSIGNED_BYTE:
                        FlipTriangle(SpanLike.Wrap <Byte>(m.IndexBuffer.Bytes));
                        break;

                    case AccessorValueType.UNSIGNED_SHORT:
                        FlipTriangle(SpanLike.Wrap <UInt16>(m.IndexBuffer.Bytes));
                        break;

                    case AccessorValueType.UNSIGNED_INT:
                        FlipTriangle(SpanLike.Wrap <UInt32>(m.IndexBuffer.Bytes));
                        break;

                    default:
                        throw new NotImplementedException();
                    }

                    foreach (var mt in m.MorphTargets)
                    {
                        foreach (var(k, v) in mt.VertexBuffer)
                        {
                            if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
                            {
                                reverser.ReverseBuffer(v);
                            }
                            if (k == VertexBuffer.TangentKey)
                            {
                                // I don't know
                            }
                        }
                    }
                }
            }

            // 親から順に処理する
            // Rootは原点決め打ちのノード(GLTFに含まれない)
            foreach (var n in model.Root.Traverse().Skip(1))
            {
                n.SetMatrix(reverser.ReverseMatrix(n.Matrix), false);
            }
            // 親から順に処理したので不要
            // model.Root.CalcWorldMatrix();

            foreach (var s in model.Skins)
            {
                if (s.InverseMatrices != null)
                {
                    reverser.ReverseBuffer(s.InverseMatrices);
                }
            }

            foreach (var a in model.Animations)
            {
                // TODO:
            }
        }
示例#19
0
文件: Skin.cs 项目: unitycoder/UniVRM
        public void Apply(VertexBuffer vertexBuffer, SpanLike <Vector3> dstPosition, SpanLike <Vector3> dstNormal)
        {
            var jointsBuffer = vertexBuffer.Joints;
            var joints       = (jointsBuffer != null || jointsBuffer.Count == 0)
                ? SpanLike.Wrap <SkinJoints>(jointsBuffer.Bytes)
                : SpanLike.Create <SkinJoints>(vertexBuffer.Count) // when MorphTarget only
            ;

            var weightsBuffer = vertexBuffer.Weights;
            var weights       = (weightsBuffer != null || weightsBuffer.Count == 0)
                ? SpanLike.Wrap <Vector4>(weightsBuffer.Bytes)
                : SpanLike.Create <Vector4>(vertexBuffer.Count) // when MorphTarget only
            ;

            var positionBuffer = vertexBuffer.Positions;
            var position       = SpanLike.Wrap <Vector3>(positionBuffer.Bytes);

            bool useNormal = false;

            if (dstNormal.Length > 0)
            {
                useNormal = vertexBuffer.Normals != null && dstNormal.Length == dstPosition.Length;
            }

            for (int i = 0; i < position.Length; ++i)
            {
                var j = joints[i];
                var w = weights[i];

                var   sum = (w.X + w.Y + w.Z + w.W);
                float factor;
                if (sum > 0)
                {
                    factor = 1.0f / sum;
                }
                else
                {
                    factor = 1.0f;
                    j      = new SkinJoints(m_indexOfRoot, 0, 0, 0);
                    w      = new Vector4(1, 0, 0, 0);
                }
                if (j.Joint0 == ushort.MaxValue)
                {
                    w.X = 0;
                }
                if (j.Joint1 == ushort.MaxValue)
                {
                    w.Y = 0;
                }
                if (j.Joint2 == ushort.MaxValue)
                {
                    w.Z = 0;
                }
                if (j.Joint3 == ushort.MaxValue)
                {
                    w.W = 0;
                }

                {
                    var src = new Vector4(position[i], 1); // 位置ベクトル
                    var dst = Vector4.Zero;
                    if (w.X > 0)
                    {
                        dst += Vector4.Transform(src, m_matrices[j.Joint0]) * w.X * factor;
                    }
                    if (w.Y > 0)
                    {
                        dst += Vector4.Transform(src, m_matrices[j.Joint1]) * w.Y * factor;
                    }
                    if (w.Z > 0)
                    {
                        dst += Vector4.Transform(src, m_matrices[j.Joint2]) * w.Z * factor;
                    }
                    if (w.W > 0)
                    {
                        dst += Vector4.Transform(src, m_matrices[j.Joint3]) * w.W * factor;
                    }
                    dstPosition[i] = new Vector3(dst.X, dst.Y, dst.Z);
                }
                if (useNormal)
                {
                    var normalBuffer = vertexBuffer.Normals;
                    var normal       = normalBuffer != null?SpanLike.Wrap <Vector3>(normalBuffer.Bytes) : dstNormal;

                    var src = new Vector4(normal[i], 0); // 方向ベクトル
                    var dst = Vector4.Zero;
                    if (w.X > 0)
                    {
                        dst += Vector4.Transform(src, m_matrices[j.Joint0]) * w.X * factor;
                    }
                    if (w.Y > 0)
                    {
                        dst += Vector4.Transform(src, m_matrices[j.Joint1]) * w.Y * factor;
                    }
                    if (w.Z > 0)
                    {
                        dst += Vector4.Transform(src, m_matrices[j.Joint2]) * w.Z * factor;
                    }
                    if (w.W > 0)
                    {
                        dst += Vector4.Transform(src, m_matrices[j.Joint3]) * w.W * factor;
                    }
                    dstNormal[i] = new Vector3(dst.X, dst.Y, dst.Z);
                }
            }
        }
示例#20
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();
                        }
                    }
                }
            }
        }
        /// <summary>
        /// * Position, Normal の Z座標に -1 を乗算する
        /// * Rotation => Axis Angle に分解 => Axis の Z座標に -1 を乗算。Angle に -1 を乗算
        /// * Triangle の index を 0, 1, 2 から 2, 1, 0 に反転する
        /// </summary>
        static void ReverseZAndFlipTriangle(this Model model, bool ignoreVrm)
        {
            foreach (var g in model.MeshGroups)
            {
                foreach (var m in g.Meshes)
                {
                    foreach (var(k, v) in m.VertexBuffer)
                    {
                        if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
                        {
                            ReverseZ(v);
                        }
                        if (k == VertexBuffer.TangentKey)
                        {
                            // I don't know
                        }
                    }

                    switch (m.IndexBuffer.ComponentType)
                    {
                    case AccessorValueType.UNSIGNED_BYTE:
                        FlipTriangle(SpanLike.Wrap <Byte>(m.IndexBuffer.Bytes));
                        break;

                    case AccessorValueType.UNSIGNED_SHORT:
                        FlipTriangle(SpanLike.Wrap <UInt16>(m.IndexBuffer.Bytes));
                        break;

                    case AccessorValueType.UNSIGNED_INT:
                        FlipTriangle(SpanLike.Wrap <UInt32>(m.IndexBuffer.Bytes));
                        break;

                    default:
                        throw new NotImplementedException();
                    }

                    foreach (var mt in m.MorphTargets)
                    {
                        foreach (var(k, v) in mt.VertexBuffer)
                        {
                            if (k == VertexBuffer.PositionKey || k == VertexBuffer.NormalKey)
                            {
                                ReverseZ(v);
                            }
                            if (k == VertexBuffer.TangentKey)
                            {
                                // I don't know
                            }
                        }
                    }
                }
            }

            // 親から順に処理する
            // Rootは原点決め打ちのノード(GLTFに含まれない)
            foreach (var n in model.Root.Traverse().Skip(1))
            {
                n.SetMatrix(n.Matrix.ReverseZ(), false);
            }
            // 親から順に処理したので不要
            // model.Root.CalcWorldMatrix();

            foreach (var s in model.Skins)
            {
                if (s.InverseMatrices != null)
                {
                    ReverseZ(s.InverseMatrices);
                }
            }

            foreach (var a in model.Animations)
            {
                // TODO:
            }

            if (model.Vrm != null)
            {
                if (!ignoreVrm)
                {
                    // LookAt
                    if (model.Vrm.LookAt != null)
                    {
                        model.Vrm.LookAt.OffsetFromHeadBone = model.Vrm.LookAt.OffsetFromHeadBone.ReverseZ();
                    }

                    // SpringBone
                    if (model.Vrm.SpringBone != null)
                    {
                        foreach (var b in model.Vrm.SpringBone.Springs)
                        {
                            foreach (var c in b.Colliders)
                            {
                                for (int i = 0; i < c.Colliders.Count; ++i)
                                {
                                    var s = c.Colliders[i];
                                    switch (s.ColliderType)
                                    {
                                    case VrmSpringBoneColliderTypes.Sphere:
                                        c.Colliders[i] = VrmSpringBoneCollider.CreateSphere(s.Offset.ReverseZ(), s.Radius);
                                        break;

                                    case VrmSpringBoneColliderTypes.Capsule:
                                        c.Colliders[i] = VrmSpringBoneCollider.CreateCapsule(s.Offset.ReverseZ(), s.Radius, s.CapsuleTail.ReverseZ());
                                        break;

                                    default:
                                        throw new NotImplementedException();
                                    }
                                }
                            }

                            b.GravityDir = b.GravityDir.ReverseZ();
                        }
                    }
                }
            }
        }
示例#22
0
        public static IEnumerable <Node> GetRemoveNodes(this Model model)
        {
            var nodeUsage = model.Nodes.Select(x =>
                                               new NodeUsage
            {
                HasMesh          = x.MeshGroup != null,
                HumanBone        = x.HumanoidBone,
                TreeHasHumanBone = x.Traverse().Any(y => y.HumanoidBone.HasValue),
            })
                            .ToArray();

            var bones = model.Nodes.Where(x => x.HumanoidBone.HasValue).ToArray();

            // joint use
            foreach (var meshGroup in model.MeshGroups)
            {
                var skin = meshGroup.Skin;
                if (skin != null)
                {
                    foreach (var mesh in meshGroup.Meshes)
                    {
                        var joints  = mesh.VertexBuffer.Joints;
                        var weights = mesh.VertexBuffer.Weights;
                        if (joints != null && weights != null)
                        {
                            var jointsSpan  = SpanLike.Wrap <SkinJoints>(joints.Bytes);
                            var weightsSpan = SpanLike.Wrap <Vector4>(weights.Bytes);
                            for (int i = 0; i < jointsSpan.Length; ++i)
                            {
                                var w = weightsSpan[i];
                                var j = jointsSpan[i];
                                if (w.X > 0)
                                {
                                    nodeUsage[model.Nodes.IndexOf(skin.Joints[j.Joint0])].WeightUsed++;
                                }
                                if (w.Y > 0)
                                {
                                    nodeUsage[model.Nodes.IndexOf(skin.Joints[j.Joint1])].WeightUsed++;
                                }
                                if (w.Z > 0)
                                {
                                    nodeUsage[model.Nodes.IndexOf(skin.Joints[j.Joint2])].WeightUsed++;
                                }
                                if (w.W > 0)
                                {
                                    nodeUsage[model.Nodes.IndexOf(skin.Joints[j.Joint3])].WeightUsed++;
                                }
                            }
                        }
                    }
                }
            }

            // 削除されるNodeのうち、子階層に1つでも残るNodeがあればそのNodeも残す
            for (int i = 0; i < nodeUsage.Length; i++)
            {
                if (nodeUsage[i].Used)
                {
                    continue;
                }

                var children = model.Nodes[i].Traverse();

                nodeUsage[i].TreeHasUsedBone = children.Where(x => nodeUsage[model.Nodes.IndexOf(x)].Used).Any();
            }


            var spring = model.Vrm?.SpringBone;

            if (spring != null)
            {
                foreach (var x in spring.Springs)
                {
                    foreach (var y in x.Joints)
                    {
                        nodeUsage[model.Nodes.IndexOf(y.Node)].SpringUse = true;
                    }
                    foreach (var y in x.Colliders)
                    {
                        nodeUsage[model.Nodes.IndexOf(y.Node)].SpringUse = true;
                    }
                }
            }

            var nodes = nodeUsage.Select((x, i) => (i, x))
                        .Where(x => !x.Item2.Used)
                        .Select(x => model.Nodes[x.Item1])
                        .ToArray();

            return(nodes);
        }
示例#23
0
        //
        // 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();
                }
            }
        }