Basic FBX export (without attached textures)
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MeshWriter.hpp"
|
#include "MeshWriter.hpp"
|
||||||
|
#include "Base/Utils.hpp"
|
||||||
#include "IO/MemMappedFile.hpp"
|
#include "IO/MemMappedFile.hpp"
|
||||||
#include "Scene/Geometry.hpp"
|
#include "Scene/Geometry.hpp"
|
||||||
#include "Scene/Vertex.hpp"
|
#include "Scene/Vertex.hpp"
|
||||||
@@ -14,7 +15,13 @@
|
|||||||
#include "IO/Archive/ZipWriter.hpp"
|
#include "IO/Archive/ZipWriter.hpp"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/Exporter.hpp>
|
||||||
|
#include <assimp/mesh.h>
|
||||||
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
|
|
||||||
namespace OpenVulkano::Scene
|
namespace OpenVulkano::Scene
|
||||||
{
|
{
|
||||||
@@ -81,4 +88,145 @@ namespace OpenVulkano::Scene
|
|||||||
zipWriter.AddFile(texDesc, textureFile.Data());
|
zipWriter.AddFile(texDesc, textureFile.Data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MeshWriter::WriteAsFBX(Geometry* geometry, const std::string& texturePath, const std::string& fbxPath)
|
||||||
|
{
|
||||||
|
aiScene scene;
|
||||||
|
scene.mRootNode = new aiNode();
|
||||||
|
|
||||||
|
aiMesh* mesh = new aiMesh();
|
||||||
|
mesh->mNumVertices = geometry->vertexCount;
|
||||||
|
mesh->mVertices = new aiVector3D[geometry->vertexCount];
|
||||||
|
mesh->mNormals = new aiVector3D[geometry->vertexCount];
|
||||||
|
mesh->mTextureCoords[0] = new aiVector3D[geometry->vertexCount];
|
||||||
|
mesh->mMaterialIndex = 0;
|
||||||
|
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < geometry->vertexCount; ++i)
|
||||||
|
{
|
||||||
|
const Vertex& vertex = geometry->vertices[i];
|
||||||
|
mesh->mVertices[i] = aiVector3D(vertex.position.x, vertex.position.y, vertex.position.z);
|
||||||
|
mesh->mNormals[i] = aiVector3D(vertex.normal.x, vertex.normal.y, vertex.normal.z);
|
||||||
|
mesh->mTextureCoords[0][i] = aiVector3D(vertex.textureCoordinates.x, vertex.textureCoordinates.y, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh->mNumFaces = geometry->indexCount / 3;
|
||||||
|
mesh->mFaces = new aiFace[mesh->mNumFaces];
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < mesh->mNumFaces; ++i)
|
||||||
|
{
|
||||||
|
aiFace& face = mesh->mFaces[i];
|
||||||
|
face.mNumIndices = 3;
|
||||||
|
face.mIndices = new unsigned int[3];
|
||||||
|
|
||||||
|
face.mIndices[0] = geometry->GetIndex(i * 3 + 0);
|
||||||
|
face.mIndices[1] = geometry->GetIndex(i * 3 + 1);
|
||||||
|
face.mIndices[2] = geometry->GetIndex(i * 3 + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.mMeshes = new aiMesh*[1];
|
||||||
|
scene.mMeshes[0] = mesh;
|
||||||
|
scene.mNumMeshes = 1;
|
||||||
|
scene.mRootNode->mMeshes = new unsigned int[1];
|
||||||
|
scene.mRootNode->mMeshes[0] = 0;
|
||||||
|
scene.mRootNode->mNumMeshes = 1;
|
||||||
|
|
||||||
|
aiMaterial* material = new aiMaterial();
|
||||||
|
scene.mMaterials = new aiMaterial*[1];
|
||||||
|
scene.mMaterials[0] = material;
|
||||||
|
scene.mNumMaterials = 1;
|
||||||
|
|
||||||
|
// aiColor3D diffuseColor(1.0f, 1.0f, 1.0f);
|
||||||
|
// material->AddProperty(&diffuseColor, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||||
|
|
||||||
|
Array<char> textureData = Utils::ReadFile(texturePath);
|
||||||
|
|
||||||
|
aiTexture* texture = new aiTexture();
|
||||||
|
texture->mWidth = static_cast<unsigned int>(textureData.Size());
|
||||||
|
texture->mHeight = 0; // indicates that this is compressed texture and the pcData has size mWidth
|
||||||
|
texture->pcData = reinterpret_cast<aiTexel*>(new uint8_t[textureData.Size()]);
|
||||||
|
std::memcpy(texture->pcData, textureData.Data(), textureData.Size());
|
||||||
|
|
||||||
|
scene.mTextures = new aiTexture*[1];
|
||||||
|
scene.mTextures[0] = texture;
|
||||||
|
scene.mNumTextures = 1;
|
||||||
|
|
||||||
|
std::string ext = texturePath.substr(texturePath.find_last_of('.') + 1);
|
||||||
|
if (ext == "png")
|
||||||
|
{
|
||||||
|
std::memcpy(texture->achFormatHint, "png", 3);
|
||||||
|
}
|
||||||
|
else if (ext == "jpg" || ext == "jpeg")
|
||||||
|
{
|
||||||
|
std::memcpy(texture->achFormatHint, "jpg", 3);
|
||||||
|
}
|
||||||
|
texture->achFormatHint[3] = '\0';
|
||||||
|
|
||||||
|
aiString texName = aiString("*0");
|
||||||
|
material->AddProperty(&texName, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
|
||||||
|
|
||||||
|
// Validation
|
||||||
|
for (uint32_t i = 0; i < geometry->indexCount; ++i) {
|
||||||
|
if (geometry->GetIndex(i) >= geometry->vertexCount) {
|
||||||
|
std::cerr << "Invalid index at position " << i << ": "
|
||||||
|
<< geometry->GetIndex(i) << " (vertex count: "
|
||||||
|
<< geometry->vertexCount << ")" << std::endl;
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geometry->indexCount % 3 != 0) {
|
||||||
|
std::cerr << "Invalid index count: " << geometry->indexCount
|
||||||
|
<< " (not divisible by 3)" << std::endl;
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//aiString externalPath(texturePath);
|
||||||
|
//scene.mMaterials[0]->AddProperty(&externalPath, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
|
||||||
|
|
||||||
|
// Export
|
||||||
|
|
||||||
|
Assimp::Exporter exporter;
|
||||||
|
aiReturn result = exporter.Export(&scene, "fbx", fbxPath);
|
||||||
|
|
||||||
|
#define SAFE_DELETE_ARRAY(arr) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if (arr) \
|
||||||
|
delete[] arr; \
|
||||||
|
arr = nullptr; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
SAFE_DELETE_ARRAY(mesh->mVertices);
|
||||||
|
SAFE_DELETE_ARRAY(mesh->mNormals);
|
||||||
|
SAFE_DELETE_ARRAY(mesh->mTextureCoords[0]);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < mesh->mNumFaces; ++i)
|
||||||
|
{
|
||||||
|
SAFE_DELETE_ARRAY(mesh->mFaces[i].mIndices);
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_DELETE_ARRAY(mesh->mFaces);
|
||||||
|
|
||||||
|
delete mesh;
|
||||||
|
mesh = nullptr;
|
||||||
|
|
||||||
|
delete material;
|
||||||
|
material = nullptr;
|
||||||
|
|
||||||
|
SAFE_DELETE_ARRAY(scene.mMeshes);
|
||||||
|
SAFE_DELETE_ARRAY(scene.mRootNode->mMeshes);
|
||||||
|
SAFE_DELETE_ARRAY(scene.mMaterials);
|
||||||
|
SAFE_DELETE_ARRAY(scene.mTextures);
|
||||||
|
SAFE_DELETE_ARRAY(texture->pcData);
|
||||||
|
delete scene.mRootNode;
|
||||||
|
scene.mRootNode = nullptr;
|
||||||
|
#undef SAFE_DELETE_ARRAY
|
||||||
|
|
||||||
|
if (result != aiReturn_SUCCESS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unable to write a fbx file to " + fbxPath + ": " + exporter.GetErrorString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,5 +18,6 @@ namespace OpenVulkano::Scene
|
|||||||
static void WriteAsUSD(Geometry* geometry, const std::string& filePath);
|
static void WriteAsUSD(Geometry* geometry, const std::string& filePath);
|
||||||
static void WriteObjAsZip(Geometry* geometry, const std::string& texturePath, const std::string& zipPath);
|
static void WriteObjAsZip(Geometry* geometry, const std::string& texturePath, const std::string& zipPath);
|
||||||
static void WriteAsUSDZ(Geometry* geometry, const std::string& texturePath, const std::string& usdzPath);
|
static void WriteAsUSDZ(Geometry* geometry, const std::string& texturePath, const std::string& usdzPath);
|
||||||
|
static void WriteAsFBX(Geometry* geometry, const std::string& texturePath, const std::string& fbxPath);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user