another gltf armature import fix

This commit is contained in:
turanszkij
2019-03-14 19:05:37 +00:00
parent 73f573a06a
commit 4163f09a76
10 changed files with 84 additions and 94 deletions
+16 -14
View File
@@ -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;
+4 -2
View File
@@ -1,6 +1,8 @@
#pragma once
#include <string>
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);
+41 -49
View File
@@ -157,7 +157,7 @@ void RegisterTexture2D(tinygltf::Image *image, const string& type_name)
struct LoaderState
{
tinygltf::Model gltfModel;
Scene scene;
Scene* scene;
unordered_map<int, Entity> 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);
}
+1 -4
View File
@@ -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<tinyobj::shape_t> obj_shapes;
vector<tinyobj::material_t> obj_materials;
@@ -188,7 +186,6 @@ void ImportModel_OBJ(const std::string& fileName)
mesh.CreateRenderData();
}
wiRenderer::GetScene().Merge(scene);
}
else
{
+1
View File
@@ -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)
+1 -1
View File
@@ -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;
+15 -19
View File
@@ -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<HierarchyComponent>& hierarchy,
const ComponentManager<TransformComponent>& transforms,
ComponentManager<ArmatureComponent>& 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)
{
-2
View File
@@ -559,7 +559,6 @@ namespace wiSceneSystem
std::vector<wiECS::Entity> boneCollection;
std::vector<XMFLOAT4X4> inverseBindMatrices;
wiECS::Entity rootBoneID = wiECS::INVALID_ENTITY;
// Non-serialized attributes:
@@ -1039,7 +1038,6 @@ namespace wiSceneSystem
wiECS::ComponentManager<LayerComponent>& layers
);
void RunArmatureUpdateSystem(
const wiECS::ComponentManager<HierarchyComponent>& hierarchy,
const wiECS::ComponentManager<TransformComponent>& transforms,
wiECS::ComponentManager<ArmatureComponent>& armatures
);
+4 -2
View File
@@ -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);
}
}
+1 -1
View File
@@ -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()