another gltf armature import fix
This commit is contained in:
+16
-14
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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,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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user