コード例 #1
0
            public void SetLocalDataFromWowBone(WowBone bone)
            {
                var matrix = Mat4.Identity();

                matrix = Mat4.Translate(matrix, bone.LocalPosition);

                // Поворота и скейла у базовых костей нет

                LocalMatrix = matrix;
            }
コード例 #2
0
        /// <summary>
        /// Устанавливает родительскую кость без изменения глобальной позиции текущей кости
        /// </summary>
        public void SetParentAndKeepGlobalPosition(WowBone parentBone)
        {
            var globalPosition = GetGlobalPosition();

            ParentBone = parentBone;

            var parentGlobalPosition = ParentBone?.GetGlobalPosition() ?? new Vec3(0, 0, 0);

            LocalPosition = new Vec3(
                globalPosition.X - parentGlobalPosition.X,
                globalPosition.Y - parentGlobalPosition.Y,
                globalPosition.Z - parentGlobalPosition.Z);
        }
コード例 #3
0
        private void TranslateBoneChildrenPositionsFromGlobalToLocal(WowBone wowBone)
        {
            if (wowBone == null)
            {
                return;
            }

            foreach (var childBone in wowBone.ChildBones)
            {
                TranslateBoneChildrenPositionsFromGlobalToLocal(childBone);

                childBone.LocalPosition = new Vec3(
                    childBone.LocalPosition.X - wowBone.LocalPosition.X,
                    childBone.LocalPosition.Y - wowBone.LocalPosition.Y,
                    childBone.LocalPosition.Z - wowBone.LocalPosition.Z);
            }
        }
コード例 #4
0
            public void SetLocalDataFromBlendshapeBone(WowBone bone, WowVrcFileData.BlendshapeData.BoneData blendshapeBoneChange, float scale)
            {
                var matrix = Mat4.Identity();

                Vec3 localPosition = bone.LocalPosition;

                localPosition.X += blendshapeBoneChange.LocalTransform.position.X * scale;
                localPosition.Y += blendshapeBoneChange.LocalTransform.position.Y * scale;
                localPosition.Z += blendshapeBoneChange.LocalTransform.position.Z * scale;

                matrix = Mat4.Translate(matrix, localPosition);

                // Поврота и скейла у базовых костей нет, так что учитываем только поврот и скейл из изменений блендшейпа
                matrix = Mat4.Multiply(matrix, Mat4.FromQuat(blendshapeBoneChange.LocalTransform.rotation));
                matrix = Mat4.Scale(matrix, blendshapeBoneChange.LocalTransform.scale);

                LocalMatrix = matrix;
            }
コード例 #5
0
        /// <summary>
        /// Добавляет кость-пустышку в конец массива с костями
        /// </summary>
        public void AddDummyBone(string boneName, WowBone parent, Vec3 localPosition)
        {
            // Так как добавление идет в конец массива - индексы в вершинах перестраивать ненужно - все старые кости остаются на своих местах

            var bone = new WowBone()
            {
                Id = uint.MaxValue, Index = (byte)Bones.Length, ParentBone = parent, LocalPosition = localPosition
            };

            bone.SetName(boneName);

            Bones = Bones.Append(bone).ToArray();

            if (parent != null)
            {
                parent.ChildBones.Add(bone);
            }
        }
コード例 #6
0
        /// <summary>
        /// Удаляет заданую кость, перенося при этом внутреннюю иерархию и веса на родителя.
        /// Если родителя нет, то удалит кость (веса никуда не перенесутся) и сделает дочернюю кость рутом (если таких костей несколько, ничего не произойдет, метод вернет false)
        /// </summary>
        public bool RemoveBone(WowBone boneToRemove)
        {
            if (boneToRemove == null || (boneToRemove.ParentBone == null && boneToRemove.ChildBones.Count > 1))
            {
                return(false);
            }

            int      boneIndex = boneToRemove.Index;
            ByteVec4 boneIndexes;
            Vec4     boneWeights;
            bool     changed;

            // В случае если удаляем корневую кость (boneToRemove.ParentBone == null) то либо у нее не будет child костей вообще либо будет одна (проверяется выше)
            var boneToRemoveSingleChild = boneToRemove.ChildBones.Count == 1 ? boneToRemove.ChildBones[0] : null;

            // ToDo: возможно надо будет менять не только вершины этого объекта но и всякие приатаченные объекты,
            // которые также могут быть завязаны на эти кости (надо видимо будет хранить в объекте список мешей которые привязаны
            // к костям этим либо вообще отдельно скелет хранить и в нем уже список мешей/wowobject-ов)

            // Меняем веса у вершин в соответствии с новой иерархией костей
            foreach (var mesh in Meshes)
            {
                foreach (var vertex in mesh.Vertices)
                {
                    boneIndexes = vertex.BoneIndexes;
                    boneWeights = vertex.BoneWeights;
                    changed     = false;

                    for (int i = 0; i < 4; i++)
                    {
                        if (boneIndexes[i] == boneIndex)
                        {
                            if (boneToRemove.ParentBone != null)
                            {
                                boneIndexes[i] = boneToRemove.ParentBone.Index;
                            }
                            else if (boneToRemoveSingleChild != null)
                            {
                                boneIndexes[i] = boneToRemoveSingleChild.Index;
                            }
                            else
                            {
                                boneIndexes[i] = 0;
                                boneWeights[i] = 0;
                            }

                            changed = true;
                        }
                    }

                    if (changed)
                    {
                        boneWeights.NormalizeSum();

                        vertex.BoneIndexes = boneIndexes;
                        vertex.BoneWeights = boneWeights;
                    }
                }
            }

            // Удаляем кость из списка костей и перебрасываем ее children на родителя удаляемой кости
            for (int i = 0; i < Bones.Length; i++)
            {
                if (Bones[i] == boneToRemove)
                {
                    Bones[i] = null;

                    foreach (var child in boneToRemove.ChildBones)
                    {
                        child.SetParentAndKeepGlobalPosition(boneToRemove.ParentBone);
                        child.ParentBone?.ChildBones.Add(child);
                    }

                    boneToRemove.ParentBone?.ChildBones.Remove(boneToRemove);

                    return(true);
                }
            }

            throw new InvalidOperationException("Похоже что идет удаление кости, которой не существет в массиве костей");
        }