Merge branch 'master' into fix_gltf2_export_componentType_error

pull/1925/head
Kim Kulling 2018-05-06 19:39:37 +02:00 committed by GitHub
commit 327a43c26f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 381 additions and 300 deletions

View File

@ -208,8 +208,15 @@ OPTION(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_
# macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader # macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader
# this way selective loaders can be compiled (reduces filesize + compile time) # this way selective loaders can be compiled (reduces filesize + compile time)
MACRO(ADD_ASSIMP_IMPORTER name) MACRO(ADD_ASSIMP_IMPORTER name)
OPTION(ASSIMP_BUILD_${name}_IMPORTER "build the ${name} importer" ${ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT}) IF (ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT)
IF(ASSIMP_BUILD_${name}_IMPORTER) set(ASSIMP_IMPORTER_ENABLED TRUE)
IF (DEFINED ASSIMP_BUILD_${name}_IMPORTER AND NOT ASSIMP_BUILD_${name}_IMPORTER)
set(ASSIMP_IMPORTER_ENABLED FALSE)
ENDIF ()
ELSE ()
set(ASSIMP_IMPORTER_ENABLED ${ASSIMP_BUILD_${name}_IMPORTER})
ENDIF ()
IF (ASSIMP_IMPORTER_ENABLED)
LIST(APPEND ASSIMP_LOADER_SRCS ${ARGN}) LIST(APPEND ASSIMP_LOADER_SRCS ${ARGN})
SET(ASSIMP_IMPORTERS_ENABLED "${ASSIMP_IMPORTERS_ENABLED} ${name}") SET(ASSIMP_IMPORTERS_ENABLED "${ASSIMP_IMPORTERS_ENABLED} ${name}")
SET(${name}_SRCS ${ARGN}) SET(${name}_SRCS ${ARGN})

View File

@ -154,9 +154,9 @@ Exporter::ExportFormatEntry gExporters[] =
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf2", &ExportSceneGLTF2, Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb2", &ExportSceneGLB2, Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
#endif #endif

View File

@ -874,7 +874,7 @@ void Converter::ConvertModel( const Model& model, aiNode& nd, const aiMatrix4x4&
const MeshGeometry* const mesh = dynamic_cast< const MeshGeometry* >( geo ); const MeshGeometry* const mesh = dynamic_cast< const MeshGeometry* >( geo );
if ( mesh ) { if ( mesh ) {
const std::vector<unsigned int>& indices = ConvertMesh( *mesh, model, node_global_transform ); const std::vector<unsigned int>& indices = ConvertMesh( *mesh, model, node_global_transform, nd);
std::copy( indices.begin(), indices.end(), std::back_inserter( meshes ) ); std::copy( indices.begin(), indices.end(), std::back_inserter( meshes ) );
} }
else { else {
@ -891,7 +891,7 @@ void Converter::ConvertModel( const Model& model, aiNode& nd, const aiMatrix4x4&
} }
std::vector<unsigned int> Converter::ConvertMesh( const MeshGeometry& mesh, const Model& model, std::vector<unsigned int> Converter::ConvertMesh( const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform ) const aiMatrix4x4& node_global_transform, aiNode& nd)
{ {
std::vector<unsigned int> temp; std::vector<unsigned int> temp;
@ -915,17 +915,17 @@ std::vector<unsigned int> Converter::ConvertMesh( const MeshGeometry& mesh, cons
const MatIndexArray::value_type base = mindices[ 0 ]; const MatIndexArray::value_type base = mindices[ 0 ];
for( MatIndexArray::value_type index : mindices ) { for( MatIndexArray::value_type index : mindices ) {
if ( index != base ) { if ( index != base ) {
return ConvertMeshMultiMaterial( mesh, model, node_global_transform ); return ConvertMeshMultiMaterial( mesh, model, node_global_transform, nd);
} }
} }
} }
// faster code-path, just copy the data // faster code-path, just copy the data
temp.push_back( ConvertMeshSingleMaterial( mesh, model, node_global_transform ) ); temp.push_back( ConvertMeshSingleMaterial( mesh, model, node_global_transform, nd) );
return temp; return temp;
} }
aiMesh* Converter::SetupEmptyMesh( const MeshGeometry& mesh ) aiMesh* Converter::SetupEmptyMesh( const MeshGeometry& mesh, aiNode& nd)
{ {
aiMesh* const out_mesh = new aiMesh(); aiMesh* const out_mesh = new aiMesh();
meshes.push_back( out_mesh ); meshes.push_back( out_mesh );
@ -940,15 +940,19 @@ aiMesh* Converter::SetupEmptyMesh( const MeshGeometry& mesh )
if ( name.length() ) { if ( name.length() ) {
out_mesh->mName.Set( name ); out_mesh->mName.Set( name );
} }
else
{
out_mesh->mName = nd.mName;
}
return out_mesh; return out_mesh;
} }
unsigned int Converter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, const Model& model, unsigned int Converter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform ) const aiMatrix4x4& node_global_transform, aiNode& nd)
{ {
const MatIndexArray& mindices = mesh.GetMaterialIndices(); const MatIndexArray& mindices = mesh.GetMaterialIndices();
aiMesh* const out_mesh = SetupEmptyMesh( mesh ); aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd);
const std::vector<aiVector3D>& vertices = mesh.GetVertices(); const std::vector<aiVector3D>& vertices = mesh.GetVertices();
const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts(); const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
@ -1072,7 +1076,7 @@ unsigned int Converter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, con
} }
std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model, std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform ) const aiMatrix4x4& node_global_transform, aiNode& nd)
{ {
const MatIndexArray& mindices = mesh.GetMaterialIndices(); const MatIndexArray& mindices = mesh.GetMaterialIndices();
ai_assert( mindices.size() ); ai_assert( mindices.size() );
@ -1083,7 +1087,7 @@ std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometr
for( MatIndexArray::value_type index : mindices ) { for( MatIndexArray::value_type index : mindices ) {
if ( had.find( index ) == had.end() ) { if ( had.find( index ) == had.end() ) {
indices.push_back( ConvertMeshMultiMaterial( mesh, model, index, node_global_transform ) ); indices.push_back( ConvertMeshMultiMaterial( mesh, model, index, node_global_transform, nd) );
had.insert( index ); had.insert( index );
} }
} }
@ -1093,9 +1097,10 @@ std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometr
unsigned int Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model, unsigned int Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model,
MatIndexArray::value_type index, MatIndexArray::value_type index,
const aiMatrix4x4& node_global_transform ) const aiMatrix4x4& node_global_transform,
aiNode& nd)
{ {
aiMesh* const out_mesh = SetupEmptyMesh( mesh ); aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd);
const MatIndexArray& mindices = mesh.GetMaterialIndices(); const MatIndexArray& mindices = mesh.GetMaterialIndices();
const std::vector<aiVector3D>& vertices = mesh.GetVertices(); const std::vector<aiVector3D>& vertices = mesh.GetVertices();

View File

@ -172,23 +172,23 @@ private:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
std::vector<unsigned int> ConvertMesh(const MeshGeometry& mesh, const Model& model, std::vector<unsigned int> ConvertMesh(const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform); const aiMatrix4x4& node_global_transform, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiMesh* SetupEmptyMesh(const MeshGeometry& mesh); aiMesh* SetupEmptyMesh(const MeshGeometry& mesh, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model, unsigned int ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform); const aiMatrix4x4& node_global_transform, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::vector<unsigned int> ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, std::vector<unsigned int> ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform); const aiMatrix4x4& node_global_transform, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, unsigned int ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
MatIndexArray::value_type index, MatIndexArray::value_type index,
const aiMatrix4x4& node_global_transform); const aiMatrix4x4& node_global_transform, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */ static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */

View File

@ -108,6 +108,125 @@ void JoinVerticesProcess::Execute( aiScene* pScene)
pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
} }
namespace {
bool areVerticesEqual(const Vertex &lhs, const Vertex &rhs, bool complex)
{
// A little helper to find locally close vertices faster.
// Try to reuse the lookup table from the last step.
const static float epsilon = 1e-5f;
// Squared because we check against squared length of the vector difference
static const float squareEpsilon = epsilon * epsilon;
// Square compare is useful for animeshes vertexes compare
if ((lhs.position - rhs.position).SquareLength() > squareEpsilon) {
return false;
}
// We just test the other attributes even if they're not present in the mesh.
// In this case they're initialized to 0 so the comparison succeeds.
// By this method the non-present attributes are effectively ignored in the comparison.
if ((lhs.normal - rhs.normal).SquareLength() > squareEpsilon) {
return false;
}
if ((lhs.texcoords[0] - rhs.texcoords[0]).SquareLength() > squareEpsilon) {
return false;
}
if ((lhs.tangent - rhs.tangent).SquareLength() > squareEpsilon) {
return false;
}
if ((lhs.bitangent - rhs.bitangent).SquareLength() > squareEpsilon) {
return false;
}
// Usually we won't have vertex colors or multiple UVs, so we can skip from here
// Actually this increases runtime performance slightly, at least if branch
// prediction is on our side.
if (complex) {
for (int i = 0; i < 8; i++) {
if (i > 0 && (lhs.texcoords[i] - rhs.texcoords[i]).SquareLength() > squareEpsilon) {
return false;
}
if (GetColorDifference(lhs.colors[i], rhs.colors[i]) > squareEpsilon) {
return false;
}
}
}
return true;
}
template<class XMesh>
void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
// replace vertex data with the unique data sets
pMesh->mNumVertices = (unsigned int)uniqueVertices.size();
// ----------------------------------------------------------------------------
// NOTE - we're *not* calling Vertex::SortBack() because it would check for
// presence of every single vertex component once PER VERTEX. And our CPU
// dislikes branches, even if they're easily predictable.
// ----------------------------------------------------------------------------
// Position, if present (check made for aiAnimMesh)
if (pMesh->mVertices)
{
delete [] pMesh->mVertices;
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mVertices[a] = uniqueVertices[a].position;
}
}
// Normals, if present
if (pMesh->mNormals)
{
delete [] pMesh->mNormals;
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mNormals[a] = uniqueVertices[a].normal;
}
}
// Tangents, if present
if (pMesh->mTangents)
{
delete [] pMesh->mTangents;
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mTangents[a] = uniqueVertices[a].tangent;
}
}
// Bitangents as well
if (pMesh->mBitangents)
{
delete [] pMesh->mBitangents;
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mBitangents[a] = uniqueVertices[a].bitangent;
}
}
// Vertex colors
for (unsigned int a = 0; pMesh->HasVertexColors(a); a++)
{
delete [] pMesh->mColors[a];
pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
pMesh->mColors[a][b] = uniqueVertices[b].colors[a];
}
}
// Texture coords
for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++)
{
delete [] pMesh->mTextureCoords[a];
pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
for (unsigned int b = 0; b < pMesh->mNumVertices; b++) {
pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a];
}
}
}
} // namespace
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Unites identical vertices in the given mesh // Unites identical vertices in the given mesh
int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
@ -132,9 +251,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff"); static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff");
std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff); std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
// A little helper to find locally close vertices faster.
// Try to reuse the lookup table from the last step.
const static float epsilon = 1e-5f;
// float posEpsilonSqr; // float posEpsilonSqr;
SpatialSort* vertexFinder = NULL; SpatialSort* vertexFinder = NULL;
SpatialSort _vertexFinder; SpatialSort _vertexFinder;
@ -156,9 +272,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// posEpsilonSqr = ComputePositionEpsilon(pMesh); // posEpsilonSqr = ComputePositionEpsilon(pMesh);
} }
// Squared because we check against squared length of the vector difference
static const float squareEpsilon = epsilon * epsilon;
// Again, better waste some bytes than a realloc ... // Again, better waste some bytes than a realloc ...
std::vector<unsigned int> verticesFound; std::vector<unsigned int> verticesFound;
verticesFound.reserve(10); verticesFound.reserve(10);
@ -166,6 +279,16 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// Run an optimized code path if we don't have multiple UVs or vertex colors. // Run an optimized code path if we don't have multiple UVs or vertex colors.
// This should yield false in more than 99% of all imports ... // This should yield false in more than 99% of all imports ...
const bool complex = ( pMesh->GetNumColorChannels() > 0 || pMesh->GetNumUVChannels() > 1); const bool complex = ( pMesh->GetNumColorChannels() > 0 || pMesh->GetNumUVChannels() > 1);
const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
// We'll never have more vertices afterwards.
std::vector<std::vector<Vertex>> uniqueAnimatedVertices;
if (hasAnimMeshes) {
uniqueAnimatedVertices.resize(pMesh->mNumAnimMeshes);
for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices);
}
}
// Now check each vertex if it brings something new to the table // Now check each vertex if it brings something new to the table
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
@ -178,74 +301,32 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// check all unique vertices close to the position if this vertex is already present among them // check all unique vertices close to the position if this vertex is already present among them
for( unsigned int b = 0; b < verticesFound.size(); b++) { for( unsigned int b = 0; b < verticesFound.size(); b++) {
const unsigned int vidx = verticesFound[b]; const unsigned int vidx = verticesFound[b];
const unsigned int uidx = replaceIndex[ vidx]; const unsigned int uidx = replaceIndex[ vidx];
if( uidx & 0x80000000) if( uidx & 0x80000000)
continue; continue;
const Vertex& uv = uniqueVertices[ uidx]; const Vertex& uv = uniqueVertices[ uidx];
// Position mismatch is impossible - the vertex finder already discarded all non-matching positions
// We just test the other attributes even if they're not present in the mesh. if (!areVerticesEqual(v, uv, complex)) {
// In this case they're initialized to 0 so the comparison succeeds.
// By this method the non-present attributes are effectively ignored in the comparison.
if( (uv.normal - v.normal).SquareLength() > squareEpsilon)
continue;
if( (uv.texcoords[0] - v.texcoords[0]).SquareLength() > squareEpsilon)
continue;
if( (uv.tangent - v.tangent).SquareLength() > squareEpsilon)
continue;
if( (uv.bitangent - v.bitangent).SquareLength() > squareEpsilon)
continue; continue;
}
// Usually we won't have vertex colors or multiple UVs, so we can skip from here if (hasAnimMeshes) {
// Actually this increases runtime performance slightly, at least if branch // If given vertex is animated, then it has to be preserver 1 to 1 (base mesh and animated mesh require same topology)
// prediction is on our side. // NOTE: not doing this totaly breaks anim meshes as they don't have their own faces (they use pMesh->mFaces)
if (complex){ bool breaksAnimMesh = false;
// manually unrolled because continue wouldn't work as desired in an inner loop, for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
// also because some compilers seem to fail the task. Colors and UV coords const Vertex& animatedUV = uniqueAnimatedVertices[animMeshIndex][ uidx];
// are interleaved since the higher entries are most likely to be Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a);
// zero and thus useless. By interleaving the arrays, vertices are, if (!areVerticesEqual(aniMeshVertex, animatedUV, complex)) {
// on average, rejected earlier. breaksAnimMesh = true;
break;
if( (uv.texcoords[1] - v.texcoords[1]).SquareLength() > squareEpsilon) }
continue; }
if( GetColorDifference( uv.colors[0], v.colors[0]) > squareEpsilon) if (breaksAnimMesh) {
continue;
if( (uv.texcoords[2] - v.texcoords[2]).SquareLength() > squareEpsilon)
continue;
if( GetColorDifference( uv.colors[1], v.colors[1]) > squareEpsilon)
continue;
if( (uv.texcoords[3] - v.texcoords[3]).SquareLength() > squareEpsilon)
continue;
if( GetColorDifference( uv.colors[2], v.colors[2]) > squareEpsilon)
continue;
if( (uv.texcoords[4] - v.texcoords[4]).SquareLength() > squareEpsilon)
continue;
if( GetColorDifference( uv.colors[3], v.colors[3]) > squareEpsilon)
continue;
if( (uv.texcoords[5] - v.texcoords[5]).SquareLength() > squareEpsilon)
continue;
if( GetColorDifference( uv.colors[4], v.colors[4]) > squareEpsilon)
continue;
if( (uv.texcoords[6] - v.texcoords[6]).SquareLength() > squareEpsilon)
continue;
if( GetColorDifference( uv.colors[5], v.colors[5]) > squareEpsilon)
continue;
if( (uv.texcoords[7] - v.texcoords[7]).SquareLength() > squareEpsilon)
continue;
if( GetColorDifference( uv.colors[6], v.colors[6]) > squareEpsilon)
continue;
if( GetColorDifference( uv.colors[7], v.colors[7]) > squareEpsilon)
continue; continue;
}
} }
// we're still here -> this vertex perfectly matches our given vertex // we're still here -> this vertex perfectly matches our given vertex
@ -264,6 +345,12 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// no unique vertex matches it up to now -> so add it // no unique vertex matches it up to now -> so add it
replaceIndex[a] = (unsigned int)uniqueVertices.size(); replaceIndex[a] = (unsigned int)uniqueVertices.size();
uniqueVertices.push_back( v); uniqueVertices.push_back( v);
if (hasAnimMeshes) {
for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a);
uniqueAnimatedVertices[animMeshIndex].push_back(aniMeshVertex);
}
}
} }
} }
@ -281,64 +368,10 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
); );
} }
// replace vertex data with the unique data sets updateXMeshVertices(pMesh, uniqueVertices);
pMesh->mNumVertices = (unsigned int)uniqueVertices.size(); if (hasAnimMeshes) {
for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
// ---------------------------------------------------------------------------- updateXMeshVertices(pMesh->mAnimMeshes[animMeshIndex], uniqueAnimatedVertices[animMeshIndex]);
// NOTE - we're *not* calling Vertex::SortBack() because it would check for
// presence of every single vertex component once PER VERTEX. And our CPU
// dislikes branches, even if they're easily predictable.
// ----------------------------------------------------------------------------
// Position
delete [] pMesh->mVertices;
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
pMesh->mVertices[a] = uniqueVertices[a].position;
// Normals, if present
if( pMesh->mNormals)
{
delete [] pMesh->mNormals;
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mNormals[a] = uniqueVertices[a].normal;
}
}
// Tangents, if present
if( pMesh->mTangents)
{
delete [] pMesh->mTangents;
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mTangents[a] = uniqueVertices[a].tangent;
}
}
// Bitangents as well
if( pMesh->mBitangents)
{
delete [] pMesh->mBitangents;
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
pMesh->mBitangents[a] = uniqueVertices[a].bitangent;
}
}
// Vertex colors
for( unsigned int a = 0; pMesh->HasVertexColors(a); a++)
{
delete [] pMesh->mColors[a];
pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
pMesh->mColors[a][b] = uniqueVertices[b].colors[a];
}
}
// Texture coords
for( unsigned int a = 0; pMesh->HasTextureCoords(a); a++)
{
delete [] pMesh->mTextureCoords[a];
pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a];
} }
} }

View File

@ -114,14 +114,13 @@ static const std::string MaterialExt = ".mtl";
ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMtl) ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMtl)
: filename(_filename) : filename(_filename)
, pScene(pScene) , pScene(pScene)
, vp()
, vn() , vn()
, vt() , vt()
, vc() , vp()
, mVpMap() , useVc(false)
, mVnMap() , mVnMap()
, mVtMap() , mVtMap()
, mVcMap() , mVpMap()
, mMeshes() , mMeshes()
, endl("\n") { , endl("\n") {
// make sure that all formatting happens using the standard, C locale and not the user's current locale // make sure that all formatting happens using the standard, C locale and not the user's current locale
@ -268,27 +267,22 @@ void ObjExporter::WriteGeometryFile(bool noMtl) {
AddNode(pScene->mRootNode, mBase); AddNode(pScene->mRootNode, mBase);
// write vertex positions with colors, if any // write vertex positions with colors, if any
mVpMap.getVectors( vp ); mVpMap.getKeys( vp );
mVcMap.getColors( vc ); if ( !useVc ) {
if ( vc.empty() ) {
mOutput << "# " << vp.size() << " vertex positions" << endl; mOutput << "# " << vp.size() << " vertex positions" << endl;
for ( const aiVector3D& v : vp ) { for ( const vertexData& v : vp ) {
mOutput << "v " << v.x << " " << v.y << " " << v.z << endl; mOutput << "v " << v.vp.x << " " << v.vp.y << " " << v.vp.z << endl;
} }
} else { } else {
mOutput << "# " << vp.size() << " vertex positions and colors" << endl; mOutput << "# " << vp.size() << " vertex positions and colors" << endl;
size_t colIdx = 0; for ( const vertexData& v : vp ) {
for ( const aiVector3D& v : vp ) { mOutput << "v " << v.vp.x << " " << v.vp.y << " " << v.vp.z << " " << v.vc.r << " " << v.vc.g << " " << v.vc.b << endl;
if ( colIdx < vc.size() ) {
mOutput << "v " << v.x << " " << v.y << " " << v.z << " " << vc[ colIdx ].r << " " << vc[ colIdx ].g << " " << vc[ colIdx ].b << endl;
}
++colIdx;
} }
} }
mOutput << endl; mOutput << endl;
// write uv coordinates // write uv coordinates
mVtMap.getVectors(vt); mVtMap.getKeys(vt);
mOutput << "# " << vt.size() << " UV coordinates" << endl; mOutput << "# " << vt.size() << " UV coordinates" << endl;
for(const aiVector3D& v : vt) { for(const aiVector3D& v : vt) {
mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl; mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl;
@ -296,7 +290,7 @@ void ObjExporter::WriteGeometryFile(bool noMtl) {
mOutput << endl; mOutput << endl;
// write vertex normals // write vertex normals
mVnMap.getVectors(vn); mVnMap.getKeys(vn);
mOutput << "# " << vn.size() << " vertex normals" << endl; mOutput << "# " << vn.size() << " vertex normals" << endl;
for(const aiVector3D& v : vn) { for(const aiVector3D& v : vn) {
mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl; mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl;
@ -337,54 +331,15 @@ void ObjExporter::WriteGeometryFile(bool noMtl) {
} }
} }
// ------------------------------------------------------------------------------------------------
int ObjExporter::vecIndexMap::getIndex(const aiVector3D& vec) {
vecIndexMap::dataType::iterator vertIt = vecMap.find(vec);
// vertex already exists, so reference it
if(vertIt != vecMap.end()){
return vertIt->second;
}
vecMap[vec] = mNextIndex;
int ret = mNextIndex;
mNextIndex++;
return ret;
}
// ------------------------------------------------------------------------------------------------
void ObjExporter::vecIndexMap::getVectors( std::vector<aiVector3D>& vecs ) {
vecs.resize(vecMap.size());
for(vecIndexMap::dataType::iterator it = vecMap.begin(); it != vecMap.end(); ++it){
vecs[it->second-1] = it->first;
}
}
// ------------------------------------------------------------------------------------------------
int ObjExporter::colIndexMap::getIndex( const aiColor4D& col ) {
colIndexMap::dataType::iterator vertIt = colMap.find( col );
// vertex already exists, so reference it
if ( vertIt != colMap.end() ) {
return vertIt->second;
}
colMap[ col ] = mNextIndex;
int ret = mNextIndex;
mNextIndex++;
return ret;
}
// ------------------------------------------------------------------------------------------------
void ObjExporter::colIndexMap::getColors( std::vector<aiColor4D> &colors ) {
colors.resize( colMap.size() );
for ( colIndexMap::dataType::iterator it = colMap.begin(); it != colMap.end(); ++it ) {
colors[ it->second - 1 ] = it->first;
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) { void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) {
mMeshes.push_back(MeshInstance() ); mMeshes.push_back(MeshInstance() );
MeshInstance& mesh = mMeshes.back(); MeshInstance& mesh = mMeshes.back();
if ( nullptr != m->mColors[ 0 ] ) {
useVc = true;
}
mesh.name = std::string( name.data, name.length ); mesh.name = std::string( name.data, name.length );
mesh.matname = GetMaterialName(m->mMaterialIndex); mesh.matname = GetMaterialName(m->mMaterialIndex);
@ -410,7 +365,13 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4
const unsigned int idx = f.mIndices[a]; const unsigned int idx = f.mIndices[a];
aiVector3D vert = mat * m->mVertices[idx]; aiVector3D vert = mat * m->mVertices[idx];
face.indices[a].vp = mVpMap.getIndex(vert);
if ( nullptr != m->mColors[ 0 ] ) {
aiColor4D col4 = m->mColors[ 0 ][ idx ];
face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(col4.r, col4.g, col4.b)});
} else {
face.indices[a].vp = mVpMap.getIndex({vert, aiColor3D(0,0,0)});
}
if (m->mNormals) { if (m->mNormals) {
aiVector3D norm = aiMatrix3x3(mat) * m->mNormals[idx]; aiVector3D norm = aiMatrix3x3(mat) * m->mNormals[idx];
@ -419,13 +380,6 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4
face.indices[a].vn = 0; face.indices[a].vn = 0;
} }
if ( nullptr != m->mColors[ 0 ] ) {
aiColor4D col4 = m->mColors[ 0 ][ idx ];
face.indices[ a ].vc = mVcMap.getIndex( col4 );
} else {
face.indices[ a ].vc = 0;
}
if ( m->mTextureCoords[ 0 ] ) { if ( m->mTextureCoords[ 0 ] ) {
face.indices[a].vt = mVtMap.getIndex(m->mTextureCoords[0][idx]); face.indices[a].vt = mVtMap.getIndex(m->mTextureCoords[0][idx]);
} else { } else {

View File

@ -77,13 +77,12 @@ private:
FaceVertex() FaceVertex()
: vp() : vp()
, vn() , vn()
, vt() , vt() {
, vc() {
// empty // empty
} }
// one-based, 0 means: 'does not exist' // one-based, 0 means: 'does not exist'
unsigned int vp, vn, vt, vc; unsigned int vp, vn, vt;
}; };
struct Face { struct Face {
@ -106,8 +105,37 @@ private:
private: private:
std::string filename; std::string filename;
const aiScene* const pScene; const aiScene* const pScene;
std::vector<aiVector3D> vp, vn, vt;
struct vertexData {
aiVector3D vp;
aiColor3D vc; // OBJ does not support 4D color
};
std::vector<aiVector3D> vn, vt;
std::vector<aiColor4D> vc; std::vector<aiColor4D> vc;
std::vector<vertexData> vp;
bool useVc;
struct vertexDataCompare {
bool operator() ( const vertexData& a, const vertexData& b ) const {
// position
if (a.vp.x < b.vp.x) return true;
if (a.vp.x > b.vp.x) return false;
if (a.vp.y < b.vp.y) return true;
if (a.vp.y > b.vp.y) return false;
if (a.vp.z < b.vp.z) return true;
if (a.vp.z > b.vp.z) return false;
// color
if (a.vc.r < b.vc.r) return true;
if (a.vc.r > b.vc.r) return false;
if (a.vc.g < b.vc.g) return true;
if (a.vc.g > b.vc.g) return false;
if (a.vc.b < b.vc.b) return true;
if (a.vc.b > b.vc.b) return false;
return false;
}
};
struct aiVectorCompare { struct aiVectorCompare {
bool operator() (const aiVector3D& a, const aiVector3D& b) const { bool operator() (const aiVector3D& a, const aiVector3D& b) const {
@ -120,52 +148,37 @@ private:
} }
}; };
struct aiColor4Compare { template <class T, class Compare = std::less<T>>
bool operator() ( const aiColor4D& a, const aiColor4D& b ) const { class indexMap {
if ( a.r < b.r ) return true;
if ( a.r > b.r ) return false;
if ( a.g < b.g ) return true;
if ( a.g > b.g ) return false;
if ( a.b < b.b ) return true;
if ( a.b > b.b ) return false;
if ( a.a < b.a ) return true;
if ( a.a > b.a ) return false;
return false;
}
};
class vecIndexMap {
int mNextIndex; int mNextIndex;
typedef std::map<aiVector3D, int, aiVectorCompare> dataType; typedef std::map<T, int, Compare> dataType;
dataType vecMap; dataType vecMap;
public: public:
vecIndexMap() indexMap()
: mNextIndex(1) { : mNextIndex(1) {
// empty // empty
} }
int getIndex(const aiVector3D& vec); int getIndex(const T& key) {
void getVectors( std::vector<aiVector3D>& vecs ); typename dataType::iterator vertIt = vecMap.find(key);
// vertex already exists, so reference it
if(vertIt != vecMap.end()){
return vertIt->second;
}
return vecMap[key] = mNextIndex++;
};
void getKeys( std::vector<T>& keys ) {
keys.resize(vecMap.size());
for(typename dataType::iterator it = vecMap.begin(); it != vecMap.end(); ++it){
keys[it->second-1] = it->first;
}
};
}; };
class colIndexMap { indexMap<aiVector3D, aiVectorCompare> mVnMap, mVtMap;
int mNextIndex; indexMap<vertexData, vertexDataCompare> mVpMap;
typedef std::map<aiColor4D, int, aiColor4Compare> dataType;
dataType colMap;
public:
colIndexMap()
: mNextIndex( 1 ) {
// empty
}
int getIndex( const aiColor4D& col );
void getColors( std::vector<aiColor4D> &colors );
};
vecIndexMap mVpMap, mVnMap, mVtMap;
colIndexMap mVcMap;
std::vector<MeshInstance> mMeshes; std::vector<MeshInstance> mMeshes;
// this endl() doesn't flush() the stream // this endl() doesn't flush() the stream

View File

@ -194,16 +194,16 @@ PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool bina
for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) { for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) {
if (!c) { if (!c) {
mOutput << "property " << typeName << " r" << endl; mOutput << "property " << "uchar" << " red" << endl;
mOutput << "property " << typeName << " g" << endl; mOutput << "property " << "uchar" << " green" << endl;
mOutput << "property " << typeName << " b" << endl; mOutput << "property " << "uchar" << " blue" << endl;
mOutput << "property " << typeName << " a" << endl; mOutput << "property " << "uchar" << " alpha" << endl;
} }
else { else {
mOutput << "property " << typeName << " r" << c << endl; mOutput << "property " << "uchar" << " red" << c << endl;
mOutput << "property " << typeName << " g" << c << endl; mOutput << "property " << "uchar" << " green" << c << endl;
mOutput << "property " << typeName << " b" << c << endl; mOutput << "property " << "uchar" << " blue" << c << endl;
mOutput << "property " << typeName << " a" << c << endl; mOutput << "property " << "uchar" << " alpha" << c << endl;
} }
} }
@ -288,13 +288,13 @@ void PlyExporter::WriteMeshVerts(const aiMesh* m, unsigned int components)
for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) { for (unsigned int n = PLY_EXPORT_HAS_COLORS, c = 0; (components & n) && c != AI_MAX_NUMBER_OF_COLOR_SETS; n <<= 1, ++c) {
if (m->HasVertexColors(c)) { if (m->HasVertexColors(c)) {
mOutput << mOutput <<
" " << m->mColors[c][i].r << " " << (int)(m->mColors[c][i].r * 255) <<
" " << m->mColors[c][i].g << " " << (int)(m->mColors[c][i].g * 255) <<
" " << m->mColors[c][i].b << " " << (int)(m->mColors[c][i].b * 255) <<
" " << m->mColors[c][i].a; " " << (int)(m->mColors[c][i].a * 255);
} }
else { else {
mOutput << " -1.0 -1.0 -1.0 -1.0"; mOutput << " 0 0 0";
} }
} }

View File

@ -85,8 +85,6 @@ void SortByPTypeProcess::SetupProperties(const Importer* pImp)
// Update changed meshes in all nodes // Update changed meshes in all nodes
void UpdateNodes(const std::vector<unsigned int>& replaceMeshIndex, aiNode* node) void UpdateNodes(const std::vector<unsigned int>& replaceMeshIndex, aiNode* node)
{ {
// std::vector<unsigned int>::const_iterator it;
if (node->mNumMeshes) if (node->mNumMeshes)
{ {
unsigned int newSize = 0; unsigned int newSize = 0;
@ -133,10 +131,8 @@ void UpdateNodes(const std::vector<unsigned int>& replaceMeshIndex, aiNode* node
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void SortByPTypeProcess::Execute( aiScene* pScene) void SortByPTypeProcess::Execute( aiScene* pScene) {
{ if ( 0 == pScene->mNumMeshes) {
if (!pScene->mNumMeshes)
{
ASSIMP_LOG_DEBUG("SortByPTypeProcess skipped, there are no meshes"); ASSIMP_LOG_DEBUG("SortByPTypeProcess skipped, there are no meshes");
return; return;
} }
@ -152,42 +148,38 @@ void SortByPTypeProcess::Execute( aiScene* pScene)
std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes*4,UINT_MAX); std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes*4,UINT_MAX);
std::vector<unsigned int>::iterator meshIdx = replaceMeshIndex.begin(); std::vector<unsigned int>::iterator meshIdx = replaceMeshIndex.begin();
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
{
aiMesh* const mesh = pScene->mMeshes[i]; aiMesh* const mesh = pScene->mMeshes[i];
ai_assert(0 != mesh->mPrimitiveTypes); ai_assert(0 != mesh->mPrimitiveTypes);
// if there's just one primitive type in the mesh there's nothing to do for us // if there's just one primitive type in the mesh there's nothing to do for us
unsigned int num = 0; unsigned int num = 0;
if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) {
{
++aiNumMeshesPerPType[0]; ++aiNumMeshesPerPType[0];
++num; ++num;
} }
if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) {
{
++aiNumMeshesPerPType[1]; ++aiNumMeshesPerPType[1];
++num; ++num;
} }
if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) {
{
++aiNumMeshesPerPType[2]; ++aiNumMeshesPerPType[2];
++num; ++num;
} }
if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON) if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON) {
{
++aiNumMeshesPerPType[3]; ++aiNumMeshesPerPType[3];
++num; ++num;
} }
if (1 == num) if (1 == num) {
{ if (!(configRemoveMeshes & mesh->mPrimitiveTypes)) {
if (!(configRemoveMeshes & mesh->mPrimitiveTypes)) *meshIdx = static_cast<unsigned int>( outMeshes.size() );
{
*meshIdx = (unsigned int) outMeshes.size();
outMeshes.push_back(mesh); outMeshes.push_back(mesh);
} else {
delete mesh;
pScene->mMeshes[ i ] = nullptr;
bAnyChanges = true;
} }
else bAnyChanges = true;
meshIdx += 4; meshIdx += 4;
continue; continue;
@ -195,14 +187,13 @@ void SortByPTypeProcess::Execute( aiScene* pScene)
bAnyChanges = true; bAnyChanges = true;
// reuse our current mesh arrays for the submesh // reuse our current mesh arrays for the submesh
// with the largest numer of primitives // with the largest number of primitives
unsigned int aiNumPerPType[4] = {0,0,0,0}; unsigned int aiNumPerPType[4] = {0,0,0,0};
aiFace* pFirstFace = mesh->mFaces; aiFace* pFirstFace = mesh->mFaces;
aiFace* const pLastFace = pFirstFace + mesh->mNumFaces; aiFace* const pLastFace = pFirstFace + mesh->mNumFaces;
unsigned int numPolyVerts = 0; unsigned int numPolyVerts = 0;
for (;pFirstFace != pLastFace; ++pFirstFace) for (;pFirstFace != pLastFace; ++pFirstFace) {
{
if (pFirstFace->mNumIndices <= 3) if (pFirstFace->mNumIndices <= 3)
++aiNumPerPType[pFirstFace->mNumIndices-1]; ++aiNumPerPType[pFirstFace->mNumIndices-1];
else else

View File

@ -890,6 +890,8 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode* n)
{ {
Ref<Node> node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node")); Ref<Node> node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node"));
node->name = n->mName.C_Str();
if (!n->mTransformation.IsIdentity()) { if (!n->mTransformation.IsIdentity()) {
node->matrix.isPresent = true; node->matrix.isPresent = true;
CopyValue(n->mTransformation, node->matrix.value); CopyValue(n->mTransformation, node->matrix.value);

View File

@ -134,6 +134,30 @@ public:
} }
} }
// ----------------------------------------------------------------------------
/** Extract a particular vertex from a anim mesh and interleave all components */
explicit Vertex(const aiAnimMesh* msh, unsigned int idx) {
ai_assert(idx < msh->mNumVertices);
position = msh->mVertices[idx];
if (msh->HasNormals()) {
normal = msh->mNormals[idx];
}
if (msh->HasTangentsAndBitangents()) {
tangent = msh->mTangents[idx];
bitangent = msh->mBitangents[idx];
}
for (unsigned int i = 0; msh->HasTextureCoords(i); ++i) {
texcoords[i] = msh->mTextureCoords[i][idx];
}
for (unsigned int i = 0; msh->HasVertexColors(i); ++i) {
colors[i] = msh->mColors[i][idx];
}
}
public: public:
Vertex& operator += (const Vertex& v) { Vertex& operator += (const Vertex& v) {

View File

@ -1,13 +1,13 @@
g cube g cube
v 0.0 0.0 0.0 124 110 120 v 0.0 0.0 0.0 0.48627 0.43137 0.47059
v 0.0 0.0 1.0 24 0 121 v 0.0 0.0 1.0 0.09412 0.00000 0.47451
v 0.0 1.0 0.0 4 0 44 v 0.0 1.0 0.0 0.01569 0.00000 0.17255
v 0.0 1.0 1.0 224 0 10 v 0.0 1.0 1.0 0.87843 0.00000 0.03922
v 1.0 0.0 0.0 24 200 25 v 1.0 0.0 0.0 0.09412 0.78431 0.09804
v 1.0 0.0 1.0 124 10 56 v 1.0 0.0 1.0 0.48627 0.03922 0.21961
v 1.0 1.0 0.0 78 10 50 v 1.0 1.0 0.0 0.30588 0.03922 0.19608
v 1.0 1.0 1.0 23 0 200 v 1.0 1.0 1.0 0.09020 0.00000 0.78431
vn 0.0 0.0 1.0 vn 0.0 0.0 1.0
vn 0.0 0.0 -1.0 vn 0.0 0.0 -1.0

View File

@ -0,0 +1,30 @@
g cube
v 0.0 0.0 0.0 0.0 0.0 0.0
v 0.0 0.0 1.0 1.0 0.6 0.3
v 0.0 1.0 0.0 0.0 0.0 0.0
v 0.0 1.0 1.0 0.3 0.6 1.0
v 1.0 0.0 0.0 0.0 0.0 0.0
v 1.0 0.0 1.0 1.0 0.6 0.3
v 1.0 1.0 0.0 0.0 0.0 0.0
v 1.0 1.0 1.0 0.3 0.6 1.0
vn 0.0 0.0 1.0
vn 0.0 0.0 -1.0
vn 0.0 1.0 0.0
vn 0.0 -1.0 0.0
vn 1.0 0.0 0.0
vn -1.0 0.0 0.0
f 1//2 7//2 5//2
f 1//2 3//2 7//2
f 1//6 4//6 3//6
f 1//6 2//6 4//6
f 3//3 8//3 7//3
f 3//3 4//3 8//3
f 5//5 7//5 8//5
f 5//5 8//5 6//5
f 1//4 5//4 6//4
f 1//4 6//4 2//4
f 2//1 6//1 8//1
f 2//1 8//1 4//1

View File

@ -267,6 +267,28 @@ TEST_F( utObjImportExport, issue809_vertex_color_Test ) {
#endif // ASSIMP_BUILD_NO_EXPORT #endif // ASSIMP_BUILD_NO_EXPORT
} }
TEST_F( utObjImportExport, issue1923_vertex_color_Test ) {
::Assimp::Importer importer;
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/cube_with_vertexcolors_uni.obj", aiProcess_ValidateDataStructure );
EXPECT_NE( nullptr, scene );
scene = importer.GetOrphanedScene();
#ifndef ASSIMP_BUILD_NO_EXPORT
::Assimp::Exporter exporter;
const aiExportDataBlob* blob = exporter.ExportToBlob( scene, "obj");
EXPECT_NE( nullptr, blob );
const aiScene *sceneReImport = importer.ReadFileFromMemory( blob->data, blob->size, aiProcess_ValidateDataStructure );
EXPECT_NE( nullptr, scene );
SceneDiffer differ;
EXPECT_TRUE( differ.isEqual( scene, sceneReImport ) );
#endif // ASSIMP_BUILD_NO_EXPORT
delete scene;
}
TEST_F( utObjImportExport, issue1453_segfault ) { TEST_F( utObjImportExport, issue1453_segfault ) {
static const std::string ObjModel = static const std::string ObjModel =
"v 0.0 0.0 0.0\n" "v 0.0 0.0 0.0\n"