2015-05-19 03:48:29 +00:00
|
|
|
/*
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
Open Asset Import Library (assimp)
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
|
2021-02-28 11:17:54 +00:00
|
|
|
Copyright (c) 2006-2021, assimp team
|
2018-01-28 18:42:05 +00:00
|
|
|
|
2017-05-09 17:57:36 +00:00
|
|
|
|
2015-05-19 03:48:29 +00:00
|
|
|
|
|
|
|
All rights reserved.
|
|
|
|
|
2015-05-19 03:52:10 +00:00
|
|
|
Redistribution and use of this software in source and binary forms,
|
|
|
|
with or without modification, are permitted provided that the following
|
2015-05-19 03:48:29 +00:00
|
|
|
conditions are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above
|
|
|
|
copyright notice, this list of conditions and the
|
|
|
|
following disclaimer.
|
|
|
|
|
|
|
|
* Redistributions in binary form must reproduce the above
|
|
|
|
copyright notice, this list of conditions and the
|
|
|
|
following disclaimer in the documentation and/or other
|
|
|
|
materials provided with the distribution.
|
|
|
|
|
|
|
|
* Neither the name of the assimp team, nor the names of its
|
|
|
|
contributors may be used to endorse or promote products
|
|
|
|
derived from this software without specific prior
|
|
|
|
written permission of the assimp team.
|
|
|
|
|
2015-05-19 03:52:10 +00:00
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
2015-05-19 03:48:29 +00:00
|
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
2015-05-19 03:52:10 +00:00
|
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
2015-05-19 03:48:29 +00:00
|
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
2015-05-19 03:52:10 +00:00
|
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
2015-05-19 03:48:29 +00:00
|
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
2015-05-19 03:52:10 +00:00
|
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
2015-05-19 03:48:29 +00:00
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
---------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** @file PretransformVertices.cpp
|
2015-05-19 03:52:10 +00:00
|
|
|
* @brief Implementation of the "PretransformVertices" post processing step
|
2015-05-19 03:48:29 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "PretransformVertices.h"
|
2019-12-09 11:07:13 +00:00
|
|
|
#include "ConvertToLHProcess.h"
|
2015-05-19 03:48:29 +00:00
|
|
|
#include "ProcessHelper.h"
|
2018-01-06 00:18:33 +00:00
|
|
|
#include <assimp/Exceptional.h>
|
2019-12-09 11:07:13 +00:00
|
|
|
#include <assimp/SceneCombiner.h>
|
2015-05-19 03:48:29 +00:00
|
|
|
|
|
|
|
using namespace Assimp;
|
|
|
|
|
|
|
|
// some array offsets
|
|
|
|
#define AI_PTVS_VERTEX 0x0
|
|
|
|
#define AI_PTVS_FACE 0x1
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Constructor to be privately used by Importer
|
2019-12-09 11:07:13 +00:00
|
|
|
PretransformVertices::PretransformVertices() :
|
|
|
|
configKeepHierarchy(false),
|
|
|
|
configNormalize(false),
|
|
|
|
configTransform(false),
|
|
|
|
configTransformation(),
|
|
|
|
mConfigPointCloud(false) {
|
|
|
|
// empty
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Destructor, private as well
|
2018-05-01 11:28:53 +00:00
|
|
|
PretransformVertices::~PretransformVertices() {
|
2019-12-09 11:07:13 +00:00
|
|
|
// nothing to do here
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Returns whether the processing step is present in the given flag field.
|
2019-12-09 11:07:13 +00:00
|
|
|
bool PretransformVertices::IsActive(unsigned int pFlags) const {
|
|
|
|
return (pFlags & aiProcess_PreTransformVertices) != 0;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Setup import configuration
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::SetupProperties(const Importer *pImp) {
|
|
|
|
// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE,
|
|
|
|
// AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION
|
|
|
|
configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0));
|
|
|
|
configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0));
|
|
|
|
configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0));
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2019-12-09 11:07:13 +00:00
|
|
|
configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4());
|
2018-05-01 11:28:53 +00:00
|
|
|
|
2019-12-09 11:07:13 +00:00
|
|
|
mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Count the number of nodes
|
2019-12-09 11:07:13 +00:00
|
|
|
unsigned int PretransformVertices::CountNodes(const aiNode *pcNode) const {
|
|
|
|
unsigned int iRet = 1;
|
|
|
|
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
|
|
|
|
iRet += CountNodes(pcNode->mChildren[i]);
|
|
|
|
}
|
|
|
|
return iRet;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Get a bitwise combination identifying the vertex format of a mesh
|
2019-12-09 11:07:13 +00:00
|
|
|
unsigned int PretransformVertices::GetMeshVFormat(aiMesh *pcMesh) const {
|
|
|
|
// the vertex format is stored in aiMesh::mBones for later retrieval.
|
|
|
|
// there isn't a good reason to compute it a few hundred times
|
|
|
|
// from scratch. The pointer is unused as animations are lost
|
|
|
|
// during PretransformVertices.
|
|
|
|
if (pcMesh->mBones)
|
|
|
|
return (unsigned int)(uint64_t)pcMesh->mBones;
|
|
|
|
|
|
|
|
const unsigned int iRet = GetMeshVFormatUnique(pcMesh);
|
|
|
|
|
|
|
|
// store the value for later use
|
|
|
|
pcMesh->mBones = (aiBone **)(uint64_t)iRet;
|
|
|
|
return iRet;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Count the number of vertices in the whole scene and a given
|
|
|
|
// material index
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat,
|
|
|
|
unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const {
|
|
|
|
for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) {
|
|
|
|
aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]];
|
|
|
|
if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) {
|
|
|
|
*piVertices += pcMesh->mNumVertices;
|
|
|
|
*piFaces += pcMesh->mNumFaces;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
|
|
|
|
CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat,
|
|
|
|
iVFormat, piFaces, piVertices);
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Collect vertex/face data
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::CollectData(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat,
|
|
|
|
unsigned int iVFormat, aiMesh *pcMeshOut,
|
|
|
|
unsigned int aiCurrent[2], unsigned int *num_refs) const {
|
|
|
|
// No need to multiply if there's no transformation
|
|
|
|
const bool identity = pcNode->mTransformation.IsIdentity();
|
|
|
|
for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) {
|
|
|
|
aiMesh *pcMesh = pcScene->mMeshes[pcNode->mMeshes[i]];
|
|
|
|
if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) {
|
|
|
|
// Decrement mesh reference counter
|
|
|
|
unsigned int &num_ref = num_refs[pcNode->mMeshes[i]];
|
|
|
|
ai_assert(0 != num_ref);
|
|
|
|
--num_ref;
|
|
|
|
// Save the name of the last mesh
|
|
|
|
if (num_ref == 0) {
|
|
|
|
pcMeshOut->mName = pcMesh->mName;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (identity) {
|
|
|
|
// copy positions without modifying them
|
|
|
|
::memcpy(pcMeshOut->mVertices + aiCurrent[AI_PTVS_VERTEX],
|
|
|
|
pcMesh->mVertices,
|
|
|
|
pcMesh->mNumVertices * sizeof(aiVector3D));
|
|
|
|
|
|
|
|
if (iVFormat & 0x2) {
|
|
|
|
// copy normals without modifying them
|
|
|
|
::memcpy(pcMeshOut->mNormals + aiCurrent[AI_PTVS_VERTEX],
|
|
|
|
pcMesh->mNormals,
|
|
|
|
pcMesh->mNumVertices * sizeof(aiVector3D));
|
|
|
|
}
|
|
|
|
if (iVFormat & 0x4) {
|
|
|
|
// copy tangents without modifying them
|
|
|
|
::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX],
|
|
|
|
pcMesh->mTangents,
|
|
|
|
pcMesh->mNumVertices * sizeof(aiVector3D));
|
|
|
|
// copy bitangents without modifying them
|
|
|
|
::memcpy(pcMeshOut->mBitangents + aiCurrent[AI_PTVS_VERTEX],
|
|
|
|
pcMesh->mBitangents,
|
|
|
|
pcMesh->mNumVertices * sizeof(aiVector3D));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// copy positions, transform them to worldspace
|
|
|
|
for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) {
|
|
|
|
pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX] + n] = pcNode->mTransformation * pcMesh->mVertices[n];
|
|
|
|
}
|
|
|
|
aiMatrix4x4 mWorldIT = pcNode->mTransformation;
|
|
|
|
mWorldIT.Inverse().Transpose();
|
|
|
|
|
|
|
|
// TODO: implement Inverse() for aiMatrix3x3
|
|
|
|
aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
|
|
|
|
|
|
|
|
if (iVFormat & 0x2) {
|
|
|
|
// copy normals, transform them to worldspace
|
|
|
|
for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) {
|
|
|
|
pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX] + n] =
|
|
|
|
(m * pcMesh->mNormals[n]).Normalize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (iVFormat & 0x4) {
|
|
|
|
// copy tangents and bitangents, transform them to worldspace
|
|
|
|
for (unsigned int n = 0; n < pcMesh->mNumVertices; ++n) {
|
|
|
|
pcMeshOut->mTangents[aiCurrent[AI_PTVS_VERTEX] + n] = (m * pcMesh->mTangents[n]).Normalize();
|
|
|
|
pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX] + n] = (m * pcMesh->mBitangents[n]).Normalize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unsigned int p = 0;
|
|
|
|
while (iVFormat & (0x100 << p)) {
|
|
|
|
// copy texture coordinates
|
|
|
|
memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX],
|
|
|
|
pcMesh->mTextureCoords[p],
|
|
|
|
pcMesh->mNumVertices * sizeof(aiVector3D));
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
p = 0;
|
|
|
|
while (iVFormat & (0x1000000 << p)) {
|
|
|
|
// copy vertex colors
|
|
|
|
memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX],
|
|
|
|
pcMesh->mColors[p],
|
|
|
|
pcMesh->mNumVertices * sizeof(aiColor4D));
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
// now we need to copy all faces. since we will delete the source mesh afterwards,
|
|
|
|
// we don't need to reallocate the array of indices except if this mesh is
|
|
|
|
// referenced multiple times.
|
|
|
|
for (unsigned int planck = 0; planck < pcMesh->mNumFaces; ++planck) {
|
|
|
|
aiFace &f_src = pcMesh->mFaces[planck];
|
|
|
|
aiFace &f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE] + planck];
|
|
|
|
|
|
|
|
const unsigned int num_idx = f_src.mNumIndices;
|
|
|
|
|
|
|
|
f_dst.mNumIndices = num_idx;
|
|
|
|
|
|
|
|
unsigned int *pi;
|
|
|
|
if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */
|
|
|
|
pi = f_dst.mIndices = f_src.mIndices;
|
|
|
|
|
|
|
|
// offset all vertex indices
|
|
|
|
for (unsigned int hahn = 0; hahn < num_idx; ++hahn) {
|
|
|
|
pi[hahn] += aiCurrent[AI_PTVS_VERTEX];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pi = f_dst.mIndices = new unsigned int[num_idx];
|
|
|
|
|
|
|
|
// copy and offset all vertex indices
|
|
|
|
for (unsigned int hahn = 0; hahn < num_idx; ++hahn) {
|
|
|
|
pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the mPrimitiveTypes member of the mesh
|
|
|
|
switch (pcMesh->mFaces[planck].mNumIndices) {
|
|
|
|
case 0x1:
|
|
|
|
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
|
|
|
break;
|
|
|
|
case 0x2:
|
|
|
|
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
|
|
|
break;
|
|
|
|
case 0x3:
|
|
|
|
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices;
|
|
|
|
aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// append all children of us
|
|
|
|
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
|
|
|
|
CollectData(pcScene, pcNode->mChildren[i], iMat,
|
|
|
|
iVFormat, pcMeshOut, aiCurrent, num_refs);
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Get a list of all vertex formats that occur for a given material index
|
|
|
|
// The output list contains duplicate elements
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::GetVFormatList(const aiScene *pcScene, unsigned int iMat,
|
|
|
|
std::list<unsigned int> &aiOut) const {
|
|
|
|
for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
|
|
|
|
aiMesh *pcMesh = pcScene->mMeshes[i];
|
|
|
|
if (iMat == pcMesh->mMaterialIndex) {
|
|
|
|
aiOut.push_back(GetMeshVFormat(pcMesh));
|
|
|
|
}
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Compute the absolute transformation matrices of each node
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) {
|
|
|
|
if (pcNode->mParent) {
|
|
|
|
pcNode->mTransformation = pcNode->mParent->mTransformation * pcNode->mTransformation;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
|
|
|
|
ComputeAbsoluteTransform(pcNode->mChildren[i]);
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Apply the node transformation to a mesh
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const {
|
|
|
|
// Check whether we need to transform the coordinates at all
|
|
|
|
if (!mat.IsIdentity()) {
|
|
|
|
|
|
|
|
// Check for odd negative scale (mirror)
|
|
|
|
if (mesh->HasFaces() && mat.Determinant() < 0) {
|
|
|
|
// Reverse the mesh face winding order
|
|
|
|
FlipWindingOrderProcess::ProcessMesh(mesh);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update positions
|
|
|
|
if (mesh->HasPositions()) {
|
|
|
|
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
|
|
|
mesh->mVertices[i] = mat * mesh->mVertices[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update normals and tangents
|
|
|
|
if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
|
|
|
|
const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose();
|
|
|
|
|
|
|
|
if (mesh->HasNormals()) {
|
|
|
|
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
|
|
|
mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mesh->HasTangentsAndBitangents()) {
|
|
|
|
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
|
|
|
mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
|
|
|
|
mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Simple routine to build meshes in worldspace, no further optimization
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **in,
|
|
|
|
unsigned int numIn, aiNode *node) const {
|
|
|
|
// NOTE:
|
|
|
|
// aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy
|
|
|
|
// aiMesh::mBones store reference to abs. transform we multiplied with
|
|
|
|
|
|
|
|
// process meshes
|
|
|
|
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
|
|
|
|
aiMesh *mesh = in[node->mMeshes[i]];
|
|
|
|
|
|
|
|
// check whether we can operate on this mesh
|
|
|
|
if (!mesh->mBones || *reinterpret_cast<aiMatrix4x4 *>(mesh->mBones) == node->mTransformation) {
|
|
|
|
// yes, we can.
|
|
|
|
mesh->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
|
|
|
|
mesh->mNumBones = UINT_MAX;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// try to find us in the list of newly created meshes
|
|
|
|
for (unsigned int n = 0; n < out.size(); ++n) {
|
|
|
|
aiMesh *ctz = out[n];
|
|
|
|
if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4 *>(ctz->mBones) == node->mTransformation) {
|
|
|
|
|
|
|
|
// ok, use this one. Update node mesh index
|
|
|
|
node->mMeshes[i] = numIn + n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (node->mMeshes[i] < numIn) {
|
|
|
|
// Worst case. Need to operate on a full copy of the mesh
|
|
|
|
ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms");
|
|
|
|
aiMesh *ntz;
|
|
|
|
|
|
|
|
const unsigned int tmp = mesh->mNumBones; //
|
|
|
|
mesh->mNumBones = 0;
|
|
|
|
SceneCombiner::Copy(&ntz, mesh);
|
|
|
|
mesh->mNumBones = tmp;
|
|
|
|
|
|
|
|
ntz->mNumBones = node->mMeshes[i];
|
|
|
|
ntz->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
|
|
|
|
|
|
|
|
out.push_back(ntz);
|
|
|
|
|
|
|
|
node->mMeshes[i] = static_cast<unsigned int>(numIn + out.size() - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// call children
|
|
|
|
for (unsigned int i = 0; i < node->mNumChildren; ++i)
|
|
|
|
BuildWCSMeshes(out, in, numIn, node->mChildren[i]);
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Reset transformation matrices to identity
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::MakeIdentityTransform(aiNode *nd) const {
|
|
|
|
nd->mTransformation = aiMatrix4x4();
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2019-12-09 11:07:13 +00:00
|
|
|
// call children
|
|
|
|
for (unsigned int i = 0; i < nd->mNumChildren; ++i)
|
|
|
|
MakeIdentityTransform(nd->mChildren[i]);
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Build reference counters for all meshes
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const {
|
|
|
|
for (unsigned int i = 0; i < nd->mNumMeshes; ++i)
|
|
|
|
refs[nd->mMeshes[i]]++;
|
|
|
|
|
|
|
|
// call children
|
|
|
|
for (unsigned int i = 0; i < nd->mNumChildren; ++i)
|
|
|
|
BuildMeshRefCountArray(nd->mChildren[i], refs);
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Executes the post processing step on the given imported data.
|
2019-12-09 11:07:13 +00:00
|
|
|
void PretransformVertices::Execute(aiScene *pScene) {
|
|
|
|
ASSIMP_LOG_DEBUG("PretransformVerticesProcess begin");
|
|
|
|
|
|
|
|
// Return immediately if we have no meshes
|
|
|
|
if (!pScene->mNumMeshes)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const unsigned int iOldMeshes = pScene->mNumMeshes;
|
|
|
|
const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
|
|
|
|
const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
|
|
|
|
|
|
|
|
if (configTransform) {
|
|
|
|
pScene->mRootNode->mTransformation = configTransformation;
|
|
|
|
}
|
|
|
|
|
|
|
|
// first compute absolute transformation matrices for all nodes
|
|
|
|
ComputeAbsoluteTransform(pScene->mRootNode);
|
|
|
|
|
|
|
|
// Delete aiMesh::mBones for all meshes. The bones are
|
|
|
|
// removed during this step and we need the pointer as
|
|
|
|
// temporary storage
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
|
|
|
aiMesh *mesh = pScene->mMeshes[i];
|
|
|
|
|
|
|
|
for (unsigned int a = 0; a < mesh->mNumBones; ++a)
|
|
|
|
delete mesh->mBones[a];
|
|
|
|
|
|
|
|
delete[] mesh->mBones;
|
2020-06-23 19:05:42 +00:00
|
|
|
mesh->mBones = nullptr;
|
2019-12-09 11:07:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// now build a list of output meshes
|
|
|
|
std::vector<aiMesh *> apcOutMeshes;
|
|
|
|
|
|
|
|
// Keep scene hierarchy? It's an easy job in this case ...
|
|
|
|
// we go on and transform all meshes, if one is referenced by nodes
|
|
|
|
// with different absolute transformations a depth copy of the mesh
|
|
|
|
// is required.
|
|
|
|
if (configKeepHierarchy) {
|
|
|
|
|
|
|
|
// Hack: store the matrix we're transforming a mesh with in aiMesh::mBones
|
|
|
|
BuildWCSMeshes(apcOutMeshes, pScene->mMeshes, pScene->mNumMeshes, pScene->mRootNode);
|
|
|
|
|
|
|
|
// ... if new meshes have been generated, append them to the end of the scene
|
|
|
|
if (apcOutMeshes.size() > 0) {
|
|
|
|
aiMesh **npp = new aiMesh *[pScene->mNumMeshes + apcOutMeshes.size()];
|
|
|
|
|
|
|
|
memcpy(npp, pScene->mMeshes, sizeof(aiMesh *) * pScene->mNumMeshes);
|
|
|
|
memcpy(npp + pScene->mNumMeshes, &apcOutMeshes[0], sizeof(aiMesh *) * apcOutMeshes.size());
|
|
|
|
|
|
|
|
pScene->mNumMeshes += static_cast<unsigned int>(apcOutMeshes.size());
|
|
|
|
delete[] pScene->mMeshes;
|
|
|
|
pScene->mMeshes = npp;
|
|
|
|
}
|
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
// now iterate through all meshes and transform them to world-space
|
2019-12-09 11:07:13 +00:00
|
|
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
|
|
|
ApplyTransform(pScene->mMeshes[i], *reinterpret_cast<aiMatrix4x4 *>(pScene->mMeshes[i]->mBones));
|
|
|
|
|
|
|
|
// prevent improper destruction
|
2020-06-23 19:05:42 +00:00
|
|
|
pScene->mMeshes[i]->mBones = nullptr;
|
2019-12-09 11:07:13 +00:00
|
|
|
pScene->mMeshes[i]->mNumBones = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
apcOutMeshes.reserve(pScene->mNumMaterials << 1u);
|
|
|
|
std::list<unsigned int> aiVFormats;
|
|
|
|
|
|
|
|
std::vector<unsigned int> s(pScene->mNumMeshes, 0);
|
|
|
|
BuildMeshRefCountArray(pScene->mRootNode, &s[0]);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
|
|
|
|
// get the list of all vertex formats for this material
|
|
|
|
aiVFormats.clear();
|
|
|
|
GetVFormatList(pScene, i, aiVFormats);
|
|
|
|
aiVFormats.sort();
|
|
|
|
aiVFormats.unique();
|
|
|
|
for (std::list<unsigned int>::const_iterator j = aiVFormats.begin(); j != aiVFormats.end(); ++j) {
|
|
|
|
unsigned int iVertices = 0;
|
|
|
|
unsigned int iFaces = 0;
|
|
|
|
CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &iFaces, &iVertices);
|
|
|
|
if (0 != iFaces && 0 != iVertices) {
|
|
|
|
apcOutMeshes.push_back(new aiMesh());
|
|
|
|
aiMesh *pcMesh = apcOutMeshes.back();
|
|
|
|
pcMesh->mNumFaces = iFaces;
|
|
|
|
pcMesh->mNumVertices = iVertices;
|
|
|
|
pcMesh->mFaces = new aiFace[iFaces];
|
|
|
|
pcMesh->mVertices = new aiVector3D[iVertices];
|
|
|
|
pcMesh->mMaterialIndex = i;
|
|
|
|
if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[iVertices];
|
|
|
|
if ((*j) & 0x4) {
|
|
|
|
pcMesh->mTangents = new aiVector3D[iVertices];
|
|
|
|
pcMesh->mBitangents = new aiVector3D[iVertices];
|
|
|
|
}
|
|
|
|
iFaces = 0;
|
|
|
|
while ((*j) & (0x100 << iFaces)) {
|
|
|
|
pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices];
|
|
|
|
if ((*j) & (0x10000 << iFaces))
|
|
|
|
pcMesh->mNumUVComponents[iFaces] = 3;
|
|
|
|
else
|
|
|
|
pcMesh->mNumUVComponents[iFaces] = 2;
|
|
|
|
iFaces++;
|
|
|
|
}
|
|
|
|
iFaces = 0;
|
|
|
|
while ((*j) & (0x1000000 << iFaces))
|
|
|
|
pcMesh->mColors[iFaces++] = new aiColor4D[iVertices];
|
|
|
|
|
|
|
|
// fill the mesh ...
|
|
|
|
unsigned int aiTemp[2] = { 0, 0 };
|
|
|
|
CollectData(pScene, pScene->mRootNode, i, *j, pcMesh, aiTemp, &s[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no meshes are referenced in the node graph it is possible that we get no output meshes.
|
|
|
|
if (apcOutMeshes.empty()) {
|
|
|
|
|
|
|
|
throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes");
|
|
|
|
} else {
|
|
|
|
// now delete all meshes in the scene and build a new mesh list
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
|
|
|
aiMesh *mesh = pScene->mMeshes[i];
|
|
|
|
mesh->mNumBones = 0;
|
2020-06-23 19:05:42 +00:00
|
|
|
mesh->mBones = nullptr;
|
2019-12-09 11:07:13 +00:00
|
|
|
|
|
|
|
// we're reusing the face index arrays. avoid destruction
|
|
|
|
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
|
|
|
|
mesh->mFaces[a].mNumIndices = 0;
|
2020-06-23 19:05:42 +00:00
|
|
|
mesh->mFaces[a].mIndices = nullptr;
|
2019-12-09 11:07:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
delete mesh;
|
|
|
|
|
|
|
|
// Invalidate the contents of the old mesh array. We will most
|
|
|
|
// likely have less output meshes now, so the last entries of
|
2020-06-23 19:05:42 +00:00
|
|
|
// the mesh array are not overridden. We set them to nullptr to
|
2019-12-09 11:07:13 +00:00
|
|
|
// make sure the developer gets notified when his application
|
|
|
|
// attempts to access these fields ...
|
2020-06-23 19:05:42 +00:00
|
|
|
mesh = nullptr;
|
2019-12-09 11:07:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// It is impossible that we have more output meshes than
|
|
|
|
// input meshes, so we can easily reuse the old mesh array
|
|
|
|
pScene->mNumMeshes = (unsigned int)apcOutMeshes.size();
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
|
|
|
pScene->mMeshes[i] = apcOutMeshes[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove all animations from the scene
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumAnimations; ++i)
|
|
|
|
delete pScene->mAnimations[i];
|
|
|
|
delete[] pScene->mAnimations;
|
|
|
|
|
2020-06-23 19:05:42 +00:00
|
|
|
pScene->mAnimations = nullptr;
|
2019-12-09 11:07:13 +00:00
|
|
|
pScene->mNumAnimations = 0;
|
|
|
|
|
|
|
|
// --- we need to keep all cameras and lights
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {
|
|
|
|
aiCamera *cam = pScene->mCameras[i];
|
|
|
|
const aiNode *nd = pScene->mRootNode->FindNode(cam->mName);
|
2020-06-23 19:05:42 +00:00
|
|
|
ai_assert(nullptr != nd);
|
2019-12-09 11:07:13 +00:00
|
|
|
|
|
|
|
// multiply all properties of the camera with the absolute
|
|
|
|
// transformation of the corresponding node
|
|
|
|
cam->mPosition = nd->mTransformation * cam->mPosition;
|
|
|
|
cam->mLookAt = aiMatrix3x3(nd->mTransformation) * cam->mLookAt;
|
|
|
|
cam->mUp = aiMatrix3x3(nd->mTransformation) * cam->mUp;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumLights; ++i) {
|
|
|
|
aiLight *l = pScene->mLights[i];
|
|
|
|
const aiNode *nd = pScene->mRootNode->FindNode(l->mName);
|
2020-06-23 19:05:42 +00:00
|
|
|
ai_assert(nullptr != nd);
|
2019-12-09 11:07:13 +00:00
|
|
|
|
|
|
|
// multiply all properties of the camera with the absolute
|
|
|
|
// transformation of the corresponding node
|
|
|
|
l->mPosition = nd->mTransformation * l->mPosition;
|
|
|
|
l->mDirection = aiMatrix3x3(nd->mTransformation) * l->mDirection;
|
|
|
|
l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!configKeepHierarchy) {
|
|
|
|
|
|
|
|
// now delete all nodes in the scene and build a new
|
|
|
|
// flat node graph with a root node and some level 1 children
|
|
|
|
aiNode *newRoot = new aiNode();
|
|
|
|
newRoot->mName = pScene->mRootNode->mName;
|
|
|
|
delete pScene->mRootNode;
|
|
|
|
pScene->mRootNode = newRoot;
|
|
|
|
|
|
|
|
if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) {
|
|
|
|
pScene->mRootNode->mNumMeshes = 1;
|
|
|
|
pScene->mRootNode->mMeshes = new unsigned int[1];
|
|
|
|
pScene->mRootNode->mMeshes[0] = 0;
|
|
|
|
} else {
|
|
|
|
pScene->mRootNode->mNumChildren = pScene->mNumMeshes + pScene->mNumLights + pScene->mNumCameras;
|
|
|
|
aiNode **nodes = pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
|
|
|
|
|
|
|
|
// generate mesh nodes
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++nodes) {
|
|
|
|
aiNode *pcNode = new aiNode();
|
|
|
|
*nodes = pcNode;
|
|
|
|
pcNode->mParent = pScene->mRootNode;
|
|
|
|
pcNode->mName = pScene->mMeshes[i]->mName;
|
|
|
|
|
|
|
|
// setup mesh indices
|
|
|
|
pcNode->mNumMeshes = 1;
|
|
|
|
pcNode->mMeshes = new unsigned int[1];
|
|
|
|
pcNode->mMeshes[0] = i;
|
|
|
|
}
|
|
|
|
// generate light nodes
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumLights; ++i, ++nodes) {
|
|
|
|
aiNode *pcNode = new aiNode();
|
|
|
|
*nodes = pcNode;
|
|
|
|
pcNode->mParent = pScene->mRootNode;
|
|
|
|
pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u", i);
|
|
|
|
pScene->mLights[i]->mName = pcNode->mName;
|
|
|
|
}
|
|
|
|
// generate camera nodes
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumCameras; ++i, ++nodes) {
|
|
|
|
aiNode *pcNode = new aiNode();
|
|
|
|
*nodes = pcNode;
|
|
|
|
pcNode->mParent = pScene->mRootNode;
|
|
|
|
pcNode->mName.length = ::ai_snprintf(pcNode->mName.data, MAXLEN, "cam_%u", i);
|
|
|
|
pScene->mCameras[i]->mName = pcNode->mName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// ... and finally set the transformation matrix of all nodes to identity
|
|
|
|
MakeIdentityTransform(pScene->mRootNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (configNormalize) {
|
|
|
|
// compute the boundary of all meshes
|
|
|
|
aiVector3D min, max;
|
|
|
|
MinMaxChooser<aiVector3D>()(min, max);
|
|
|
|
|
|
|
|
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
|
|
|
|
aiMesh *m = pScene->mMeshes[a];
|
|
|
|
for (unsigned int i = 0; i < m->mNumVertices; ++i) {
|
|
|
|
min = std::min(m->mVertices[i], min);
|
|
|
|
max = std::max(m->mVertices[i], max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the dominant axis
|
|
|
|
aiVector3D d = max - min;
|
|
|
|
const ai_real div = std::max(d.x, std::max(d.y, d.z)) * ai_real(0.5);
|
|
|
|
|
|
|
|
d = min + d * (ai_real)0.5;
|
|
|
|
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
|
|
|
|
aiMesh *m = pScene->mMeshes[a];
|
|
|
|
for (unsigned int i = 0; i < m->mNumVertices; ++i) {
|
|
|
|
m->mVertices[i] = (m->mVertices[i] - d) / div;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// print statistics
|
|
|
|
if (!DefaultLogger::isNullLogger()) {
|
|
|
|
ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished");
|
|
|
|
|
|
|
|
ASSIMP_LOG_INFO_F("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (",
|
|
|
|
CountNodes(pScene->mRootNode), " output nodes)");
|
|
|
|
ASSIMP_LOG_INFO_F("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras.");
|
|
|
|
ASSIMP_LOG_INFO_F("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")");
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|