1
Fork 0
mirror of https://github.com/redstrate/Novus.git synced 2025-04-24 13:07:44 +00:00

Export gltf instead of fbx

This commit is contained in:
Joshua Goins 2023-09-23 14:08:41 -04:00
parent b96b2a86c2
commit 9663164e76
9 changed files with 45046 additions and 108 deletions

View file

@ -22,4 +22,5 @@ corrosion_import_crate(MANIFEST_PATH ${libphysis_SOURCE_DIR}/Cargo.toml)
target_include_directories(physis INTERFACE ${libphysis_SOURCE_DIR}/target/public) target_include_directories(physis INTERFACE ${libphysis_SOURCE_DIR}/target/public)
target_link_libraries(physis INTERFACE unshield) target_link_libraries(physis INTERFACE unshield)
add_subdirectory(magic_enum) add_subdirectory(magic_enum)
add_subdirectory(tinygltf)

3
extern/tinygltf/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,3 @@
add_library(tinygltf STATIC)
target_sources(tinygltf PRIVATE src/tiny_gltf.cc)
target_include_directories(tinygltf PUBLIC include)

26753
extern/tinygltf/include/json.hpp vendored Normal file

File diff suppressed because it is too large Load diff

8007
extern/tinygltf/include/stb_image.h vendored Normal file

File diff suppressed because it is too large Load diff

1724
extern/tinygltf/include/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load diff

8416
extern/tinygltf/include/tiny_gltf.h vendored Normal file

File diff suppressed because it is too large Load diff

4
extern/tinygltf/src/tiny_gltf.cc vendored Normal file
View file

@ -0,0 +1,4 @@
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "tiny_gltf.h"

View file

@ -1,9 +1,6 @@
# SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com> # SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
find_package(assimp REQUIRED)
set_target_properties(assimp::assimp PROPERTIES MAP_IMPORTED_CONFIG_DEBUG Release)
add_library(mdlpart STATIC mdlpart.cpp) add_library(mdlpart STATIC mdlpart.cpp)
target_link_libraries(mdlpart PUBLIC physis z ${LIBRARIES} Qt5::Core Qt5::Widgets renderer NovusCommon assimp::assimp) target_link_libraries(mdlpart PUBLIC physis z ${LIBRARIES} Qt5::Core Qt5::Widgets renderer NovusCommon tinygltf)
target_include_directories(mdlpart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(mdlpart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View file

@ -12,15 +12,12 @@
#include <QVulkanInstance> #include <QVulkanInstance>
#include <QVulkanWindow> #include <QVulkanWindow>
#include <QWindow> #include <QWindow>
#include <assimp/Exporter.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <fmt/core.h> #include <fmt/core.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include <glm/gtc/type_ptr.inl> #include <glm/gtc/type_ptr.inl>
#include "filecache.h" #include "filecache.h"
#include "tiny_gltf.h"
#ifndef USE_STANDALONE_WINDOW #ifndef USE_STANDALONE_WINDOW
class VulkanWindow : public QWindow { class VulkanWindow : public QWindow {
@ -181,148 +178,184 @@ MDLPart::MDLPart(GameData* data, FileCache& cache) : data(data), cache(cache) {
} }
void MDLPart::exportModel(const QString& fileName) { void MDLPart::exportModel(const QString& fileName) {
Assimp::Exporter exporter; const int selectedModel = 0;
const int selectedLod = 0;
aiScene scene; const physis_MDL& model = models[selectedModel].model;
scene.mRootNode = new aiNode(); const physis_LOD& lod = model.lods[selectedLod];
// TODO: hardcoded to the first model for now tinygltf::Model gltfModel;
scene.mRootNode->mNumChildren = models[0].model.lods[0].num_parts + 1; // plus one for the skeleton gltfModel.asset.generator = "Novus";
scene.mRootNode->mChildren = new aiNode*[scene.mRootNode->mNumChildren];
scene.mNumMeshes = models[0].model.lods[0].num_parts; auto& gltfSkeletonNode = gltfModel.nodes.emplace_back();
scene.mMeshes = new aiMesh*[scene.mNumMeshes]; gltfSkeletonNode.name = skeleton->root_bone->name;
auto skeleton_node = new aiNode(); for (int i = 0; i < model.num_affected_bones; i++) {
skeleton_node->mName = "Skeleton"; auto& node = gltfModel.nodes.emplace_back();
skeleton_node->mNumChildren = 1; node.name = model.affected_bone_names[i];
skeleton_node->mChildren = new aiNode*[skeleton_node->mNumChildren];
scene.mRootNode->mChildren[scene.mRootNode->mNumChildren - 1] = skeleton_node;
std::vector<aiNode*> skeletonNodes;
for (int i = 0; i < models[0].model.num_affected_bones; i++) {
auto& node = skeletonNodes.emplace_back();
node = new aiNode();
node->mName = models[0].model.affected_bone_names[i];
int real_bone_id = 0; int real_bone_id = 0;
for (int k = 0; k < skeleton->num_bones; k++) { for (int k = 0; k < skeleton->num_bones; k++) {
if (strcmp(skeleton->bones[k].name, models[0].model.affected_bone_names[i]) == 0) { if (strcmp(skeleton->bones[k].name, model.affected_bone_names[i]) == 0) {
real_bone_id = k; real_bone_id = k;
} }
} }
node->mChildren = new aiNode*[models[0].model.num_affected_bones];
auto& real_bone = skeleton->bones[real_bone_id]; auto& real_bone = skeleton->bones[real_bone_id];
memcpy(&node->mTransformation, glm::value_ptr(boneData[real_bone.index].finalTransform), sizeof(aiMatrix4x4)); node.translation = {real_bone.position[0], real_bone.position[1], real_bone.position[2]};
node.rotation = {real_bone.rotation[0], real_bone.rotation[1], real_bone.rotation[2], real_bone.rotation[3]};
node.scale = {real_bone.scale[0], real_bone.scale[1], real_bone.scale[2]};
} }
// setup parenting // setup parenting
for (int i = 0; i < models[0].model.num_affected_bones; i++) { for (int i = 0; i < model.num_affected_bones; i++) {
int real_bone_id = 0; int real_bone_id = 0;
for (int k = 0; k < skeleton->num_bones; k++) { for (int k = 0; k < skeleton->num_bones; k++) {
if (strcmp(skeleton->bones[k].name, models[0].model.affected_bone_names[i]) == 0) { if (strcmp(skeleton->bones[k].name, model.affected_bone_names[i]) == 0) {
real_bone_id = k; real_bone_id = k;
} }
} }
auto& real_bone = skeleton->bones[real_bone_id]; auto& real_bone = skeleton->bones[real_bone_id];
if (real_bone.parent_bone != nullptr) { if (real_bone.parent_bone != nullptr) {
for (int k = 0; k < models[0].model.num_affected_bones; k++) { for (int k = 0; k < model.num_affected_bones; k++) {
if (strcmp(models[0].model.affected_bone_names[k], real_bone.parent_bone->name) == 0) { if (strcmp(model.affected_bone_names[k], real_bone.parent_bone->name) == 0) {
skeletonNodes[i]->mParent = skeletonNodes[k]; gltfModel.nodes[k + 1].children.push_back(i + 1); // +1 for the skeleton node taking up the first index
skeletonNodes[k]->mChildren[skeletonNodes[k]->mNumChildren++] = skeletonNodes[i];
} }
} }
} else {
gltfSkeletonNode.children.push_back(i + 1);
} }
} }
skeleton_node->mChildren[0] = new aiNode(); auto& gltfSkin = gltfModel.skins.emplace_back();
skeleton_node->mChildren[0]->mName = "root"; gltfSkin.name = gltfSkeletonNode.name;
skeleton_node->mChildren[0]->mChildren = new aiNode*[models[0].model.num_affected_bones]; for (int i = 1; i < gltfModel.nodes.size(); i++) {
gltfSkin.joints.push_back(i);
for (int i = 0; i < skeletonNodes.size(); i++) {
if (skeletonNodes[i]->mParent == nullptr) {
skeleton_node->mChildren[0]->mChildren[skeleton_node->mChildren[0]->mNumChildren++] = skeletonNodes[i];
}
} }
for (int i = 0; i < models[0].model.lods[0].num_parts; i++) { // Inverse bind matrices
scene.mMeshes[i] = new aiMesh(); {
scene.mMeshes[i]->mMaterialIndex = 0; gltfSkin.inverseBindMatrices = gltfModel.accessors.size();
auto& node = scene.mRootNode->mChildren[i]; auto& inverseAccessor = gltfModel.accessors.emplace_back();
node = new aiNode(); inverseAccessor.bufferView = gltfModel.bufferViews.size();
node->mNumMeshes = 1; inverseAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
node->mMeshes = new unsigned int[scene.mRootNode->mNumMeshes]; inverseAccessor.count = model.num_affected_bones;
node->mMeshes[0] = i; inverseAccessor.type = TINYGLTF_TYPE_MAT4;
auto mesh = scene.mMeshes[i]; auto& inverseBufferView = gltfModel.bufferViews.emplace_back();
mesh->mNumVertices = models[0].model.lods[0].parts[i].num_vertices; inverseBufferView.buffer = gltfModel.buffers.size();
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
mesh->mNormals = new aiVector3D[mesh->mNumVertices];
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
mesh->mNumUVComponents[0] = 2;
for (int j = 0; j < mesh->mNumVertices; j++) { auto& inverseBuffer = gltfModel.buffers.emplace_back();
auto vertex = models[0].model.lods[0].parts[i].vertices[j]; for (int i = 0; i < model.num_affected_bones; i++) {
mesh->mVertices[j] = aiVector3D(vertex.position[0], vertex.position[1], vertex.position[2]); int real_bone_id = 0;
mesh->mNormals[j] = aiVector3D(vertex.normal[0], vertex.normal[1], vertex.normal[2]); for (int k = 0; k < skeleton->num_bones; k++) {
mesh->mTextureCoords[0][j] = aiVector3D(vertex.uv[0], vertex.uv[1], 0.0f); if (strcmp(skeleton->bones[k].name, model.affected_bone_names[i]) == 0) {
} real_bone_id = k;
mesh->mNumBones = models[0].model.num_affected_bones;
mesh->mBones = new aiBone*[mesh->mNumBones];
for (int j = 0; j < mesh->mNumBones; j++) {
int real_bone_id = j;
// TODO: is this still relevant?5
/*for(int k = 0; k < skeleton.bones.size(); k++) {
if(skeleton.bones[k].name == model.affectedBoneNames[j]) {
real_bone_id = k;
}
}*/
mesh->mBones[j] = new aiBone();
mesh->mBones[j]->mName = models[0].model.affected_bone_names[j];
mesh->mBones[j]->mNumWeights = mesh->mNumVertices * 4;
mesh->mBones[j]->mWeights = new aiVertexWeight[mesh->mBones[j]->mNumWeights];
// mesh->mBones[j]->mNode = skeleton_node->mChildren[j];
for (int k = 0; k < mesh->mNumVertices; k++) {
for (int z = 0; z < 4; z++) {
if (models[0].model.lods[0].parts[i].vertices[k].bone_id[z] == real_bone_id) {
auto& weight = mesh->mBones[j]->mWeights[k * 4 + z];
weight.mVertexId = k;
weight.mWeight = models[0].model.lods[0].parts[i].vertices[k].bone_weight[z];
}
} }
} }
auto& real_bone = skeleton->bones[real_bone_id];
auto inverseMatrix = boneData[real_bone.index].inversePose;
auto inverseMatrixCPtr = reinterpret_cast<uint8_t*>(glm::value_ptr(inverseMatrix));
inverseBuffer.data.insert(inverseBuffer.data.end(), inverseMatrixCPtr, inverseMatrixCPtr + sizeof(float) * 16);
} }
mesh->mNumFaces = models[0].model.lods[0].parts[i].num_indices / 3; inverseBufferView.byteLength = inverseBuffer.data.size();
mesh->mFaces = new aiFace[mesh->mNumFaces]; }
int lastFace = 0; for (int i = 0; i < lod.num_parts; i++) {
for (int j = 0; j < models[0].model.lods[0].parts[i].num_indices; j += 3) { auto& gltfNode = gltfModel.nodes.emplace_back();;
aiFace& face = mesh->mFaces[lastFace++]; gltfNode.name = "placeholder Part 0.1";
gltfNode.skin = 0;
face.mNumIndices = 3; gltfNode.mesh = gltfModel.meshes.size();
face.mIndices = new unsigned int[face.mNumIndices]; auto& gltfMesh = gltfModel.meshes.emplace_back();
face.mIndices[0] = models[0].model.lods[0].parts[i].indices[j]; gltfMesh.name = "what?";
face.mIndices[1] = models[0].model.lods[0].parts[i].indices[j + 1];
face.mIndices[2] = models[0].model.lods[0].parts[i].indices[j + 2]; auto& gltfPrimitive = gltfMesh.primitives.emplace_back();
gltfPrimitive.attributes["POSITION"] = gltfModel.accessors.size();
gltfPrimitive.attributes["TEXCOORD_0"] = gltfModel.accessors.size() + 1;
gltfPrimitive.attributes["NORMAL"] = gltfModel.accessors.size() + 2;
gltfPrimitive.attributes["WEIGHTS_0"] = gltfModel.accessors.size() + 3;
gltfPrimitive.attributes["JOINTS_0"] = gltfModel.accessors.size() + 4;
gltfPrimitive.mode = TINYGLTF_MODE_TRIANGLES;
// Vertices
{
auto& positionAccessor = gltfModel.accessors.emplace_back();
positionAccessor.bufferView = gltfModel.bufferViews.size();
positionAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
positionAccessor.count = lod.parts[i].num_vertices;
positionAccessor.type = TINYGLTF_TYPE_VEC3;
auto& uvAccessor = gltfModel.accessors.emplace_back();
uvAccessor.bufferView = gltfModel.bufferViews.size();
uvAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
uvAccessor.count = lod.parts[i].num_vertices;
uvAccessor.type = TINYGLTF_TYPE_VEC2;
uvAccessor.byteOffset = offsetof(Vertex, uv);
auto& normalAccessor = gltfModel.accessors.emplace_back();
normalAccessor.bufferView = gltfModel.bufferViews.size();
normalAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
normalAccessor.count = lod.parts[i].num_vertices;
normalAccessor.type = TINYGLTF_TYPE_VEC3;
normalAccessor.byteOffset = offsetof(Vertex, normal);
auto& boneWeightAccessor = gltfModel.accessors.emplace_back();
boneWeightAccessor.bufferView = gltfModel.bufferViews.size();
boneWeightAccessor.componentType = TINYGLTF_COMPONENT_TYPE_FLOAT;
boneWeightAccessor.count = lod.parts[i].num_vertices;
boneWeightAccessor.type = TINYGLTF_TYPE_VEC4;
boneWeightAccessor.byteOffset = offsetof(Vertex, bone_weight);
auto& boneIdAccessor = gltfModel.accessors.emplace_back();
boneIdAccessor.bufferView = gltfModel.bufferViews.size();
boneIdAccessor.componentType = TINYGLTF_COMPONENT_TYPE_BYTE;
boneIdAccessor.count = lod.parts[i].num_vertices;
boneIdAccessor.type = TINYGLTF_TYPE_VEC4;
boneIdAccessor.byteOffset = offsetof(Vertex, bone_id);
auto& vertexBufferView = gltfModel.bufferViews.emplace_back();
vertexBufferView.buffer = gltfModel.buffers.size();
vertexBufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER;
auto& vertexBuffer = gltfModel.buffers.emplace_back();
vertexBuffer.data.resize(lod.parts[i].num_vertices * sizeof(Vertex));
memcpy(vertexBuffer.data.data(), lod.parts[i].vertices, vertexBuffer.data.size());
vertexBufferView.byteLength = vertexBuffer.data.size();
vertexBufferView.byteStride = sizeof(Vertex);
}
// Indices
{
gltfPrimitive.indices = gltfModel.accessors.size();
auto& indexAccessor = gltfModel.accessors.emplace_back();
indexAccessor.bufferView = gltfModel.bufferViews.size();
indexAccessor.componentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
indexAccessor.count = lod.parts[i].num_indices;
indexAccessor.type = TINYGLTF_TYPE_SCALAR;
auto& indexBufferView = gltfModel.bufferViews.emplace_back();
indexBufferView.buffer = gltfModel.buffers.size();
indexBufferView.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
auto& indexBuffer = gltfModel.buffers.emplace_back();
indexBuffer.data.resize(lod.parts[i].num_indices * sizeof(uint16_t));
memcpy(indexBuffer.data.data(), lod.parts[i].indices, indexBuffer.data.size());
indexBufferView.byteLength = indexBuffer.data.size();
indexBufferView.byteStride = sizeof(uint16_t);
} }
} }
scene.mNumMaterials = 1; tinygltf::TinyGLTF loader;
scene.mMaterials = new aiMaterial*[1]; loader.WriteGltfSceneToFile(&gltfModel, fileName.toStdString(), true, true, false, true);
scene.mMaterials[0] = new aiMaterial();
exporter.Export(&scene, "fbx", fileName.toStdString());
} }
void MDLPart::clear() { void MDLPart::clear() {