From 4163f09a761318f28a81a14c32384e33ca8a714d Mon Sep 17 00:00:00 2001 From: turanszkij Date: Thu, 14 Mar 2019 19:05:37 +0000 Subject: [PATCH] another gltf armature import fix --- Editor/Editor.cpp | 30 ++++---- Editor/ModelImporter.h | 6 +- Editor/ModelImporter_GLTF.cpp | 90 ++++++++++------------ Editor/ModelImporter_OBJ.cpp | 5 +- WickedEngine/ArchiveVersionHistory.txt | 1 + WickedEngine/wiArchive.cpp | 2 +- WickedEngine/wiSceneSystem.cpp | 34 ++++---- WickedEngine/wiSceneSystem.h | 2 - WickedEngine/wiSceneSystem_Serializers.cpp | 6 +- WickedEngine/wiVersion.cpp | 2 +- 10 files changed, 84 insertions(+), 94 deletions(-) diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index e9817460c..437703e3f 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -453,15 +453,21 @@ void EditorComponent::Load() } else if (!extension.compare("OBJ")) // wavefront-obj { - ImportModel_OBJ(fileName); + Scene scene; + ImportModel_OBJ(fileName, scene); + wiRenderer::GetScene().Merge(scene); } else if (!extension.compare("GLTF")) // text-based gltf { - ImportModel_GLTF(fileName); + Scene scene; + ImportModel_GLTF(fileName, scene); + wiRenderer::GetScene().Merge(scene); } else if (!extension.compare("GLB")) // binary gltf { - ImportModel_GLTF(fileName); + Scene scene; + ImportModel_GLTF(fileName, scene); + wiRenderer::GetScene().Merge(scene); } }); loader->onFinished([=] { @@ -982,17 +988,15 @@ void EditorComponent::Update(float dt) { for (size_t i = 0; i < scene.armatures.GetCount(); ++i) { - const ArmatureComponent& armature = scene.armatures[i]; - if (armature.rootBoneID == INVALID_ENTITY) - continue; - const TransformComponent& transform = *scene.transforms.GetComponent(armature.rootBoneID); + Entity entity = scene.armatures.GetEntity(i); + const TransformComponent& transform = *scene.transforms.GetComponent(entity); XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), transform.GetPositionV()); float dis = XMVectorGetX(disV); if (dis < wiMath::Distance(transform.GetPosition(), pickRay.origin) * 0.05f && dis < hovered.distance) { hovered = wiRenderer::RayIntersectWorldResult(); - hovered.entity = armature.rootBoneID; + hovered.entity = entity; hovered.distance = dis; } } @@ -1643,10 +1647,8 @@ void EditorComponent::Compose() const { for (size_t i = 0; i < scene.armatures.GetCount(); ++i) { - const ArmatureComponent& armature = scene.armatures[i]; - if (armature.rootBoneID == INVALID_ENTITY) - continue; - const TransformComponent& transform = *scene.transforms.GetComponent(armature.rootBoneID); + Entity entity = scene.armatures.GetEntity(i); + const TransformComponent& transform = *scene.transforms.GetComponent(entity); float dist = wiMath::Distance(transform.GetPosition(), camera.Eye) * 0.08f; @@ -1657,13 +1659,13 @@ void EditorComponent::Compose() const fx.pivot = XMFLOAT2(0.5f, 0.5f); fx.col = XMFLOAT4(1, 1, 1, 0.5f); - if (hovered.entity == armature.rootBoneID) + if (hovered.entity == entity) { fx.col = XMFLOAT4(1, 1, 1, 1); } for (auto& picked : selected) { - if (picked.entity == armature.rootBoneID) + if (picked.entity == entity) { fx.col = XMFLOAT4(1, 1, 0, 1); break; diff --git a/Editor/ModelImporter.h b/Editor/ModelImporter.h index d76bdc7f3..ede17e7aa 100644 --- a/Editor/ModelImporter.h +++ b/Editor/ModelImporter.h @@ -1,6 +1,8 @@ #pragma once #include -void ImportModel_OBJ(const std::string& fileName); -void ImportModel_GLTF(const std::string& fileName); +struct wiSceneSystem::Scene; + +void ImportModel_OBJ(const std::string& fileName, wiSceneSystem::Scene& scene); +void ImportModel_GLTF(const std::string& fileName, wiSceneSystem::Scene& scene); diff --git a/Editor/ModelImporter_GLTF.cpp b/Editor/ModelImporter_GLTF.cpp index ff9cd27b4..56475290c 100644 --- a/Editor/ModelImporter_GLTF.cpp +++ b/Editor/ModelImporter_GLTF.cpp @@ -157,7 +157,7 @@ void RegisterTexture2D(tinygltf::Image *image, const string& type_name) struct LoaderState { tinygltf::Model gltfModel; - Scene scene; + Scene* scene; unordered_map entityMap; // node -> entity }; @@ -169,27 +169,33 @@ void LoadNode(int nodeIndex, Entity parent, LoaderState& state) return; } auto& node = state.gltfModel.nodes[nodeIndex]; + Scene& scene = *state.scene; Entity entity = INVALID_ENTITY; if(node.mesh >= 0) { - entity = state.scene.Entity_CreateObject(node.name); - ObjectComponent& object = *state.scene.objects.GetComponent(entity); + assert(node.mesh < (int)scene.meshes.GetCount()); - if (node.mesh < (int)state.scene.meshes.GetCount()) + if (node.skin >= 0) { - object.meshID = state.scene.meshes.GetEntity(node.mesh); + // This node is an armature: + MeshComponent& mesh = scene.meshes[node.mesh]; + assert(!mesh.vertex_boneindices.empty()); + entity = scene.armatures.GetEntity(node.skin); + mesh.armatureID = entity; - if (node.skin >= 0) - { - MeshComponent& mesh = *state.scene.meshes.GetComponent(object.meshID); - assert(!mesh.vertex_boneindices.empty()); - mesh.armatureID = state.scene.armatures.GetEntity(node.skin); - } + // The object component will use an identity transform but will be parented to the armature: + Entity objectEntity = scene.Entity_CreateObject(node.name); + ObjectComponent& object = *scene.objects.GetComponent(objectEntity); + object.meshID = scene.meshes.GetEntity(node.mesh); + scene.Component_Attach(objectEntity, entity); } else { - assert(0); + // This node is a mesh instance: + entity = scene.Entity_CreateObject(node.name); + ObjectComponent& object = *scene.objects.GetComponent(entity); + object.meshID = scene.meshes.GetEntity(node.mesh); } } else if (node.camera >= 0) @@ -202,19 +208,19 @@ void LoadNode(int nodeIndex, Entity parent, LoaderState& state) node.name = ss.str(); } - entity = state.scene.Entity_CreateCamera(node.name, (float)wiRenderer::GetInternalResolution().x, (float)wiRenderer::GetInternalResolution().y, 0.1f, 800); + entity = scene.Entity_CreateCamera(node.name, (float)wiRenderer::GetInternalResolution().x, (float)wiRenderer::GetInternalResolution().y, 0.1f, 800); } if (entity == INVALID_ENTITY) { entity = CreateEntity(); - state.scene.transforms.Create(entity); - state.scene.names.Create(entity) = node.name; + scene.transforms.Create(entity); + scene.names.Create(entity) = node.name; } state.entityMap[nodeIndex] = entity; - TransformComponent& transform = *state.scene.transforms.GetComponent(entity); + TransformComponent& transform = *scene.transforms.GetComponent(entity); if (!node.scale.empty()) { transform.scale_local = XMFLOAT3((float)node.scale[0], (float)node.scale[1], (float)node.scale[2]); @@ -255,7 +261,7 @@ void LoadNode(int nodeIndex, Entity parent, LoaderState& state) if (parent != INVALID_ENTITY) { - state.scene.Component_Attach(entity, parent); + scene.Component_Attach(entity, parent); } if (!node.children.empty()) @@ -267,7 +273,7 @@ void LoadNode(int nodeIndex, Entity parent, LoaderState& state) } } -void ImportModel_GLTF(const std::string& fileName) +void ImportModel_GLTF(const std::string& fileName, Scene& scene) { string directory, name; wiHelper::SplitPath(fileName, directory, name); @@ -283,6 +289,7 @@ void ImportModel_GLTF(const std::string& fileName) loader.SetImageWriter(tinygltf::WriteImageData, nullptr); LoaderState state; + state.scene = &scene; bool ret; if (!extension.compare("GLTF")) @@ -298,14 +305,14 @@ void ImportModel_GLTF(const std::string& fileName) } Entity rootEntity = CreateEntity(); - state.scene.transforms.Create(rootEntity); + scene.transforms.Create(rootEntity); // Create materials: for (auto& x : state.gltfModel.materials) { - Entity materialEntity = state.scene.Entity_CreateMaterial(x.name); + Entity materialEntity = scene.Entity_CreateMaterial(x.name); - MaterialComponent& material = *state.scene.materials.GetComponent(materialEntity); + MaterialComponent& material = *scene.materials.GetComponent(materialEntity); material.baseColor = XMFLOAT4(1, 1, 1, 1); material.roughness = 1.0f; @@ -410,16 +417,16 @@ void ImportModel_GLTF(const std::string& fileName) } - if (state.scene.materials.GetCount() == 0) + if (scene.materials.GetCount() == 0) { - state.scene.Entity_CreateMaterial("gltfimport_defaultMaterial"); + scene.Entity_CreateMaterial("gltfimport_defaultMaterial"); } // Create meshes: for (auto& x : state.gltfModel.meshes) { - Entity meshEntity = state.scene.Entity_CreateMesh(x.name); - MeshComponent& mesh = *state.scene.meshes.GetComponent(meshEntity); + Entity meshEntity = scene.Entity_CreateMesh(x.name); + MeshComponent& mesh = *scene.meshes.GetComponent(meshEntity); for (auto& prim : x.primitives) { @@ -439,7 +446,7 @@ void ImportModel_GLTF(const std::string& fileName) mesh.subsets.back().indexOffset = (uint32_t)indexOffset; mesh.subsets.back().indexCount = (uint32_t)indexCount; - mesh.subsets.back().materialID = state.scene.materials.GetEntity(max(0, prim.material)); + mesh.subsets.back().materialID = scene.materials.GetEntity(max(0, prim.material)); uint32_t vertexOffset = (uint32_t)mesh.vertex_positions.size(); @@ -622,9 +629,10 @@ void ImportModel_GLTF(const std::string& fileName) for (auto& skin : state.gltfModel.skins) { Entity armatureEntity = CreateEntity(); - state.scene.names.Create(armatureEntity) = skin.name; - state.scene.layers.Create(armatureEntity); - ArmatureComponent& armature = state.scene.armatures.Create(armatureEntity); + scene.names.Create(armatureEntity) = skin.name; + scene.layers.Create(armatureEntity); + scene.transforms.Create(armatureEntity); + ArmatureComponent& armature = scene.armatures.Create(armatureEntity); if (skin.inverseBindMatrices >= 0) { @@ -651,8 +659,7 @@ void ImportModel_GLTF(const std::string& fileName) int armatureIndex = 0; for (auto& skin : state.gltfModel.skins) { - Entity entity = state.scene.armatures.GetEntity(armatureIndex++); - ArmatureComponent& armature = *state.scene.armatures.GetComponent(entity); + ArmatureComponent& armature = scene.armatures[armatureIndex++]; const size_t jointCount = skin.joints.size(); @@ -666,21 +673,14 @@ void ImportModel_GLTF(const std::string& fileName) armature.boneCollection[i] = boneEntity; } - - // Save the root bone ID: - // It is important because if the root bone is transformed, we still need to remain in armature-local space for instanced skinning - if (skin.skeleton >= 0) - { - armature.rootBoneID = state.entityMap.at(skin.skeleton); - } } // Create animations: for (auto& anim : state.gltfModel.animations) { Entity entity = CreateEntity(); - state.scene.names.Create(entity) = anim.name; - AnimationComponent& animationcomponent = state.scene.animations.Create(entity); + scene.names.Create(entity) = anim.name; + AnimationComponent& animationcomponent = scene.animations.Create(entity); animationcomponent.samplers.resize(anim.samplers.size()); animationcomponent.channels.resize(anim.channels.size()); @@ -795,18 +795,10 @@ void ImportModel_GLTF(const std::string& fileName) if (transform_to_LH) { - TransformComponent& transform = *state.scene.transforms.GetComponent(rootEntity); + TransformComponent& transform = *scene.transforms.GetComponent(rootEntity); transform.scale_local.z = -transform.scale_local.z; transform.SetDirty(); } - // We parented everything to a root transform, but we actually don't need that after loading model. - // Apply every transformation according to root transform, then remove root all together. - // We could also keep it, but right now, it seems better to delete and have less hierarchy - state.scene.Update(0); - state.scene.Component_DetachChildren(rootEntity); - state.scene.Entity_Remove(rootEntity); - - wiRenderer::GetScene().Merge(state.scene); } diff --git a/Editor/ModelImporter_OBJ.cpp b/Editor/ModelImporter_OBJ.cpp index 66bcabe82..4c5a5e66f 100644 --- a/Editor/ModelImporter_OBJ.cpp +++ b/Editor/ModelImporter_OBJ.cpp @@ -15,14 +15,12 @@ using namespace wiECS; // Transform the data from OBJ space to engine-space: static const bool transform_to_LH = true; -void ImportModel_OBJ(const std::string& fileName) +void ImportModel_OBJ(const std::string& fileName, Scene& scene) { string directory, name; wiHelper::SplitPath(fileName, directory, name); wiHelper::RemoveExtensionFromFileName(name); - Scene scene; - tinyobj::attrib_t obj_attrib; vector obj_shapes; vector obj_materials; @@ -188,7 +186,6 @@ void ImportModel_OBJ(const std::string& fileName) mesh.CreateRenderData(); } - wiRenderer::GetScene().Merge(scene); } else { diff --git a/WickedEngine/ArchiveVersionHistory.txt b/WickedEngine/ArchiveVersionHistory.txt index 9cf06d3db..f243c88d0 100644 --- a/WickedEngine/ArchiveVersionHistory.txt +++ b/WickedEngine/ArchiveVersionHistory.txt @@ -1,5 +1,6 @@ This file contains changelog of wiArchive versions +27: removed ArmatureComponent::rootBoneID 26: removed ArmatureComponent::remapMatrix, added ArmatureComponent::rootBoneID 25: emissiveColor separated from baseColor 24: emissive map moved to separate texture (non-grayscale) diff --git a/WickedEngine/wiArchive.cpp b/WickedEngine/wiArchive.cpp index 64a965296..8cd6f8746 100644 --- a/WickedEngine/wiArchive.cpp +++ b/WickedEngine/wiArchive.cpp @@ -7,7 +7,7 @@ using namespace std; // this should always be only INCREMENTED and only if a new serialization is implemeted somewhere! -uint64_t __archiveVersion = 26; +uint64_t __archiveVersion = 27; // this is the version number of which below the archive is not compatible with the current version uint64_t __archiveVersionBarrier = 22; diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp index 257c12c7d..ff0e03c79 100644 --- a/WickedEngine/wiSceneSystem.cpp +++ b/WickedEngine/wiSceneSystem.cpp @@ -937,7 +937,7 @@ namespace wiSceneSystem RunHierarchyUpdateSystem(hierarchy, transforms, layers); - RunArmatureUpdateSystem(hierarchy, transforms, armatures); + RunArmatureUpdateSystem(transforms, armatures); RunMaterialUpdateSystem(materials, dt); @@ -1574,7 +1574,6 @@ namespace wiSceneSystem } } void RunArmatureUpdateSystem( - const ComponentManager& hierarchy, const ComponentManager& transforms, ComponentManager& armatures ) @@ -1582,29 +1581,26 @@ namespace wiSceneSystem wiJobSystem::Dispatch((uint32_t)armatures.GetCount(), 1, [&](wiJobDispatchArgs args) { ArmatureComponent& armature = armatures[args.jobIndex]; + Entity entity = armatures.GetEntity(args.jobIndex); + const TransformComponent& transform = *transforms.GetComponent(entity); + + // The transform world matrices are in world space, but skinning needs them in armature-local space, + // so that the skin is reusable for instanced meshes. + // We remove the armature's world matrix from the bone world matrix to obtain the bone local transform + // These local bone matrices will only be used for skinning, the actual transform components for the bones + // remain unchanged. + // + // This is useful for an other thing too: + // If a whole transform tree is transformed by some parent (even gltf import does that to convert from RH to LH space) + // then the inverseBindMatrices are not reflected in that because they are not contained in the hierarchy system. + // But this will correct them too. + XMMATRIX R = XMMatrixInverse(nullptr, XMLoadFloat4x4(&transform.world)); if (armature.boneData.size() != armature.boneCollection.size()) { armature.boneData.resize(armature.boneCollection.size()); } - // The transform world matrices are in global space, but skinning needs them in armature-local space, - // so that the skin is reusable for instanced meshes. - // The bones can be in NOT armature-local space if the root bone is parented to something, - // so we look into the hierarchy to find out if the root bone has a parent or not. - // If it has, we will premultiply all skinning bone matrices with the inverse of it to transform them - // back into armature-local space. - XMMATRIX R = XMMatrixIdentity(); - if (armature.rootBoneID != INVALID_ENTITY) - { - const HierarchyComponent* parent = hierarchy.GetComponent(armature.rootBoneID); - if (parent != nullptr) - { - const TransformComponent* transform = transforms.GetComponent(parent->parentID); - R = R * XMMatrixInverse(nullptr, XMLoadFloat4x4(&transform->world)); - } - } - int boneIndex = 0; for (Entity boneEntity : armature.boneCollection) { diff --git a/WickedEngine/wiSceneSystem.h b/WickedEngine/wiSceneSystem.h index eb8f9f91b..9df8d29cc 100644 --- a/WickedEngine/wiSceneSystem.h +++ b/WickedEngine/wiSceneSystem.h @@ -559,7 +559,6 @@ namespace wiSceneSystem std::vector boneCollection; std::vector inverseBindMatrices; - wiECS::Entity rootBoneID = wiECS::INVALID_ENTITY; // Non-serialized attributes: @@ -1039,7 +1038,6 @@ namespace wiSceneSystem wiECS::ComponentManager& layers ); void RunArmatureUpdateSystem( - const wiECS::ComponentManager& hierarchy, const wiECS::ComponentManager& transforms, wiECS::ComponentManager& armatures ); diff --git a/WickedEngine/wiSceneSystem_Serializers.cpp b/WickedEngine/wiSceneSystem_Serializers.cpp index 6cae1a333..499368db2 100644 --- a/WickedEngine/wiSceneSystem_Serializers.cpp +++ b/WickedEngine/wiSceneSystem_Serializers.cpp @@ -379,8 +379,9 @@ namespace wiSceneSystem XMFLOAT4X4 remapMatrix; archive >> remapMatrix; // no longer used } - if (archive.GetVersion() >= 26) + if (archive.GetVersion() == 26) { + Entity rootBoneID; SerializeEntity(archive, rootBoneID, seed); } } @@ -396,8 +397,9 @@ namespace wiSceneSystem } archive << inverseBindMatrices; - if (archive.GetVersion() >= 26) + if (archive.GetVersion() == 26) { + Entity rootBoneID; SerializeEntity(archive, rootBoneID, seed); } } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 1f6ad7adc..a7dbdb443 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 25; // minor bug fixes, alterations, refactors, updates - const int revision = 5; + const int revision = 6; long GetVersion()