mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 09:08:37 +02:00
Added ability to read FBX textures embedded in FBX files.
This commit is contained in:
parent
6251b6b819
commit
197127fbde
6 changed files with 112 additions and 47 deletions
|
@ -306,14 +306,14 @@ bool ModelUploader::addTextures(const QString& texdir, const QString fbxFile) {
|
||||||
|
|
||||||
foreach (FBXMesh mesh, geometry.meshes) {
|
foreach (FBXMesh mesh, geometry.meshes) {
|
||||||
foreach (FBXMeshPart part, mesh.parts) {
|
foreach (FBXMeshPart part, mesh.parts) {
|
||||||
if (!part.diffuseFilename.isEmpty()) {
|
if (!part.diffuseTexture.filename.isEmpty()) {
|
||||||
if (!addPart(texdir + "/" + part.diffuseFilename,
|
if (!addPart(texdir + "/" + part.diffuseTexture.filename,
|
||||||
QString("texture%1").arg(++_texturesCount))) {
|
QString("texture%1").arg(++_texturesCount))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!part.normalFilename.isEmpty()) {
|
if (!part.normalTexture.filename.isEmpty()) {
|
||||||
if (!addPart(texdir + "/" + part.normalFilename,
|
if (!addPart(texdir + "/" + part.normalTexture.filename,
|
||||||
QString("texture%1").arg(++_texturesCount))) {
|
QString("texture%1").arg(++_texturesCount))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -543,14 +543,14 @@ void NetworkGeometry::setGeometry(const FBXGeometry& geometry) {
|
||||||
int totalIndices = 0;
|
int totalIndices = 0;
|
||||||
foreach (const FBXMeshPart& part, mesh.parts) {
|
foreach (const FBXMeshPart& part, mesh.parts) {
|
||||||
NetworkMeshPart networkPart;
|
NetworkMeshPart networkPart;
|
||||||
if (!part.diffuseFilename.isEmpty()) {
|
if (!part.diffuseTexture.filename.isEmpty()) {
|
||||||
networkPart.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture(
|
networkPart.diffuseTexture = Application::getInstance()->getTextureCache()->getTexture(
|
||||||
_textureBase.resolved(QUrl(part.diffuseFilename)), false, mesh.isEye);
|
_textureBase.resolved(QUrl(part.diffuseTexture.filename)), false, mesh.isEye, part.diffuseTexture.content);
|
||||||
networkPart.diffuseTexture->setLoadPriorities(_loadPriorities);
|
networkPart.diffuseTexture->setLoadPriorities(_loadPriorities);
|
||||||
}
|
}
|
||||||
if (!part.normalFilename.isEmpty()) {
|
if (!part.normalTexture.filename.isEmpty()) {
|
||||||
networkPart.normalTexture = Application::getInstance()->getTextureCache()->getTexture(
|
networkPart.normalTexture = Application::getInstance()->getTextureCache()->getTexture(
|
||||||
_textureBase.resolved(QUrl(part.normalFilename)), true);
|
_textureBase.resolved(QUrl(part.normalTexture.filename)), true, false, part.normalTexture.content);
|
||||||
networkPart.normalTexture->setLoadPriorities(_loadPriorities);
|
networkPart.normalTexture->setLoadPriorities(_loadPriorities);
|
||||||
}
|
}
|
||||||
networkMesh.parts.append(networkPart);
|
networkMesh.parts.append(networkPart);
|
||||||
|
|
|
@ -105,13 +105,22 @@ GLuint TextureCache::getBlueTextureID() {
|
||||||
return _blueTextureID;
|
return _blueTextureID;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<NetworkTexture> TextureCache::getTexture(const QUrl& url, bool normalMap, bool dilatable) {
|
/// Extra data for creating textures.
|
||||||
|
class TextureExtra {
|
||||||
|
public:
|
||||||
|
bool normalMap;
|
||||||
|
const QByteArray& content;
|
||||||
|
};
|
||||||
|
|
||||||
|
QSharedPointer<NetworkTexture> TextureCache::getTexture(const QUrl& url, bool normalMap,
|
||||||
|
bool dilatable, const QByteArray& content) {
|
||||||
if (!dilatable) {
|
if (!dilatable) {
|
||||||
return ResourceCache::getResource(url, QUrl(), false, &normalMap).staticCast<NetworkTexture>();
|
TextureExtra extra = { normalMap, content };
|
||||||
|
return ResourceCache::getResource(url, QUrl(), false, &extra).staticCast<NetworkTexture>();
|
||||||
}
|
}
|
||||||
QSharedPointer<NetworkTexture> texture = _dilatableNetworkTextures.value(url);
|
QSharedPointer<NetworkTexture> texture = _dilatableNetworkTextures.value(url);
|
||||||
if (texture.isNull()) {
|
if (texture.isNull()) {
|
||||||
texture = QSharedPointer<NetworkTexture>(new DilatableNetworkTexture(url), &Resource::allReferencesCleared);
|
texture = QSharedPointer<NetworkTexture>(new DilatableNetworkTexture(url, content), &Resource::allReferencesCleared);
|
||||||
texture->setSelf(texture);
|
texture->setSelf(texture);
|
||||||
texture->setCache(this);
|
texture->setCache(this);
|
||||||
_dilatableNetworkTextures.insert(url, texture);
|
_dilatableNetworkTextures.insert(url, texture);
|
||||||
|
@ -215,7 +224,9 @@ bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
|
||||||
|
|
||||||
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
|
QSharedPointer<Resource> TextureCache::createResource(const QUrl& url,
|
||||||
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
||||||
return QSharedPointer<Resource>(new NetworkTexture(url, *(const bool*)extra), &Resource::allReferencesCleared);
|
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
|
||||||
|
return QSharedPointer<Resource>(new NetworkTexture(url, textureExtra->normalMap, textureExtra->content),
|
||||||
|
&Resource::allReferencesCleared);
|
||||||
}
|
}
|
||||||
|
|
||||||
QOpenGLFramebufferObject* TextureCache::createFramebufferObject() {
|
QOpenGLFramebufferObject* TextureCache::createFramebufferObject() {
|
||||||
|
@ -238,8 +249,8 @@ Texture::~Texture() {
|
||||||
glDeleteTextures(1, &_id);
|
glDeleteTextures(1, &_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) :
|
NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap, const QByteArray& content) :
|
||||||
Resource(url),
|
Resource(url, !content.isEmpty()),
|
||||||
_translucent(false) {
|
_translucent(false) {
|
||||||
|
|
||||||
if (!url.isValid()) {
|
if (!url.isValid()) {
|
||||||
|
@ -250,12 +261,19 @@ NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) :
|
||||||
glBindTexture(GL_TEXTURE_2D, getID());
|
glBindTexture(GL_TEXTURE_2D, getID());
|
||||||
loadSingleColorTexture(normalMap ? OPAQUE_BLUE : OPAQUE_WHITE);
|
loadSingleColorTexture(normalMap ? OPAQUE_BLUE : OPAQUE_WHITE);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
// if we have content, load it after we have our self pointer
|
||||||
|
if (!content.isEmpty()) {
|
||||||
|
_startedLoading = true;
|
||||||
|
QMetaObject::invokeMethod(this, "loadContent", Qt::QueuedConnection, Q_ARG(const QByteArray&, content));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ImageReader : public QRunnable {
|
class ImageReader : public QRunnable {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply);
|
ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply, const QUrl& url = QUrl(),
|
||||||
|
const QByteArray& content = QByteArray());
|
||||||
|
|
||||||
virtual void run();
|
virtual void run();
|
||||||
|
|
||||||
|
@ -263,27 +281,37 @@ private:
|
||||||
|
|
||||||
QWeakPointer<Resource> _texture;
|
QWeakPointer<Resource> _texture;
|
||||||
QNetworkReply* _reply;
|
QNetworkReply* _reply;
|
||||||
|
QUrl _url;
|
||||||
|
QByteArray _content;
|
||||||
};
|
};
|
||||||
|
|
||||||
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply) :
|
ImageReader::ImageReader(const QWeakPointer<Resource>& texture, QNetworkReply* reply,
|
||||||
|
const QUrl& url, const QByteArray& content) :
|
||||||
_texture(texture),
|
_texture(texture),
|
||||||
_reply(reply) {
|
_reply(reply),
|
||||||
|
_url(url),
|
||||||
|
_content(content) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageReader::run() {
|
void ImageReader::run() {
|
||||||
QSharedPointer<Resource> texture = _texture.toStrongRef();
|
QSharedPointer<Resource> texture = _texture.toStrongRef();
|
||||||
if (texture.isNull()) {
|
if (texture.isNull()) {
|
||||||
_reply->deleteLater();
|
if (_reply) {
|
||||||
|
_reply->deleteLater();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QUrl url = _reply->url();
|
if (_reply) {
|
||||||
QImage image = QImage::fromData(_reply->readAll());
|
_url = _reply->url();
|
||||||
_reply->deleteLater();
|
_content = _reply->readAll();
|
||||||
|
_reply->deleteLater();
|
||||||
|
}
|
||||||
|
QImage image = QImage::fromData(_content);
|
||||||
|
|
||||||
// enforce a fixed maximum
|
// enforce a fixed maximum
|
||||||
const int MAXIMUM_SIZE = 1024;
|
const int MAXIMUM_SIZE = 1024;
|
||||||
if (image.width() > MAXIMUM_SIZE || image.height() > MAXIMUM_SIZE) {
|
if (image.width() > MAXIMUM_SIZE || image.height() > MAXIMUM_SIZE) {
|
||||||
qDebug() << "Image greater than maximum size:" << url << image.width() << image.height();
|
qDebug() << "Image greater than maximum size:" << _url << image.width() << image.height();
|
||||||
image = image.scaled(MAXIMUM_SIZE, MAXIMUM_SIZE, Qt::KeepAspectRatio);
|
image = image.scaled(MAXIMUM_SIZE, MAXIMUM_SIZE, Qt::KeepAspectRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +343,7 @@ void ImageReader::run() {
|
||||||
}
|
}
|
||||||
int imageArea = image.width() * image.height();
|
int imageArea = image.width() * image.height();
|
||||||
if (opaquePixels == imageArea) {
|
if (opaquePixels == imageArea) {
|
||||||
qDebug() << "Image with alpha channel is completely opaque:" << url;
|
qDebug() << "Image with alpha channel is completely opaque:" << _url;
|
||||||
image = image.convertToFormat(QImage::Format_RGB888);
|
image = image.convertToFormat(QImage::Format_RGB888);
|
||||||
}
|
}
|
||||||
QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image),
|
QMetaObject::invokeMethod(texture.data(), "setImage", Q_ARG(const QImage&, image),
|
||||||
|
@ -327,6 +355,10 @@ void NetworkTexture::downloadFinished(QNetworkReply* reply) {
|
||||||
QThreadPool::globalInstance()->start(new ImageReader(_self, reply));
|
QThreadPool::globalInstance()->start(new ImageReader(_self, reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkTexture::loadContent(const QByteArray& content) {
|
||||||
|
QThreadPool::globalInstance()->start(new ImageReader(_self, NULL, _url, content));
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkTexture::setImage(const QImage& image, bool translucent) {
|
void NetworkTexture::setImage(const QImage& image, bool translucent) {
|
||||||
_translucent = translucent;
|
_translucent = translucent;
|
||||||
|
|
||||||
|
@ -348,8 +380,8 @@ void NetworkTexture::imageLoaded(const QImage& image) {
|
||||||
// nothing by default
|
// nothing by default
|
||||||
}
|
}
|
||||||
|
|
||||||
DilatableNetworkTexture::DilatableNetworkTexture(const QUrl& url) :
|
DilatableNetworkTexture::DilatableNetworkTexture(const QUrl& url, const QByteArray& content) :
|
||||||
NetworkTexture(url, false),
|
NetworkTexture(url, false, content),
|
||||||
_innerRadius(0),
|
_innerRadius(0),
|
||||||
_outerRadius(0)
|
_outerRadius(0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,7 +44,8 @@ public:
|
||||||
GLuint getBlueTextureID();
|
GLuint getBlueTextureID();
|
||||||
|
|
||||||
/// Loads a texture from the specified URL.
|
/// Loads a texture from the specified URL.
|
||||||
QSharedPointer<NetworkTexture> getTexture(const QUrl& url, bool normalMap = false, bool dilatable = false);
|
QSharedPointer<NetworkTexture> getTexture(const QUrl& url, bool normalMap = false, bool dilatable = false,
|
||||||
|
const QByteArray& content = QByteArray());
|
||||||
|
|
||||||
/// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is
|
/// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is
|
||||||
/// used for scene rendering.
|
/// used for scene rendering.
|
||||||
|
@ -115,7 +116,7 @@ class NetworkTexture : public Resource, public Texture {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NetworkTexture(const QUrl& url, bool normalMap);
|
NetworkTexture(const QUrl& url, bool normalMap, const QByteArray& content);
|
||||||
|
|
||||||
/// Checks whether it "looks like" this texture is translucent
|
/// Checks whether it "looks like" this texture is translucent
|
||||||
/// (majority of pixels neither fully opaque or fully transparent).
|
/// (majority of pixels neither fully opaque or fully transparent).
|
||||||
|
@ -124,10 +125,12 @@ public:
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void downloadFinished(QNetworkReply* reply);
|
virtual void downloadFinished(QNetworkReply* reply);
|
||||||
virtual void imageLoaded(const QImage& image);
|
|
||||||
|
Q_INVOKABLE void loadContent(const QByteArray& content);
|
||||||
Q_INVOKABLE void setImage(const QImage& image, bool translucent);
|
Q_INVOKABLE void setImage(const QImage& image, bool translucent);
|
||||||
|
|
||||||
|
virtual void imageLoaded(const QImage& image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool _translucent;
|
bool _translucent;
|
||||||
|
@ -139,7 +142,7 @@ class DilatableNetworkTexture : public NetworkTexture {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DilatableNetworkTexture(const QUrl& url);
|
DilatableNetworkTexture(const QUrl& url, const QByteArray& content);
|
||||||
|
|
||||||
/// Returns a pointer to a texture with the requested amount of dilation.
|
/// Returns a pointer to a texture with the requested amount of dilation.
|
||||||
QSharedPointer<Texture> getDilatedTexture(float dilation);
|
QSharedPointer<Texture> getDilatedTexture(float dilation);
|
||||||
|
|
|
@ -935,6 +935,14 @@ public:
|
||||||
QVector<float> values;
|
QVector<float> values;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FBXTexture getTexture(const QString& textureID, const QHash<QString, QByteArray>& textureFilenames,
|
||||||
|
const QHash<QByteArray, QByteArray>& textureContent) {
|
||||||
|
FBXTexture texture;
|
||||||
|
texture.filename = textureFilenames.value(textureID);
|
||||||
|
texture.content = textureContent.value(texture.filename);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
||||||
QHash<QString, ExtractedMesh> meshes;
|
QHash<QString, ExtractedMesh> meshes;
|
||||||
QVector<ExtractedBlendshape> blendshapes;
|
QVector<ExtractedBlendshape> blendshapes;
|
||||||
|
@ -944,6 +952,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
QHash<QString, Cluster> clusters;
|
QHash<QString, Cluster> clusters;
|
||||||
QHash<QString, AnimationCurve> animationCurves;
|
QHash<QString, AnimationCurve> animationCurves;
|
||||||
QHash<QString, QByteArray> textureFilenames;
|
QHash<QString, QByteArray> textureFilenames;
|
||||||
|
QHash<QByteArray, QByteArray> textureContent;
|
||||||
QHash<QString, Material> materials;
|
QHash<QString, Material> materials;
|
||||||
QHash<QString, QString> diffuseTextures;
|
QHash<QString, QString> diffuseTextures;
|
||||||
QHash<QString, QString> bumpTextures;
|
QHash<QString, QString> bumpTextures;
|
||||||
|
@ -952,8 +961,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
QHash<QString, QString> yComponents;
|
QHash<QString, QString> yComponents;
|
||||||
QHash<QString, QString> zComponents;
|
QHash<QString, QString> zComponents;
|
||||||
|
|
||||||
printNode(node, 0);
|
|
||||||
|
|
||||||
QVariantHash joints = mapping.value("joint").toHash();
|
QVariantHash joints = mapping.value("joint").toHash();
|
||||||
QString jointEyeLeftName = processID(getString(joints.value("jointEyeLeft", "jointEyeLeft")));
|
QString jointEyeLeftName = processID(getString(joints.value("jointEyeLeft", "jointEyeLeft")));
|
||||||
QString jointEyeRightName = processID(getString(joints.value("jointEyeRight", "jointEyeRight")));
|
QString jointEyeRightName = processID(getString(joints.value("jointEyeRight", "jointEyeRight")));
|
||||||
|
@ -1182,6 +1189,21 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
textureFilenames.insert(getID(object.properties), filename);
|
textureFilenames.insert(getID(object.properties), filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (object.name == "Video") {
|
||||||
|
QByteArray filename;
|
||||||
|
QByteArray content;
|
||||||
|
foreach (const FBXNode& subobject, object.children) {
|
||||||
|
if (subobject.name == "RelativeFilename") {
|
||||||
|
filename = subobject.properties.at(0).toByteArray();
|
||||||
|
filename = filename.mid(qMax(filename.lastIndexOf('\\'), filename.lastIndexOf('/')) + 1);
|
||||||
|
|
||||||
|
} else if (subobject.name == "Content" && !subobject.properties.isEmpty()) {
|
||||||
|
content = subobject.properties.at(0).toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!content.isEmpty()) {
|
||||||
|
textureContent.insert(filename, content);
|
||||||
|
}
|
||||||
} else if (object.name == "Material") {
|
} else if (object.name == "Material") {
|
||||||
Material material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), 96.0f };
|
Material material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), 96.0f };
|
||||||
foreach (const FBXNode& subobject, object.children) {
|
foreach (const FBXNode& subobject, object.children) {
|
||||||
|
@ -1263,7 +1285,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
if (type.contains("diffuse")) {
|
if (type.contains("diffuse")) {
|
||||||
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
||||||
} else if (type.contains("bump")) {
|
} else if (type.contains("bump") || type.contains("normal")) {
|
||||||
bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||||
|
|
||||||
} else if (type == "lcl rotation") {
|
} else if (type == "lcl rotation") {
|
||||||
|
@ -1463,23 +1485,23 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
if (materials.contains(childID)) {
|
if (materials.contains(childID)) {
|
||||||
Material material = materials.value(childID);
|
Material material = materials.value(childID);
|
||||||
|
|
||||||
QByteArray diffuseFilename;
|
FBXTexture diffuseTexture;
|
||||||
QString diffuseTextureID = diffuseTextures.value(childID);
|
QString diffuseTextureID = diffuseTextures.value(childID);
|
||||||
if (!diffuseTextureID.isNull()) {
|
if (!diffuseTextureID.isNull()) {
|
||||||
diffuseFilename = textureFilenames.value(diffuseTextureID);
|
diffuseTexture = getTexture(diffuseTextureID, textureFilenames, textureContent);
|
||||||
|
|
||||||
// FBX files generated by 3DSMax have an intermediate texture parent, apparently
|
// FBX files generated by 3DSMax have an intermediate texture parent, apparently
|
||||||
foreach (const QString& childTextureID, childMap.values(diffuseTextureID)) {
|
foreach (const QString& childTextureID, childMap.values(diffuseTextureID)) {
|
||||||
if (textureFilenames.contains(childTextureID)) {
|
if (textureFilenames.contains(childTextureID)) {
|
||||||
diffuseFilename = textureFilenames.value(childTextureID);
|
diffuseTexture = getTexture(diffuseTextureID, textureFilenames, textureContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray normalFilename;
|
FBXTexture normalTexture;
|
||||||
QString bumpTextureID = bumpTextures.value(childID);
|
QString bumpTextureID = bumpTextures.value(childID);
|
||||||
if (!bumpTextureID.isNull()) {
|
if (!bumpTextureID.isNull()) {
|
||||||
normalFilename = textureFilenames.value(bumpTextureID);
|
normalTexture = getTexture(bumpTextureID, textureFilenames, textureContent);
|
||||||
generateTangents = true;
|
generateTangents = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1489,21 +1511,21 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
part.diffuseColor = material.diffuse;
|
part.diffuseColor = material.diffuse;
|
||||||
part.specularColor = material.specular;
|
part.specularColor = material.specular;
|
||||||
part.shininess = material.shininess;
|
part.shininess = material.shininess;
|
||||||
if (!diffuseFilename.isNull()) {
|
if (!diffuseTexture.filename.isNull()) {
|
||||||
part.diffuseFilename = diffuseFilename;
|
part.diffuseTexture = diffuseTexture;
|
||||||
}
|
}
|
||||||
if (!normalFilename.isNull()) {
|
if (!normalTexture.filename.isNull()) {
|
||||||
part.normalFilename = normalFilename;
|
part.normalTexture = normalTexture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
materialIndex++;
|
materialIndex++;
|
||||||
|
|
||||||
} else if (textureFilenames.contains(childID)) {
|
} else if (textureFilenames.contains(childID)) {
|
||||||
QByteArray filename = textureFilenames.value(childID);
|
FBXTexture texture = getTexture(childID, textureFilenames, textureContent);
|
||||||
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
|
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
|
||||||
if (extracted.partMaterialTextures.at(j).second == textureIndex) {
|
if (extracted.partMaterialTextures.at(j).second == textureIndex) {
|
||||||
extracted.mesh.parts[j].diffuseFilename = filename;
|
extracted.mesh.parts[j].diffuseTexture = texture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
textureIndex++;
|
textureIndex++;
|
||||||
|
|
|
@ -103,6 +103,14 @@ public:
|
||||||
glm::mat4 inverseBindMatrix;
|
glm::mat4 inverseBindMatrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A texture map in an FBX document.
|
||||||
|
class FBXTexture {
|
||||||
|
public:
|
||||||
|
|
||||||
|
QByteArray filename;
|
||||||
|
QByteArray content;
|
||||||
|
};
|
||||||
|
|
||||||
/// A single part of a mesh (with the same material).
|
/// A single part of a mesh (with the same material).
|
||||||
class FBXMeshPart {
|
class FBXMeshPart {
|
||||||
public:
|
public:
|
||||||
|
@ -114,8 +122,8 @@ public:
|
||||||
glm::vec3 specularColor;
|
glm::vec3 specularColor;
|
||||||
float shininess;
|
float shininess;
|
||||||
|
|
||||||
QByteArray diffuseFilename;
|
FBXTexture diffuseTexture;
|
||||||
QByteArray normalFilename;
|
FBXTexture normalTexture;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A single mesh (with optional blendshapes) extracted from an FBX document.
|
/// A single mesh (with optional blendshapes) extracted from an FBX document.
|
||||||
|
|
Loading…
Reference in a new issue