Merge branch 'master' into master

pull/1938/head
Kim Kulling 2018-05-06 16:41:12 +02:00 committed by GitHub
commit be0203229b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 191 additions and 125 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

@ -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

@ -759,7 +759,7 @@ void glTF2Exporter::ExportMeshes()
if (c) if (c)
p.attributes.color.push_back(c); p.attributes.color.push_back(c);
} }
/*************** Vertices indices ****************/ /*************** Vertices indices ****************/
if (aim->mNumFaces > 0) { if (aim->mNumFaces > 0) {
std::vector<IndicesType> indices; std::vector<IndicesType> indices;
@ -891,6 +891,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) {