Пример #1
0
        public static string MaterialIntegrate(this ModelModifier modifier)
        {
            var sb        = new System.Text.StringBuilder();
            var materials = new List <Material>();

            foreach (var material in modifier.Model.Materials.ToArray())
            {
                var found = materials.FirstOrDefault(x => x.CanIntegrate(material));
                if (found != null)
                {
                    // merge
                    modifier.MaterialReplace(material, found);
                }
                else
                {
                    // add
                    materials.Add(material);
                }
            }

            sb.Append($"MaterialIntegrate: {modifier.Model.Materials.Count} => {materials.Count}");

            modifier.Model.Materials.Clear();
            modifier.Model.Materials.AddRange(materials);

            return(sb.ToString());
        }
Пример #2
0
        public static string CloneSharedMesh(this ModelModifier modifier)
        {
            Dictionary <MeshGroup, int> m_useMap = new Dictionary <MeshGroup, int>();

            var cloned = new List <string>();

            foreach (var node in modifier.Model.Nodes)
            {
                if (node.MeshGroup == null)
                {
                    continue;
                }

                var n = m_useMap.GetValueOrDefault(node.MeshGroup);
                if (n > 0)
                {
                    // copy
                    node.MeshGroup = node.MeshGroup.Clone();
                    cloned.Add($"[{node.MeshGroup.Name}]");
                }
                m_useMap[node.MeshGroup] = n + 1;
            }

            if (!cloned.Any())
            {
                return("CloneSharedMesh: no shared mesh. do nothing");
            }
            else
            {
                var joined = string.Join("", cloned);
                return($"CloneSharedMesh: copy {joined}");
            }
        }
Пример #3
0
        /// BlendShape
        /// FirstPersonの置き換え
        public static void MeshNodeReplace(this ModelModifier modifier, Node src, Node dst)
        {
            var vrm = modifier.Model.Vrm;

            if (vrm is null)
            {
                return;
            }

            if (vrm.BlendShape != null)
            {
                foreach (var b in vrm.BlendShape.BlendShapeList)
                {
                    foreach (var v in b.BlendShapeValues)
                    {
                        if (v.Node == src)
                        {
                            v.Node = dst;
                        }
                    }
                }
            }
            if (vrm.FirstPerson != null)
            {
                foreach (var a in vrm.FirstPerson.Annotations)
                {
                    if (a.Node == src)
                    {
                        a.Node = dst;
                    }
                }
            }
        }
Пример #4
0
        public static void SepareteByHeadBone(this ModelModifier modifier, MeshGroup mesh, HashSet <int> boneIndices)
        {
            var(with, without) = mesh.SepareteByHeadBone(boneIndices);
            var list = new List <MeshGroup>();

            if (with != null)
            {
                list.Add(with);
            }
            if (without != null)
            {
                list.Add(without);
            }

            // 分割モデルで置き換え
            if (list.Any())
            {
                modifier.MeshReplace(mesh, list[0]);
                // rename node
                modifier.Model.Nodes.Find(x => x.MeshGroup == list[0]).Name = list[0].Name;
            }

            if (list.Count > 1)
            {
                // 頭と胴体で分割後2つ以上ある場合、2つ目を追加する
                modifier.MeshReplace(null, list[1]);
                modifier.NodeAdd(new Node(list[1].Name)
                {
                    MeshGroup = list[1]
                });
            }
        }
Пример #5
0
        public static void SepareteByMorphTarget(this ModelModifier modifier, MeshGroup mesh)
        {
            var(with, without) = mesh.SepareteByMorphTarget();
            var list = new List <MeshGroup>();

            if (with != null)
            {
                list.Add(with);
            }
            if (without != null)
            {
                list.Add(without);
            }

            // 分割モデルで置き換え
            if (list.Any())
            {
                modifier.MeshReplace(mesh, list[0]);
                // rename node
                modifier.Model.Nodes.Find(x => x.MeshGroup == list[0]).Name = list[0].Name;
            }

            if (list.Count > 1)
            {
                // morph無しと有り両方存在する場合に2つ目を追加する
                modifier.MeshReplace(null, list[1]);
                modifier.NodeAdd(new Node(list[1].Name)
                {
                    MeshGroup = list[1]
                });
            }
        }
Пример #6
0
        public static string NodeReduce(this ModelModifier modifier)
        {
            var count       = modifier.Model.Nodes.Count;
            var removeNames = new List <string>();

            // ノードを削除する
            foreach (var node in modifier.Model.GetRemoveNodes())
            {
                modifier.NodeRemove(node);
                removeNames.Add($"[{node.Name}]");
            }

            // 削除されたノードを参照する頂点バッファを修正する
            foreach (var meshGroup in modifier.Model.MeshGroups)
            {
                var skin = meshGroup.Skin;
                if (skin != null && skin.Joints.Contains(null))
                {
                    foreach (var mesh in meshGroup.Meshes)
                    {
                        skin.FixBoneWeight(mesh.VertexBuffer.Joints, mesh.VertexBuffer.Weights);
                    }
                }
            }

            var joined = string.Join("", removeNames);

            return($"NodeReduce: {count} => {modifier.Model.Nodes.Count}");
            // return $"NodeReduce: {joined}";
        }
Пример #7
0
        public static string SingleMesh(this ModelModifier modifier, string name)
        {
            var count  = modifier.Model.MeshGroups.Sum(x => x.Meshes.Count);
            var meshes = modifier.Model.Root.Traverse()
                         .Select(x => x.MeshGroup)
                         .Where(x => x != null)
                         .Select(x => $"[{x.Name}]")
                         .ToArray();

            if (meshes.Length == 0)
            {
                return("SingleMesh: no mesh. do nothing");
            }
            if (meshes.Length <= 1)
            {
                return("SingleMesh: one mesh. do nothing");
            }

            var mesh     = modifier.Model.CreateSingleMesh(name);
            var meshNode = new Node(mesh.Name)
            {
                MeshGroup = mesh,
            };

            mesh.Skin.Root = meshNode;

            // fix bone weight (0, x, 0, 0) => (x, 0, 0, 0)
            // mesh.Meshes[0].VertexBuffer.FixBoneWeight();

            // replace morphAnimation reference
            ReplaceMorphTargetAnimationNode(modifier.Model.Animations, meshNode);

            // update Model
            foreach (var x in modifier.Model.MeshGroups.ToArray())
            {
                modifier.MeshReplace(x, mesh);
            }
            foreach (var node in modifier.Model.Nodes)
            {
                if (node.MeshGroup != null)
                {
                    node.MeshGroup = null;
                    modifier.MeshNodeReplace(node, meshNode);
                }
            }
            modifier.NodeAdd(meshNode);

            var names = string.Join("", meshes);

            // return $"SingleMesh: {names}";
            return($"SingleMesh: {count} => {modifier.Model.MeshGroups.Sum(x => x.Meshes.Count)}");
        }
Пример #8
0
        /// <summary>
        // [Debug向け]secondaryを除去
        /// </summary>
        public static void RemoveSecondary(this Model model)
        {
            var secondary = model.Nodes
                            .FirstOrDefault(x =>
                                            (x.Name == "secondary" || x.Name == "SpringBone") &&
                                            x.Parent == model.Root &&
                                            x.Children.Count == 0)
            ;

            if (secondary != null)
            {
                var mod = new ModelModifier(model);
                mod.NodeRemove(secondary);
            }
        }
Пример #9
0
        public static string SkinningBake(this ModelModifier modifier)
        {
            foreach (var node in modifier.Model.Nodes)
            {
                var meshGroup = node.MeshGroup;
                if (meshGroup == null)
                {
                    continue;
                }

                if (meshGroup.Skin != null)
                {
                    // 正規化されていれば1つしかない
                    // されていないと Primitive の数だけある
                    foreach (var mesh in meshGroup.Meshes)
                    {
                        {
                            // Skinningの出力先を自身にすることでBakeする
                            meshGroup.Skin.Skinning(mesh.VertexBuffer);
                        }

                        // morphのPositionは相対値が入っているはずなので、手を加えない(正規化されていない場合、二重に補正が掛かる)

                        /*
                         *                      foreach (var morph in mesh.MorphTargets)
                         *                      {
                         *                          if (morph.VertexBuffer.Positions != null)
                         *                          {
                         *                              meshGroup.Skin.Skinning(morph.VertexBuffer);
                         *                          }
                         *                      }
                         */
                    }

                    meshGroup.Skin.Root            = null;
                    meshGroup.Skin.InverseMatrices = null;
                }
                else
                {
                    foreach (var mesh in meshGroup.Meshes)
                    {
                        // nodeに対して疑似的にSkinningする
                        // 回転と拡縮を適用し位置は適用しない
                        mesh.ApplyRotationAndScaling(node.Matrix);
                    }
                }
            }

            // 回転・拡縮を除去する
            modifier.Model.ApplyRotationAndScale();

            // inverse matrix の再計算
            foreach (var node in modifier.Model.Nodes)
            {
                var meshGroup = node.MeshGroup;
                if (meshGroup == null)
                {
                    continue;
                }

                foreach (var mesh in meshGroup.Meshes)
                {
                    if (meshGroup.Skin != null)
                    {
                        meshGroup.Skin.CalcInverseMatrices();
                    }
                }
            }

            return("SkinningBake");
        }