Fix out-of-range access cause of aiProcess_GenNormals : array size inconsistency of members of mesh after process (#6332)
* Fix aiProcess_GenNormals process: copy members of mesh corresponding with additional vertices * Fix aiProcess_GenNormals process: Refoctoring * refactoring: fix SonarQube Issue * Update GenFaceNormalsProcess.cpp: fix small findings --------- Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>
This commit is contained in:
@@ -51,6 +51,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#include <numeric>
|
||||
#include <memory>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -86,6 +89,64 @@ void GenFaceNormalsProcess::Execute(aiScene *pScene) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template<class XMesh>
|
||||
void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
|
||||
// replace vertex data with the unique data sets
|
||||
pMesh->mNumVertices = static_cast<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) {
|
||||
std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
|
||||
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
||||
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
||||
pMesh->mVertices[a] = oldVertices[uniqueVertices[a]];
|
||||
}
|
||||
}
|
||||
|
||||
// Tangents, if present
|
||||
if (pMesh->mTangents) {
|
||||
std::unique_ptr<aiVector3D[]> oldTangents(pMesh->mTangents);
|
||||
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
|
||||
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
||||
pMesh->mTangents[a] = oldTangents[uniqueVertices[a]];
|
||||
}
|
||||
}
|
||||
// Bitangents as well
|
||||
if (pMesh->mBitangents) {
|
||||
std::unique_ptr<aiVector3D[]> oldBitangents(pMesh->mBitangents);
|
||||
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
|
||||
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
||||
pMesh->mBitangents[a] = oldBitangents[uniqueVertices[a]];
|
||||
}
|
||||
}
|
||||
// Vertex colors
|
||||
for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) {
|
||||
std::unique_ptr<aiColor4D[]> oldColors(pMesh->mColors[a]);
|
||||
pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
|
||||
for (unsigned int b = 0; b < pMesh->mNumVertices; b++) {
|
||||
pMesh->mColors[a][b] = oldColors[uniqueVertices[b]];
|
||||
}
|
||||
}
|
||||
// Texture coords
|
||||
for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) {
|
||||
std::unique_ptr<aiVector3D[]> oldTextureCoords(pMesh->mTextureCoords[a]);
|
||||
pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
|
||||
for (unsigned int b = 0; b < pMesh->mNumVertices; b++) {
|
||||
pMesh->mTextureCoords[a][b] = oldTextureCoords[uniqueVertices[b]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post-processing step on the given imported data.
|
||||
bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) {
|
||||
@@ -112,17 +173,21 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) {
|
||||
// mask to indicate if a vertex was already referenced and needs to be duplicated
|
||||
std::vector<bool> alreadyReferenced;
|
||||
alreadyReferenced.resize(pMesh->mNumVertices, false);
|
||||
std::vector<aiVector3D> duplicatedVertices;
|
||||
|
||||
std::vector<int> duplicatedVertices;
|
||||
duplicatedVertices.resize(pMesh->mNumVertices);
|
||||
std::iota(std::begin(duplicatedVertices), std::end(duplicatedVertices), 0);
|
||||
|
||||
auto storeNormalSplitVertex = [&](unsigned int index, const aiVector3D& normal) {
|
||||
if (!alreadyReferenced[index]) {
|
||||
normals[index] = normal;
|
||||
alreadyReferenced[index] = true;
|
||||
} else {
|
||||
duplicatedVertices.push_back(pMesh->mVertices[index]);
|
||||
normals.push_back(normal);
|
||||
index = pMesh->mNumVertices + static_cast<unsigned int>(duplicatedVertices.size() - 1);
|
||||
duplicatedVertices.push_back(index);
|
||||
index = static_cast<unsigned int>(duplicatedVertices.size() - 1);
|
||||
}
|
||||
|
||||
return index;
|
||||
};
|
||||
|
||||
@@ -154,16 +219,10 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) {
|
||||
}
|
||||
|
||||
// store normals (and additional vertices) back into the mesh
|
||||
if (!duplicatedVertices.empty()) {
|
||||
const aiVector3D * oldVertices = pMesh->mVertices;
|
||||
auto oldNumVertices = pMesh->mNumVertices;
|
||||
pMesh->mNumVertices += static_cast<unsigned int>(duplicatedVertices.size());
|
||||
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
||||
memcpy(pMesh->mVertices, oldVertices, oldNumVertices * sizeof(aiVector3D));
|
||||
memcpy(pMesh->mVertices + oldNumVertices, duplicatedVertices.data(), duplicatedVertices.size() * sizeof(aiVector3D));
|
||||
delete[] oldVertices;
|
||||
if (pMesh->mNumVertices != std::size(duplicatedVertices)) {
|
||||
updateXMeshVertices(pMesh, duplicatedVertices);
|
||||
}
|
||||
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
||||
pMesh->mNormals = new aiVector3D[normals.size()];
|
||||
memcpy(pMesh->mNormals, normals.data(), normals.size() * sizeof(aiVector3D));
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user