mirror of
https://github.com/overte-org/overte.git
synced 2025-04-10 08:56:57 +02:00
Add draco support to FBXBaker
This commit is contained in:
parent
09d18b5ba9
commit
9b462171f6
7 changed files with 148 additions and 13 deletions
|
@ -3,3 +3,8 @@ setup_hifi_library(Concurrent)
|
|||
|
||||
link_hifi_libraries(shared model networking ktx image fbx)
|
||||
include_hifi_library_headers(gpu)
|
||||
|
||||
add_dependency_external_projects(draco)
|
||||
find_package(Draco REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${DRACO_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${DRACO_LIBRARY} ${DRACO_ENCODER_LIBRARY})
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
#include <cmath> // need this include so we don't get an error looking for std::isnan
|
||||
|
||||
#include <fbxsdk.h>
|
||||
|
||||
#include <QtConcurrent>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDir>
|
||||
|
@ -35,6 +33,9 @@
|
|||
|
||||
#include "FBXBaker.h"
|
||||
|
||||
#include <draco/mesh/triangle_soup_mesh_builder.h>
|
||||
#include <draco/compression/encode.h>
|
||||
|
||||
FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter,
|
||||
const QString& bakedOutputDir, const QString& originalOutputDir) :
|
||||
_fbxURL(fbxURL),
|
||||
|
@ -80,7 +81,8 @@ void FBXBaker::bakeSourceCopy() {
|
|||
return;
|
||||
}
|
||||
|
||||
// enumerate the textures found in the scene and start a bake for them
|
||||
// enumerate the models and textures found in the scene and start a bake for them
|
||||
rewriteAndBakeSceneModels();
|
||||
rewriteAndBakeSceneTextures();
|
||||
|
||||
if (hasErrors()) {
|
||||
|
@ -212,7 +214,7 @@ void FBXBaker::importScene() {
|
|||
|
||||
qCDebug(model_baking) << "Parsing" << _fbxURL;
|
||||
_rootNode = reader._rootNode = reader.parseFBX(&fbxFile);
|
||||
_geometry = *reader.extractFBXGeometry({}, _fbxURL.toString());
|
||||
_geometry = reader.extractFBXGeometry({}, _fbxURL.toString());
|
||||
_textureContent = reader._textureContent;
|
||||
}
|
||||
|
||||
|
@ -278,12 +280,136 @@ QUrl FBXBaker::getTextureURL(const QFileInfo& textureFileInfo, QString relativeF
|
|||
return urlToTexture;
|
||||
}
|
||||
|
||||
void FBXBaker::rewriteAndBakeSceneModels() {
|
||||
unsigned int meshIndex = 0;
|
||||
for (FBXNode& rootChild : _rootNode.children) {
|
||||
if (rootChild.name == "Objects") {
|
||||
for (FBXNode& objectChild : rootChild.children) {
|
||||
if (objectChild.name == "Geometry") {
|
||||
|
||||
// TODO Pull this out of _geometry instead so we don't have to reprocess it
|
||||
auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex);
|
||||
auto mesh = extractedMesh.mesh;
|
||||
|
||||
Q_ASSERT(mesh.normals.size() == 0 || mesh.normals.size() == mesh.vertices.size());
|
||||
Q_ASSERT(mesh.colors.size() == 0 || mesh.colors.size() == mesh.vertices.size());
|
||||
Q_ASSERT(mesh.texCoords.size() == 0 || mesh.texCoords.size() == mesh.vertices.size());
|
||||
|
||||
int64_t numTriangles { 0 };
|
||||
for (auto& part : mesh.parts) {
|
||||
Q_ASSERT(part.quadTrianglesIndices.size() % 3 == 0);
|
||||
Q_ASSERT(part.triangleIndices.size() % 3 == 0);
|
||||
|
||||
numTriangles += part.quadTrianglesIndices.size() / 3;
|
||||
numTriangles += part.triangleIndices.size() / 3;
|
||||
}
|
||||
|
||||
draco::TriangleSoupMeshBuilder meshBuilder;
|
||||
|
||||
meshBuilder.Start(numTriangles);
|
||||
|
||||
bool hasNormals { mesh.normals.size() > 0 };
|
||||
bool hasColors { mesh.colors.size() > 0 };
|
||||
bool hasTexCoords { mesh.texCoords.size() > 0 };
|
||||
//bool hasTexCoords1 { mesh.texCoords1.size() > 0 };
|
||||
|
||||
int normalsAttributeID { -1 };
|
||||
int colorsAttributeID { -1 };
|
||||
int texCoordsAttributeID { -1 };
|
||||
//int texCoords1AttributeID { -1 };
|
||||
|
||||
const int positionAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::POSITION,
|
||||
3, draco::DT_FLOAT32);
|
||||
|
||||
const int faceMaterialAttributeID = meshBuilder.AddAttribute(
|
||||
(draco::GeometryAttribute::Type)DRACO_ATTRIBUTE_MATERIAL_ID,
|
||||
1, draco::DT_INT64);
|
||||
|
||||
if (hasNormals) {
|
||||
normalsAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::NORMAL,
|
||||
3, draco::DT_FLOAT32);
|
||||
}
|
||||
if (hasColors) {
|
||||
colorsAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::COLOR,
|
||||
3, draco::DT_FLOAT32);
|
||||
}
|
||||
if (hasTexCoords) {
|
||||
texCoordsAttributeID = meshBuilder.AddAttribute(draco::GeometryAttribute::TEX_COORD,
|
||||
2, draco::DT_FLOAT32);
|
||||
}
|
||||
|
||||
|
||||
for (auto& part : mesh.parts) {
|
||||
//Q_ASSERT(part.quadTrianglesIndices % 3 == 0);
|
||||
//Q_ASSERT(part.triangleIndices % 3 == 0);
|
||||
|
||||
int64_t materialID = 0;
|
||||
|
||||
for (int i = 0; (i + 2) < part.quadTrianglesIndices.size(); i += 3) {
|
||||
auto idx0 = part.quadTrianglesIndices[i];
|
||||
auto idx1 = part.quadTrianglesIndices[i + 1];
|
||||
auto idx2 = part.quadTrianglesIndices[i + 2];
|
||||
|
||||
auto face = draco::FaceIndex(i / 3);
|
||||
|
||||
meshBuilder.SetPerFaceAttributeValueForFace(faceMaterialAttributeID, face, &materialID);
|
||||
|
||||
meshBuilder.SetAttributeValuesForFace(positionAttributeID, face,
|
||||
&mesh.vertices[idx0], &mesh.vertices[idx1],
|
||||
&mesh.vertices[idx2]);
|
||||
|
||||
if (hasNormals) {
|
||||
meshBuilder.SetAttributeValuesForFace(normalsAttributeID, face,
|
||||
&mesh.normals[idx0],&mesh.normals[idx1],
|
||||
&mesh.normals[idx2]);
|
||||
}
|
||||
if (hasColors) {
|
||||
meshBuilder.SetAttributeValuesForFace(colorsAttributeID, face,
|
||||
&mesh.colors[idx0], &mesh.colors[idx1],
|
||||
&mesh.colors[idx2]);
|
||||
}
|
||||
if (hasTexCoords) {
|
||||
meshBuilder.SetAttributeValuesForFace(texCoordsAttributeID, face,
|
||||
&mesh.texCoords[idx0], &mesh.texCoords[idx1],
|
||||
&mesh.texCoords[idx2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto dracoMesh = meshBuilder.Finalize();
|
||||
|
||||
draco::Encoder encoder;
|
||||
draco::EncoderBuffer buffer;
|
||||
encoder.EncodeMeshToBuffer(*dracoMesh, &buffer);
|
||||
|
||||
FBXNode dracoMeshNode;
|
||||
dracoMeshNode.name = "DracoMesh";
|
||||
auto value = QVariant::fromValue(QByteArray(buffer.data(), buffer.size()));
|
||||
dracoMeshNode.properties.append(value);
|
||||
|
||||
|
||||
QFile file("C:/Users/huffm/encodedFBX/" + this->_fbxURL.fileName() + "-" + QString::number(meshIndex) + ".drc");
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(buffer.data(), buffer.size());
|
||||
file.close();
|
||||
} else {
|
||||
qWarning() << "Failed to write to: " << file.fileName();
|
||||
|
||||
}
|
||||
|
||||
objectChild.children.push_back(dracoMeshNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FBXBaker::rewriteAndBakeSceneTextures() {
|
||||
using namespace image::TextureUsage;
|
||||
QHash<QString, image::TextureUsage::Type> textureTypes;
|
||||
|
||||
// enumerate the materials in the extracted geometry so we can determine the texture type for each texture ID
|
||||
for (const auto& material : _geometry.materials) {
|
||||
for (const auto& material : _geometry->materials) {
|
||||
if (material.normalTexture.isBumpmap) {
|
||||
textureTypes[material.normalTexture.id] = BUMP_TEXTURE;
|
||||
} else {
|
||||
|
|
|
@ -58,6 +58,7 @@ private:
|
|||
void loadSourceFBX();
|
||||
|
||||
void importScene();
|
||||
void rewriteAndBakeSceneModels();
|
||||
void rewriteAndBakeSceneTextures();
|
||||
void exportScene();
|
||||
void removeEmbeddedMediaFolder();
|
||||
|
@ -73,7 +74,7 @@ private:
|
|||
QUrl _fbxURL;
|
||||
|
||||
FBXNode _rootNode;
|
||||
FBXGeometry _geometry;
|
||||
FBXGeometry* _geometry;
|
||||
QHash<QByteArray, QByteArray> _textureContent;
|
||||
|
||||
QString _bakedFBXFilePath;
|
||||
|
|
|
@ -32,6 +32,13 @@ static const QByteArray FBX_BINARY_PROLOG = "Kaydara FBX Binary ";
|
|||
static const int FBX_HEADER_BYTES_BEFORE_VERSION = 23;
|
||||
static const quint32 FBX_VERSION_2016 = 7500;
|
||||
|
||||
|
||||
// TODO Convert to GeometryAttribute type
|
||||
static const int DRACO_BEGIN_CUSTOM_HIFI_ATTRIBUTES = 1000;
|
||||
static const int DRACO_ATTRIBUTE_MATERIAL_ID = DRACO_BEGIN_CUSTOM_HIFI_ATTRIBUTES;
|
||||
static const int DRACO_ATTRIBUTE_TEX_COORD_1 = DRACO_BEGIN_CUSTOM_HIFI_ATTRIBUTES + 1;
|
||||
|
||||
|
||||
class FBXNode;
|
||||
using FBXNodeList = QList<FBXNode>;
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ public:
|
|||
|
||||
FBXGeometry* extractFBXGeometry(const QVariantHash& mapping, const QString& url);
|
||||
|
||||
ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex);
|
||||
static ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex);
|
||||
QHash<QString, ExtractedMesh> meshes;
|
||||
static void buildModelMesh(FBXMesh& extractedMesh, const QString& url);
|
||||
|
||||
|
|
|
@ -304,8 +304,9 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn
|
|||
if (subdata.name == "Materials") {
|
||||
materials = getIntVector(subdata);
|
||||
} else if (subdata.name == "MappingInformationType") {
|
||||
if (subdata.properties.at(0) == BY_POLYGON)
|
||||
if (subdata.properties.at(0) == BY_POLYGON) {
|
||||
isMaterialPerPolygon = true;
|
||||
}
|
||||
} else {
|
||||
isMaterialPerPolygon = false;
|
||||
}
|
||||
|
|
|
@ -6,11 +6,6 @@ link_hifi_libraries(networking shared image gpu ktx fbx baking model)
|
|||
|
||||
setup_memory_debugger()
|
||||
|
||||
add_dependency_external_projects(draco)
|
||||
find_package(Draco REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${DRACO_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${DRACO_LIBRARY} ${DRACO_ENCODER_LIBRARY})
|
||||
|
||||
if (WIN32)
|
||||
package_libraries_for_deployment()
|
||||
endif ()
|
||||
|
|
Loading…
Reference in a new issue