diff --git a/src/renderer/editor/fbx_importer.cpp b/src/renderer/editor/fbx_importer.cpp index efdbe35fde..59d7ae19df 100644 --- a/src/renderer/editor/fbx_importer.cpp +++ b/src/renderer/editor/fbx_importer.cpp @@ -25,6 +25,7 @@ #include "physics/physics_system.h" #include "renderer/draw_stream.h" #include "renderer/editor/model_importer.h" +#include "renderer/editor/model_meta.h" #include "renderer/material.h" #include "renderer/model.h" #include "renderer/pipeline.h" @@ -547,7 +548,8 @@ struct FBXImporter : ModelImporter { const ofbx::Object* node = (const ofbx::Object*)bone.id; const ImportMesh* mesh = getAnyMeshFromBone(node, i32(&bone - m_bones.begin())); Matrix tr = toLumix(getBindPoseMatrix(mesh, node)); - tr.normalizeScale(); + tr.normalizeScale(); // TODO why? + tr.setTranslation(tr.getTranslation() * m_scene_scale); bone.bind_pose_matrix = fixOrientation(tr); bone.name = node->name; } @@ -696,7 +698,7 @@ struct FBXImporter : ModelImporter { u32 tri_count = ofbx::triangulate(geom, polygon, tri_indices.begin()); for (u32 i = 0; i < tri_count; ++i) { ofbx::Vec3 cp = positions.get(tri_indices[i]); - Vec3 pos = matrix.transformPoint(toLumixVec3(cp)) * meta.scene_scale * m_scene_scale; + Vec3 pos = matrix.transformPoint(toLumixVec3(cp)) * m_scene_scale; pos = fixOrientation(pos); write(pos); @@ -955,14 +957,18 @@ struct FBXImporter : ModelImporter { for (const Bone& bone : m_bones) { const Bone* parent = getParent(bone); - if (!parent) continue; - - // parent_scale - animated scale is not supported, but we can get rid of static scale if we ignore - // it in writeSkeleton() and use `parent_scale` in this function - const ofbx::Object* fbx_parent = (const ofbx::Object*)(parent->id); - const float parent_scale = (float)getScaleX(fbx_parent->getGlobalTransform()); + float scale = m_scene_scale; + if (parent) { + // parent_scale - animated scale is not supported, but we can get rid of static scale if we ignore + // it in writeSkeleton() and use `parent_scale` in this function + const ofbx::Object* fbx_parent = (const ofbx::Object*)(parent->id); + const float parent_scale = (float)getScaleX(fbx_parent->getGlobalTransform()); + scale *= parent_scale; + } + if (fabsf(scale - 1) < 1e-5f) continue; + Array& keys = tracks[u32(&bone - m_bones.begin())]; - for (Key& k : keys) k.pos *= parent_scale; + for (Key& k : keys) k.pos *= scale; } if (m_orientation != Orientation::Y_UP) { @@ -1243,7 +1249,15 @@ struct FBXImporter : ModelImporter { }); } - bool parse(const Path& filename, const ModelMeta* meta) override { + bool parse(const Path& filename, const ModelMeta& meta) override { + return parseInternal(filename, &meta); + } + + bool parseSimple(const Path& filename) override { + return parseInternal(filename, nullptr); + } + + bool parseInternal(const Path& filename, const ModelMeta* meta) { PROFILE_FUNCTION(); const bool ignore_geometry = meta == nullptr; @@ -1267,6 +1281,7 @@ struct FBXImporter : ModelImporter { return false; } m_scene_scale = m_scene->getGlobalSettings()->UnitScaleFactor * 0.01f; + if (meta) m_scene_scale *= meta->scene_scale; const ofbx::GlobalSettings* settings = m_scene->getGlobalSettings(); switch (settings->UpAxis) { @@ -1279,7 +1294,7 @@ struct FBXImporter : ModelImporter { if (!ignore_geometry) extractEmbedded(*m_scene, src_dir, m_allocator); gatherMeshes(filename, src_dir); - gatherAnimations(filename); + if(!meta || !meta->ignore_animations) gatherAnimations(filename); if (meta) gatherLights(*meta); if (!ignore_geometry) { @@ -1303,6 +1318,7 @@ struct FBXImporter : ModelImporter { Array m_fbx_meshes; ofbx::IScene* m_scene; Orientation m_orientation = Orientation::Y_UP; + float m_scene_scale = 1.f; }; ModelImporter* createFBXImporter(StudioApp& app, IAllocator& allocator) { diff --git a/src/renderer/editor/model_importer.cpp b/src/renderer/editor/model_importer.cpp index 66f4eb5963..319409dfe8 100644 --- a/src/renderer/editor/model_importer.cpp +++ b/src/renderer/editor/model_importer.cpp @@ -14,6 +14,7 @@ #include "physics/physics_module.h" #include "physics/physics_resources.h" #include "physics/physics_system.h" +#include "renderer/editor/model_meta.h" #include "renderer/material.h" #include "renderer/model.h" #include "renderer/pipeline.h" @@ -584,15 +585,15 @@ bool ModelImporter::write(const Path& src, const ModelMeta& meta) { const Path filepath = Path(ResourcePath::getResource(src)); any_written = writeModel(src, meta) || any_written; any_written = writeMaterials(filepath, meta, false) || any_written; - if (!meta.ignore_animations) any_written = writeAnimations(filepath, meta) || any_written; + any_written = writeAnimations(filepath, meta) || any_written; if (meta.split) { centerMeshes(); any_written = writeSubmodels(filepath, meta) || any_written; } - any_written = writePhysics(filepath, meta, meta.split) || any_written; + any_written = writePhysics(filepath, meta) || any_written; if (meta.split || meta.create_prefab_with_physics) { jobs::moveJobToWorker(0); - any_written = writePrefab(filepath, meta, meta.split) || any_written; + any_written = writePrefab(filepath, meta) || any_written; jobs::yield(); } return any_written; @@ -762,7 +763,7 @@ void ModelImporter::writeGeometry(int mesh_idx) { write(import_mesh.aabb); } -bool ModelImporter::writePrefab(const Path& src, const ModelMeta& meta, bool split_meshes) { +bool ModelImporter::writePrefab(const Path& src, const ModelMeta& meta) { Engine& engine = m_app.getEngine(); World& world = engine.createWorld(); @@ -783,7 +784,7 @@ bool ModelImporter::writePrefab(const Path& src, const ModelMeta& meta, bool spl PhysicsModule* pmodule = (PhysicsModule*)world.getModule(RIGID_ACTOR_TYPE); const EntityRef root = world.createEntity({0, 0, 0}, Quat::IDENTITY); - if (!split_meshes) { + if (!meta.split) { world.createComponent(MODEL_INSTANCE_TYPE, root); rmodule->setModelInstancePath(root, src); @@ -933,7 +934,7 @@ void ModelImporter::writeGeometry(const ModelMeta& meta) { if (m_meshes.empty()) { for (const Bone& bone : m_bones) { // TODO check if this works with different values of m_orientation - const Vec3 p = bone.bind_pose_matrix.getTranslation() * meta.scene_scale * m_scene_scale; + const Vec3 p = bone.bind_pose_matrix.getTranslation(); origin_radius_squared = maximum(origin_radius_squared, squaredLength(p)); aabb.addPoint(p); } @@ -1030,23 +1031,25 @@ void ModelImporter::writeMeshes(const Path& src, int mesh_idx, const ModelMeta& void ModelImporter::writeSkeleton(const ModelMeta& meta) { write(m_bones.size()); - u32 idx = 0; - for (const Bone& node : m_bones) { + for (i32 idx = 0, num = m_bones.size(); idx < num; ++idx) { + const Bone& node = m_bones[idx]; const char* name = node.name.c_str(); - int len = (int)stringLength(name); + const i32 len = stringLength(name); write(len); writeString(name); const i32 parent_index = getParentIndex(m_bones, node); + // m_bones must have parents before children + // i.e. importers must sort them that way + ASSERT(parent_index < idx); write(parent_index); const Matrix& tr = node.bind_pose_matrix; const Quat q = tr.getRotation(); - const Vec3 t = tr.getTranslation() * meta.scene_scale * m_scene_scale; + const Vec3 t = tr.getTranslation(); write(t); write(q); - ++idx; } } @@ -1150,7 +1153,7 @@ void ModelImporter::writeModelHeader() write(header); } -bool ModelImporter::writePhysics(const Path& src, const ModelMeta& meta, bool split_meshes) { +bool ModelImporter::writePhysics(const Path& src, const ModelMeta& meta) { if (m_meshes.empty()) return false; if (meta.physics == ModelMeta::Physics::NONE) return false; @@ -1167,7 +1170,7 @@ bool ModelImporter::writePhysics(const Path& src, const ModelMeta& meta, bool sp const bool to_convex = meta.physics == ModelMeta::Physics::CONVEX; header.m_convex = (u32)to_convex; - if (split_meshes) { + if (meta.split) { for (const ImportMesh& mesh : m_meshes) { m_out_file.clear(); m_out_file.write(&header, sizeof(header)); @@ -1328,7 +1331,7 @@ bool ModelImporter::writeAnimations(const Path& src, const ModelMeta& meta) { Vec3 min(FLT_MAX), max(-FLT_MAX); for (const Key& k : keys) { - const Vec3 p = k.pos * meta.scene_scale * m_scene_scale; + const Vec3 p = k.pos; min = minimum(p, min); max = maximum(p, max); } @@ -1342,7 +1345,7 @@ bool ModelImporter::writeAnimations(const Path& src, const ModelMeta& meta) { if (bitsize == 0) { translation_tracks[bone_idx].is_const = true; write(Animation::TrackType::CONSTANT); - write(keys[0].pos * meta.scene_scale * m_scene_scale); + write(keys[0].pos); } else { translation_tracks[bone_idx].is_const = false; @@ -1355,7 +1358,7 @@ bool ModelImporter::writeAnimations(const Path& src, const ModelMeta& meta) { write(bitsizes); write(offset_bits); offset_bits += bitsize; - + memcpy(translation_tracks[bone_idx].bitsizes, bitsizes, sizeof(bitsizes)); translation_tracks[bone_idx].max = max; translation_tracks[bone_idx].min = min; @@ -1374,7 +1377,7 @@ bool ModelImporter::writeAnimations(const Path& src, const ModelMeta& meta) { if (!keys.empty() && !track.is_const) { const Key& k = keys[i]; - Vec3 p = k.pos * meta.scene_scale * m_scene_scale; + Vec3 p = k.pos; const u64 packed = pack(p, track); const u32 bitsize = (track.bitsizes[0] + track.bitsizes[1] + track.bitsizes[2]); ASSERT(bitsize <= 64); diff --git a/src/renderer/editor/model_importer.h b/src/renderer/editor/model_importer.h index 6b288187ae..092c0a0cbe 100644 --- a/src/renderer/editor/model_importer.h +++ b/src/renderer/editor/model_importer.h @@ -4,25 +4,13 @@ #include "core/geometry.h" #include "core/math.h" #include "core/path.h" -#include "core/span.h" #include "core/stream.h" -#include "engine/lumix.h" #include "renderer/gpu/gpu.h" -#include "renderer/editor/model_meta.h" namespace Lumix { -struct ImpostorTexturesContext { - virtual ~ImpostorTexturesContext() {} - virtual void readCallback0(Span data) = 0; - virtual void readCallback1(Span data) = 0; - virtual void readCallback2(Span data) = 0; - virtual void readCallback3(Span data) = 0; - virtual void start() = 0; - - IVec2 tile_size; - Path path; -}; +struct ImpostorTexturesContext; +struct ModelMeta; enum class AttributeSemantic : u8; @@ -79,9 +67,9 @@ struct ModelImporter { u32 mesh_index = 0xFFffFFff; u32 material_index = 0xffFFffFF; bool is_skinned = false; - int bone_idx = -1; + i32 bone_idx = -1; u32 lod = 0; - int submesh = -1; + i32 submesh = -1; OutputMemoryStream vertex_buffer; u32 vertex_size = 0xffFFffFF; Array attributes; @@ -107,7 +95,14 @@ struct ModelImporter { void init(); // TODO get rid of this? - virtual bool parse(const Path& filename, const ModelMeta* meta) = 0; + // simple parsing - you can get only the list of objects (mesh, materials, animations, etc.), + // but not their content (geometry, embedded textures, etc.) + // calling write(...) after this is invalid + // used for to get a list of subresources (addSubresources) and to reimport materials + virtual bool parseSimple(const Path& filename) = 0; + + // full parsing - parse all data, including geometry + virtual bool parse(const Path& filename, const ModelMeta& meta) = 0; // meta must be the same as in parse // TODO fix this (remove meta from these functions?) @@ -142,13 +137,13 @@ struct ModelImporter { void writeGeometry(const ModelMeta& meta); void writeGeometry(int mesh_idx); void writeSkeleton(const ModelMeta& meta); - bool writePrefab(const Path& src, const ModelMeta& meta, bool split_meshes); + bool writePrefab(const Path& src, const ModelMeta& meta); bool findTexture(StringView src_dir, StringView ext, ImportTexture& tex) const; void bakeVertexAO(float min_ao); bool writeSubmodels(const Path& src, const ModelMeta& meta); bool writeModel(const Path& src, const ModelMeta& meta); bool writeAnimations(const Path& src, const ModelMeta& meta); - bool writePhysics(const Path& src, const ModelMeta& meta, bool split_meshes); + bool writePhysics(const Path& src, const ModelMeta& meta); void centerMeshes(); // compute AO, auto LODs, etc. @@ -166,7 +161,18 @@ struct ModelImporter { Array m_meshes; Array m_animations; Array m_lights; - float m_scene_scale = 1.f; +}; + +struct ImpostorTexturesContext { + virtual ~ImpostorTexturesContext() {} + virtual void readCallback0(Span data) = 0; + virtual void readCallback1(Span data) = 0; + virtual void readCallback2(Span data) = 0; + virtual void readCallback3(Span data) = 0; + virtual void start() = 0; + + IVec2 tile_size; + Path path; }; } // namespace Lumix \ No newline at end of file diff --git a/src/renderer/editor/model_meta.h b/src/renderer/editor/model_meta.h index 185d39ad30..bee4229a9b 100644 --- a/src/renderer/editor/model_meta.h +++ b/src/renderer/editor/model_meta.h @@ -4,7 +4,6 @@ #include "core/stream.h" #include "core/string.h" #include "core/tokenizer.h" -#include "fbx_importer.h" namespace Lumix { diff --git a/src/renderer/editor/render_plugins.cpp b/src/renderer/editor/render_plugins.cpp index 723b73db07..78b1b1f50a 100644 --- a/src/renderer/editor/render_plugins.cpp +++ b/src/renderer/editor/render_plugins.cpp @@ -2190,7 +2190,7 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin { if (ImGui::Button("Reimport materials")) { ModelImporter* fbx_importer = createFBXImporter(m_app, m_app.getAllocator()); - if (fbx_importer->parse(m_resource->getPath(), nullptr)) { + if (fbx_importer->parseSimple(m_resource->getPath())) { if (!fbx_importer->writeMaterials(m_resource->getPath(), m_meta, true)) { logError("Failed to write materials for ", m_resource->getPath()); } @@ -2574,7 +2574,7 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin { const char* path = _path.c_str(); if (path[0] == '/') ++path; // TODO why is this here? - if (!importer->parse(Path(path), nullptr)) { + if (!importer->parseSimple(Path(path))) { logError("Failed to parse ", path); destroyFBXImporter(*importer); return; @@ -2624,7 +2624,7 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin { meta.load(Path(filepath), m_app); ModelImporter* importer = createFBXImporter(m_app, m_app.getAllocator()); - bool result = importer->parse(filepath, &meta); + bool result = importer->parse(filepath, meta); result = result && importer->write(src, meta); destroyFBXImporter(*importer);