Skip to content

Commit

Permalink
Add support for multiple maps (#180)
Browse files Browse the repository at this point in the history
* Add support for multiple maps

* Fixed a few issues with mapping COLLADA sets -> semantics; added optimization for removing unused of multiple texture coordindates

* Update CHANGES.md

* Added GLTF::Asset test for removing unused semantics

* Updated CHANGES.md
  • Loading branch information
lasalvavida authored Aug 30, 2018
1 parent 34f55fe commit 078f05f
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 21 deletions.
7 changes: 5 additions & 2 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
Change Log
==========
### Next Release
### v2.1.4 - 2018-08-29

#### Fixes :wrench:
##### Additions :tada:
* Added support for multiple maps [#169](https://github.com/KhronosGroup/COLLADA2GLTF/issues/169)

##### Fixes :wrench:
* Fixed issue with relative path resolution on Windows [#200](https://github.com/KhronosGroup/COLLADA2GLTF/issues/200)
* Updated to OpenCOLLADA 1.6.63
* Resolves issue where image elements declared in profile_COMMON are not written [#129](https://github.com/KhronosGroup/COLLADA2GLTF/issues/129) and [#114](https://github.com/KhronosGroup/COLLADA2GLTF/issues/114)
Expand Down
3 changes: 1 addition & 2 deletions GLTF/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,5 @@ if (test)
add_executable(${PROJECT_NAME}-test ${TEST_HEADERS} ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME} gtest)

add_test(GLTFAccessorTest ${PROJECT_NAME}-test)
add_test(GLTFObjectTest ${PROJECT_NAME}-test)
add_test(GLTFTest ${PROJECT_NAME}-test)
endif()
4 changes: 4 additions & 0 deletions GLTF/include/GLTFMaterial.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ namespace GLTF {
public:
float* ambient = NULL;
GLTF::Texture* ambientTexture = NULL;
int ambientTexCoord = 0;
float* diffuse = NULL;
GLTF::Texture* diffuseTexture = NULL;
int diffuseTexCoord = 0;
float* emission = NULL;
GLTF::Texture* emissionTexture = NULL;
int emissionTexCoord = 0;
float* specular = NULL;
GLTF::Texture* specularTexture = NULL;
int specularTexCoord = 0;
float* shininess = NULL;
float* transparency = NULL;
GLTF::Texture* bumpTexture = NULL;
Expand Down
87 changes: 74 additions & 13 deletions GLTF/src/GLTFAsset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,30 +415,91 @@ void GLTF::Asset::removeUncompressedBufferViews() {
}

void GLTF::Asset::removeUnusedSemantics() {
for (GLTF::Primitive* primitive : getAllPrimitives()) {
// Remove unused TEXCOORD semantics
std::map<GLTF::Material*, std::vector<GLTF::Primitive*>> materialMappings;
std::vector<GLTF::Primitive*> primitives = getAllPrimitives();
for (GLTF::Primitive* primitive : primitives) {
GLTF::Material* material = primitive->material;
if (material != NULL) {
GLTF::Material::Values* values = material->values;
std::map<std::string, GLTF::Accessor*> attributes = primitive->attributes;
std::vector<std::string> semantics;
for (const auto attribute : attributes) {
std::string semantic = attribute.first;
if (semantic.find("TEXCOORD") != std::string::npos) {
std::map<std::string, GLTF::Accessor*>::iterator removeTexcoord = primitive->attributes.find(semantic);
if (semantic == "TEXCOORD_0") {
if (values->ambientTexture == NULL && values->diffuseTexture == NULL && values->emissionTexture == NULL &&
values->specularTexture == NULL && values->bumpTexture == NULL) {
std::map<std::string, GLTF::Accessor*>::iterator removeTexcoord = primitive->attributes.find(semantic);
primitive->attributes.erase(removeTexcoord);
removeAttributeFromDracoExtension(primitive, semantic);
}
semantics.push_back(semantic);
}
}
for (const std::string semantic : semantics) {
std::map<std::string, GLTF::Accessor*>::iterator removeTexcoord = primitive->attributes.find(semantic);
size_t index = std::stoi(semantic.substr(semantic.find_last_of('_') + 1));
if ((values->ambientTexture == NULL || values->ambientTexCoord != index) &&
(values->diffuseTexture == NULL || values->diffuseTexCoord != index) &&
(values->emissionTexture == NULL || values->emissionTexCoord != index) &&
(values->specularTexture == NULL || values->specularTexCoord != index) &&
(values->bumpTexture == NULL)) {
auto findMaterialMapping = materialMappings.find(material);
if (findMaterialMapping == materialMappings.end()) {
materialMappings[material] = std::vector<GLTF::Primitive*>();
}
else {
// Right now we don't support multiple sets of texture coordinates
primitive->attributes.erase(removeTexcoord);
removeAttributeFromDracoExtension(primitive, semantic);
materialMappings[material].push_back(primitive);

std::map<std::string, GLTF::Accessor*>::iterator removeTexcoord = primitive->attributes.find(semantic);
primitive->attributes.erase(removeTexcoord);
// TODO: This will need to be adjusted for multiple maps
removeAttributeFromDracoExtension(primitive, semantic);
}
}
}
}
// Remove holes, i.e. if we removed TEXCOORD_0, change TEXCOORD_1 -> TEXCOORD_0
for (const auto materialMapping : materialMappings) {
std::map<size_t, size_t> indexMapping;
for (GLTF::Primitive* primitive : materialMapping.second) {
std::map<std::string, GLTF::Accessor*> rebuildAttributes;
std::vector<GLTF::Accessor*> texcoordAccessors;
size_t index;
for (const auto attribute : primitive->attributes) {
std::string semantic = attribute.first;
if (semantic.find("TEXCOORD") != std::string::npos) {
index = std::stoi(semantic.substr(semantic.find_last_of('_') + 1));
while (index >= texcoordAccessors.size()) {
texcoordAccessors.push_back(NULL);
}
texcoordAccessors[index] = attribute.second;
} else {
rebuildAttributes[semantic] = attribute.second;
}
}
index = 0;
for (size_t i = 0; i < texcoordAccessors.size(); i++) {
GLTF::Accessor* texcoordAccessor = texcoordAccessors[i];
if (texcoordAccessor != NULL) {
indexMapping[i] = index;
rebuildAttributes["TEXCOORD_" + std::to_string(index)] = texcoordAccessor;
index++;
}
}
primitive->attributes = rebuildAttributes;
}
// Fix material texcoord references
GLTF::Material* material = materialMapping.first;
GLTF::Material::Values* values = material->values;
for (const auto indexMap : indexMapping) {
size_t from = indexMap.first;
size_t to = indexMap.second;
if (values->ambientTexCoord == from) {
values->ambientTexCoord = to;
}
if (values->diffuseTexCoord == from) {
values->diffuseTexCoord = to;
}
if (values->emissionTexCoord == from) {
values->emissionTexCoord = to;
}
if (values->specularTexCoord == from) {
values->specularTexCoord = to;
}
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion GLTF/src/GLTFMaterial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ void GLTF::MaterialPBR::Texture::writeJSON(void* writer, GLTF::Options* options)
jsonWriter->Key("index");
jsonWriter->Int(texture->id);
}
if (texCoord >= 0) {
if (texCoord > 0) {
jsonWriter->Key("texCoord");
jsonWriter->Int(texCoord);
}
Expand Down Expand Up @@ -867,6 +867,7 @@ GLTF::MaterialPBR* GLTF::MaterialCommon::getMaterialPBR(GLTF::Options* options)
}
if (values->diffuseTexture) {
GLTF::MaterialPBR::Texture* texture = new GLTF::MaterialPBR::Texture();
texture->texCoord = values->diffuseTexCoord;
texture->texture = values->diffuseTexture;
material->metallicRoughness->baseColorTexture = texture;
if (options->specularGlossiness) {
Expand All @@ -879,13 +880,15 @@ GLTF::MaterialPBR* GLTF::MaterialCommon::getMaterialPBR(GLTF::Options* options)
}
if (values->emissionTexture) {
GLTF::MaterialPBR::Texture* texture = new GLTF::MaterialPBR::Texture();
texture->texCoord = values->emissionTexCoord;
texture->texture = values->emissionTexture;
material->emissiveTexture = texture;
material->emissiveFactor = new float[3]{ 1.0, 1.0, 1.0 };
}

if (values->ambientTexture) {
GLTF::MaterialPBR::Texture* texture = new GLTF::MaterialPBR::Texture();
texture->texCoord = values->ambientTexCoord;
texture->texture = values->ambientTexture;
material->occlusionTexture = texture;
}
Expand All @@ -896,6 +899,7 @@ GLTF::MaterialPBR* GLTF::MaterialCommon::getMaterialPBR(GLTF::Options* options)
}
if (values->specularTexture) {
GLTF::MaterialPBR::Texture* texture = new GLTF::MaterialPBR::Texture();
texture->texCoord = values->specularTexCoord;
texture->texture = values->specularTexture;
material->specularGlossiness->specularGlossinessTexture = texture;
}
Expand Down
7 changes: 7 additions & 0 deletions GLTF/test/include/GLTFAssetTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include "gtest/gtest.h"

namespace {
class GLTFAssetTest : public ::testing::Test {};
}
42 changes: 42 additions & 0 deletions GLTF/test/src/GLTFAssetTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "GLTFAsset.h"
#include "GLTFAssetTest.h"

TEST(GLTFAssetTest, RemoveUnusedSemantics) {
GLTF::Asset* asset = new GLTF::Asset();

GLTF::Scene* scene = new GLTF::Scene();
asset->scenes.push_back(scene);
asset->scene = 0;

GLTF::Node* node = new GLTF::Node();
scene->nodes.push_back(node);

GLTF::Mesh* mesh = new GLTF::Mesh();
node->mesh = mesh;

GLTF::Primitive* primitive = new GLTF::Primitive();
mesh->primitives.push_back(primitive);

GLTF::Material* material = new GLTF::Material();
primitive->material = material;

// Add an unused texture coordinate attribute
primitive->attributes["TEXCOORD_0"] = NULL;

EXPECT_EQ(primitive->attributes.size(), 1);
asset->removeUnusedSemantics();
EXPECT_EQ(primitive->attributes.size(), 0);

// Add an unused and a used texture coordinaate
primitive->attributes["TEXCOORD_0"] = NULL;
primitive->attributes["TEXCOORD_1"] = (GLTF::Accessor*)1;

material->values->ambientTexture = new GLTF::Texture();
material->values->ambientTexCoord = 1;

EXPECT_EQ(primitive->attributes.size(), 2);
asset->removeUnusedSemantics();
EXPECT_EQ(primitive->attributes.size(), 1);
EXPECT_EQ(primitive->attributes["TEXCOORD_0"], (GLTF::Accessor*)1);
EXPECT_EQ(material->values->ambientTexCoord, 0);
}
2 changes: 2 additions & 0 deletions include/COLLADA2GLTFWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace COLLADA2GLTF {
std::map<COLLADAFW::UniqueId, std::map<int, std::set<GLTF::Primitive*>>> _meshMaterialPrimitiveMapping;
std::map<COLLADAFW::UniqueId, GLTF::MaterialCommon::Light*> _lightInstances;
std::map<COLLADAFW::UniqueId, std::map<GLTF::Primitive*, std::vector<unsigned int>>> _meshPositionMapping;
std::map<GLTF::Mesh*, std::map<unsigned int, unsigned int>> _meshTexCoordSetMapping;
std::map<COLLADAFW::UniqueId, GLTF::Skin*> _skinInstances;
std::map<COLLADAFW::UniqueId, GLTF::Node*> _animatedNodes;
std::map<COLLADAFW::UniqueId, float> _originalRotationAngles;
Expand All @@ -38,6 +39,7 @@ namespace COLLADA2GLTF {
std::map<COLLADAFW::UniqueId, GLTF::Mesh*> _skinnedMeshes;
std::map<COLLADAFW::UniqueId, GLTF::Image*> _images;
std::map<COLLADAFW::UniqueId, std::tuple<std::vector<float>, std::vector<float>>> _animationData;
std::map<COLLADAFW::UniqueId, std::map<std::string, GLTF::Texture*>> _effectTextureMapping;

bool writeNodeToGroup(std::vector<GLTF::Node*>* group, const COLLADAFW::Node* node);
bool writeNodesToGroup(std::vector<GLTF::Node*>* group, const COLLADAFW::NodePointerArray& nodes);
Expand Down
37 changes: 34 additions & 3 deletions src/COLLADA2GLTFWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ bool COLLADA2GLTF::Writer::writeNodeToGroup(std::vector<GLTF::Node*>* group, con
node->mesh = skinnedMesh;
}

const COLLADAFW::MaterialBindingArray &materialBindings = instanceController->getMaterialBindings();
const COLLADAFW::MaterialBindingArray& materialBindings = instanceController->getMaterialBindings();
for (size_t j = 0; j < materialBindings.getCount(); j++) {
COLLADAFW::MaterialBinding materialBinding = materialBindings[j];
GLTF::Primitive* primitive = skinnedMesh->primitives[j];
Expand All @@ -262,7 +262,6 @@ bool COLLADA2GLTF::Writer::writeNodeToGroup(std::vector<GLTF::Node*>* group, con
GLTF::MaterialCommon* materialCommon = (GLTF::MaterialCommon*)material;
materialCommon->jointCount = _skinJointNodes[uniqueId].size();
}
primitive->material = material;
}

for (const COLLADABU::URI& skeletonURI : instanceController->skeletons()) {
Expand Down Expand Up @@ -315,11 +314,32 @@ bool COLLADA2GLTF::Writer::writeNodeToGroup(std::vector<GLTF::Node*>* group, con
std::map<COLLADAFW::UniqueId, GLTF::Mesh*>::iterator iter = _meshInstances.find(objectId);
if (iter != _meshInstances.end()) {
GLTF::Mesh* mesh = iter->second;
std::map<unsigned int, unsigned int> texCoordSetMapping = _meshTexCoordSetMapping[mesh];
for (size_t j = 0; j < materialBindings.getCount(); j++) {
COLLADAFW::MaterialBinding materialBinding = materialBindings[j];
COLLADAFW::UniqueId materialId = materialBinding.getReferencedMaterial();
COLLADAFW::UniqueId effectId = this->_materialEffects[materialId];
GLTF::Material* material = _effectInstances[effectId];
std::map<std::string, GLTF::Texture*> textureMapping = _effectTextureMapping[effectId];
// Assign maps
const COLLADAFW::TextureCoordinateBindingArray& texCoordBindings = materialBinding.getTextureCoordinateBindingArray();
for (size_t k = 0; k < texCoordBindings.getCount(); k++) {
COLLADAFW::TextureCoordinateBinding texCoordBinding = texCoordBindings[k];

GLTF::Texture* texture = textureMapping[texCoordBinding.getSemantic()];
GLTF::MaterialCommon* materialCommon = (GLTF::MaterialCommon*)material;
size_t index = texCoordSetMapping[texCoordBinding.getSetIndex()];

if (materialCommon->values->ambientTexture == texture) {
materialCommon->values->ambientTexCoord = index;
} else if (materialCommon->values->diffuseTexture == texture) {
materialCommon->values->diffuseTexCoord = index;
} else if (materialCommon->values->emissionTexture == texture) {
materialCommon->values->emissionTexCoord = index;
} else if (materialCommon->values->specularTexture == texture) {
materialCommon->values->specularTexCoord = index;
}
}
for (GLTF::Primitive* primitive : primitiveMaterialMapping[materialBinding.getMaterialId()]) {
if (primitive->material != NULL && primitive->material != material) {
// This mesh primitive has a different material from a previous instance, clone the mesh and primitives
Expand Down Expand Up @@ -513,6 +533,7 @@ bool COLLADA2GLTF::Writer::writeMesh(const COLLADAFW::Mesh* colladaMesh) {

const COLLADAFW::MeshPrimitiveArray& meshPrimitives = colladaMesh->getMeshPrimitives();
std::map<int, std::set<GLTF::Primitive*>> primitiveMaterialMapping;
std::map<unsigned int, unsigned int> texCoordSetMapping;
size_t meshPrimitivesCount = meshPrimitives.getCount();
if (meshPrimitivesCount > 0) {
// Create primitives
Expand Down Expand Up @@ -603,6 +624,7 @@ bool COLLADA2GLTF::Writer::writeMesh(const COLLADAFW::Mesh* colladaMesh) {
size_t uvCoordIndicesArrayCount = uvCoordIndicesArray.getCount();
for (size_t j = 0; j < uvCoordIndicesArrayCount; j++) {
semantic = "TEXCOORD_" + std::to_string(j);
texCoordSetMapping[uvCoordIndicesArray[j]->getSetIndex()] = j;
buildAttributes[semantic] = std::vector<float>();
semanticIndices[semantic] = uvCoordIndicesArray[j]->getIndices().getData();
semanticData[semantic] = &colladaMesh->getUVCoords();
Expand Down Expand Up @@ -750,6 +772,7 @@ bool COLLADA2GLTF::Writer::writeMesh(const COLLADAFW::Mesh* colladaMesh) {
}
_meshMaterialPrimitiveMapping[uniqueId] = primitiveMaterialMapping;
_meshPositionMapping[uniqueId] = positionMapping;
_meshTexCoordSetMapping[mesh] = texCoordSetMapping;
_meshInstances[uniqueId] = mesh;
return true;
}
Expand Down Expand Up @@ -902,6 +925,9 @@ bool COLLADA2GLTF::Writer::writeEffect(const COLLADAFW::Effect* effect) {

if (commonEffects.getCount() > 0) {
GLTF::MaterialCommon* material = new GLTF::MaterialCommon();
COLLADAFW::UniqueId effectId = effect->getUniqueId();
std::map<std::string, GLTF::Texture*> textureMapping;

material->stringId = effect->getOriginalId();
material->name = effect->getName();
if (material->name == "") {
Expand Down Expand Up @@ -931,6 +957,7 @@ bool COLLADA2GLTF::Writer::writeEffect(const COLLADAFW::Effect* effect) {
COLLADAFW::ColorOrTexture ambient = effectCommon->getAmbient();
if (ambient.isTexture()) {
material->values->ambientTexture = fromColladaTexture(effectCommon, ambient.getTexture());
textureMapping[ambient.getTexture().getTexcoord()] = material->values->ambientTexture;
}
else if (ambient.isColor()) {
material->values->ambient = new float[4];
Expand All @@ -941,6 +968,7 @@ bool COLLADA2GLTF::Writer::writeEffect(const COLLADAFW::Effect* effect) {
COLLADAFW::ColorOrTexture diffuse = effectCommon->getDiffuse();
if (diffuse.isTexture()) {
material->values->diffuseTexture = fromColladaTexture(effectCommon, diffuse.getTexture());
textureMapping[diffuse.getTexture().getTexcoord()] = material->values->diffuseTexture;
if (lockAmbientDiffuse) {
material->values->ambientTexture = material->values->diffuseTexture;
}
Expand All @@ -956,6 +984,7 @@ bool COLLADA2GLTF::Writer::writeEffect(const COLLADAFW::Effect* effect) {
COLLADAFW::ColorOrTexture emission = effectCommon->getEmission();
if (emission.isTexture()) {
material->values->emissionTexture = fromColladaTexture(effectCommon, emission.getTexture());
textureMapping[emission.getTexture().getTexcoord()] = material->values->emissionTexture;
}
else if (emission.isColor()) {
material->values->emission = new float[4];
Expand All @@ -965,6 +994,7 @@ bool COLLADA2GLTF::Writer::writeEffect(const COLLADAFW::Effect* effect) {
COLLADAFW::ColorOrTexture specular = effectCommon->getSpecular();
if (specular.isTexture()) {
material->values->specularTexture = fromColladaTexture(effectCommon, specular.getTexture());
textureMapping[specular.getTexture().getTexcoord()] = material->values->specularTexture;
}
else if (specular.isColor()) {
material->values->specular = new float[4];
Expand Down Expand Up @@ -999,7 +1029,8 @@ bool COLLADA2GLTF::Writer::writeEffect(const COLLADAFW::Effect* effect) {
material->doubleSided = true;
}

this->_effectInstances[effect->getUniqueId()] = material;
_effectTextureMapping[effectId] = textureMapping;
_effectInstances[effectId] = material;
}

return true;
Expand Down

0 comments on commit 078f05f

Please sign in to comment.