public void SetLocalDataFromWowBone(WowBone bone) { var matrix = Mat4.Identity(); matrix = Mat4.Translate(matrix, bone.LocalPosition); // Поворота и скейла у базовых костей нет LocalMatrix = matrix; }
/// <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); }
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); } }
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; }
/// <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); } }
/// <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("Похоже что идет удаление кости, которой не существет в массиве костей"); }