Refactoring: Reuse code from GeometryUtils

pull/5086/head
Kim Kulling 2023-05-04 00:00:52 +02:00
parent 5d841ec9a5
commit d58201a579
20 changed files with 526 additions and 535 deletions

View File

@ -89,4 +89,12 @@ bool GeometryUtils::PlaneIntersect(const aiRay& ray, const aiVector3D& planePos,
return true; return true;
} }
// ------------------------------------------------------------------------------------------------
void GeometryUtils::normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut,
size_t numVectors) {
for (size_t i=0; i<numVectors; ++i) {
vectorArrayOut[i] = vectorArrayIn[i].Normalize();
}
}
} // namespace Assimp } // namespace Assimp

View File

@ -47,7 +47,7 @@ namespace Assimp {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/// @brief This helper class supports some basic geometry algorithms. /// @brief This helper class supports some basic geometry algorithms.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
class GeometryUtils { class ASSIMP_API GeometryUtils {
public: public:
static ai_real heron( ai_real a, ai_real b, ai_real c ); static ai_real heron( ai_real a, ai_real b, ai_real c );
@ -63,7 +63,19 @@ public:
/// @return The area. /// @return The area.
static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ); static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh );
/// @brief
/// @param ray
/// @param planePos
/// @param planeNormal
/// @param pos
/// @return
static bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, const aiVector3D& planeNormal, aiVector3D& pos); static bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, const aiVector3D& planeNormal, aiVector3D& pos);
/// @brief
/// @param vectorArrayIn
/// @param vectorArrayOut
/// @param numVectors
static void normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors);
}; };
} // namespace Assimp } // namespace Assimp

View File

@ -42,30 +42,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file GenUVCoords step */ /** @file GenUVCoords step */
#include "ComputeUVMappingProcess.h" #include "ComputeUVMappingProcess.h"
#include "Geometry/GeometryUtils.h"
#include "ProcessHelper.h" #include "ProcessHelper.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include "Geometry/GeometryUtils.h"
using namespace Assimp; using namespace Assimp;
namespace { namespace {
const static aiVector3D base_axis_y(0.0,1.0,0.0); const static aiVector3D base_axis_y(0.0, 1.0, 0.0);
const static aiVector3D base_axis_x(1.0,0.0,0.0); const static aiVector3D base_axis_x(1.0, 0.0, 0.0);
const static aiVector3D base_axis_z(0.0,0.0,1.0); const static aiVector3D base_axis_z(0.0, 0.0, 1.0);
const static ai_real angle_epsilon = ai_real( 0.95 ); const static ai_real angle_epsilon = ai_real(0.95);
} } // namespace
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const { bool ComputeUVMappingProcess::IsActive(unsigned int pFlags) const {
return (pFlags & aiProcess_GenUVCoords) != 0; return (pFlags & aiProcess_GenUVCoords) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Find the first empty UV channel in a mesh // Find the first empty UV channel in a mesh
inline unsigned int FindEmptyUVChannel (aiMesh* mesh) { inline unsigned int FindEmptyUVChannel(aiMesh *mesh) {
for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m) for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++m)
if (!mesh->mTextureCoords[m]) { if (!mesh->mTextureCoords[m]) {
return m; return m;
} }
@ -76,19 +76,19 @@ inline unsigned int FindEmptyUVChannel (aiMesh* mesh) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Try to remove UV seams // Try to remove UV seams
void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) { void RemoveUVSeams(aiMesh *mesh, aiVector3D *out) {
// TODO: just a very rough algorithm. I think it could be done // TODO: just a very rough algorithm. I think it could be done
// much easier, but I don't know how and am currently too tired to // much easier, but I don't know how and am currently too tired to
// to think about a better solution. // to think about a better solution.
const static ai_real LOWER_LIMIT = ai_real( 0.1 ); const static ai_real LOWER_LIMIT = ai_real(0.1);
const static ai_real UPPER_LIMIT = ai_real( 0.9 ); const static ai_real UPPER_LIMIT = ai_real(0.9);
const static ai_real LOWER_EPSILON = ai_real( 10e-3 ); const static ai_real LOWER_EPSILON = ai_real(10e-3);
const static ai_real UPPER_EPSILON = ai_real( 1.0-10e-3 ); const static ai_real UPPER_EPSILON = ai_real(1.0 - 10e-3);
for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) { for (unsigned int fidx = 0; fidx < mesh->mNumFaces; ++fidx) {
const aiFace& face = mesh->mFaces[fidx]; const aiFace &face = mesh->mFaces[fidx];
if (face.mNumIndices < 3) { if (face.mNumIndices < 3) {
continue; // triangles and polygons only, please continue; // triangles and polygons only, please
} }
@ -100,20 +100,18 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) {
// but the assumption that a face with at least one very small // but the assumption that a face with at least one very small
// on the one side and one very large U coord on the other side // on the one side and one very large U coord on the other side
// lies on a UV seam should work for most cases. // lies on a UV seam should work for most cases.
for (unsigned int n = 0; n < face.mNumIndices;++n) for (unsigned int n = 0; n < face.mNumIndices; ++n) {
{ if (out[face.mIndices[n]].x < LOWER_LIMIT) {
if (out[face.mIndices[n]].x < LOWER_LIMIT)
{
smallV = n; smallV = n;
// If we have a U value very close to 0 we can't // If we have a U value very close to 0 we can't
// round the others to 0, too. // round the others to 0, too.
if (out[face.mIndices[n]].x <= LOWER_EPSILON) if (out[face.mIndices[n]].x <= LOWER_EPSILON)
zero = true; zero = true;
else round_to_zero = true; else
round_to_zero = true;
} }
if (out[face.mIndices[n]].x > UPPER_LIMIT) if (out[face.mIndices[n]].x > UPPER_LIMIT) {
{
large = n; large = n;
// If we have a U value very close to 1 we can't // If we have a U value very close to 1 we can't
@ -122,10 +120,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) {
one = true; one = true;
} }
} }
if (smallV != face.mNumIndices && large != face.mNumIndices) if (smallV != face.mNumIndices && large != face.mNumIndices) {
{ for (unsigned int n = 0; n < face.mNumIndices; ++n) {
for (unsigned int n = 0; n < face.mNumIndices;++n)
{
// If the u value is over the upper limit and no other u // If the u value is over the upper limit and no other u
// value of that face is 0, round it to 0 // value of that face is 0, round it to 0
if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero) if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero)
@ -141,9 +137,8 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) {
// Due to numerical inaccuracies one U coord becomes 0, the // Due to numerical inaccuracies one U coord becomes 0, the
// other 1. But we do still have a third UV coord to determine // other 1. But we do still have a third UV coord to determine
// to which side we must round to. // to which side we must round to.
else if (one && zero) else if (one && zero) {
{ if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON)
out[face.mIndices[n]].x = 0.0; out[face.mIndices[n]].x = 0.0;
else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON) else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON)
out[face.mIndices[n]].x = 1.0; out[face.mIndices[n]].x = 1.0;
@ -154,8 +149,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
{
aiVector3D center, min, max; aiVector3D center, min, max;
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
@ -163,7 +157,7 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
// currently the mapping axis will always be one of x,y,z, except if the // currently the mapping axis will always be one of x,y,z, except if the
// PretransformVertices step is used (it transforms the meshes into worldspace, // PretransformVertices step is used (it transforms the meshes into worldspace,
// thus changing the mapping axis) // thus changing the mapping axis)
if (axis * base_axis_x >= angle_epsilon) { if (axis * base_axis_x >= angle_epsilon) {
// For each point get a normalized projection vector in the sphere, // For each point get a normalized projection vector in the sphere,
// get its longitude and latitude and map them to their respective // get its longitude and latitude and map them to their respective
@ -177,58 +171,54 @@ void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D
// Thus we can derive: // Thus we can derive:
// lat = arcsin (z) // lat = arcsin (z)
// lon = arctan (y/x) // lon = arctan (y/x)
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
(std::asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); (std::asin(diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
} }
} } else if (axis * base_axis_y >= angle_epsilon) {
else if (axis * base_axis_y >= angle_epsilon) {
// ... just the same again // ... just the same again
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
(std::asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); (std::asin(diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
} }
} } else if (axis * base_axis_z >= angle_epsilon) {
else if (axis * base_axis_z >= angle_epsilon) {
// ... just the same again // ... just the same again
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); const aiVector3D diff = (mesh->mVertices[pnt] - center).Normalize();
out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
(std::asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
} }
} }
// slower code path in case the mapping axis is not one of the coordinate system axes // slower code path in case the mapping axis is not one of the coordinate system axes
else { else {
aiMatrix4x4 mTrafo; aiMatrix4x4 mTrafo;
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
// again the same, except we're applying a transformation now // again the same, except we're applying a transformation now
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize(); const aiVector3D diff = ((mTrafo * mesh->mVertices[pnt]) - center).Normalize();
out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F) / AI_MATH_TWO_PI_F,
(std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0);
} }
} }
// Now find and remove UV seams. A seam occurs if a face has a tcoord // Now find and remove UV seams. A seam occurs if a face has a tcoord
// close to zero on the one side, and a tcoord close to one on the // close to zero on the one side, and a tcoord close to one on the
// other side. // other side.
RemoveUVSeams(mesh,out); RemoveUVSeams(mesh, out);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
{
aiVector3D center, min, max; aiVector3D center, min, max;
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
// currently the mapping axis will always be one of x,y,z, except if the // currently the mapping axis will always be one of x,y,z, except if the
// PretransformVertices step is used (it transforms the meshes into worldspace, // PretransformVertices step is used (it transforms the meshes into worldspace,
// thus changing the mapping axis) // thus changing the mapping axis)
if (axis * base_axis_x >= angle_epsilon) { if (axis * base_axis_x >= angle_epsilon) {
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
const ai_real diff = max.x - min.x; const ai_real diff = max.x - min.x;
@ -236,116 +226,110 @@ void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector
// directly to the texture V axis. The other axis is derived from // directly to the texture V axis. The other axis is derived from
// the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where // the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where
// 'c' is the center point of the mesh. // 'c' is the center point of the mesh.
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D& pos = mesh->mVertices[pnt]; const aiVector3D &pos = mesh->mVertices[pnt];
aiVector3D& uv = out[pnt]; aiVector3D &uv = out[pnt];
uv.y = (pos.x - min.x) / diff; uv.y = (pos.x - min.x) / diff;
uv.x = (std::atan2( pos.z - center.z, pos.y - center.y) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; uv.x = (std::atan2(pos.z - center.z, pos.y - center.y) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
} }
} } else if (axis * base_axis_y >= angle_epsilon) {
else if (axis * base_axis_y >= angle_epsilon) {
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
const ai_real diff = max.y - min.y; const ai_real diff = max.y - min.y;
// just the same ... // just the same ...
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D& pos = mesh->mVertices[pnt]; const aiVector3D &pos = mesh->mVertices[pnt];
aiVector3D& uv = out[pnt]; aiVector3D &uv = out[pnt];
uv.y = (pos.y - min.y) / diff; uv.y = (pos.y - min.y) / diff;
uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; uv.x = (std::atan2(pos.x - center.x, pos.z - center.z) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
} }
} } else if (axis * base_axis_z >= angle_epsilon) {
else if (axis * base_axis_z >= angle_epsilon) {
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
const ai_real diff = max.z - min.z; const ai_real diff = max.z - min.z;
// just the same ... // just the same ...
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D& pos = mesh->mVertices[pnt]; const aiVector3D &pos = mesh->mVertices[pnt];
aiVector3D& uv = out[pnt]; aiVector3D &uv = out[pnt];
uv.y = (pos.z - min.z) / diff; uv.y = (pos.z - min.z) / diff;
uv.x = (std::atan2( pos.y - center.y, pos.x - center.x) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; uv.x = (std::atan2(pos.y - center.y, pos.x - center.x) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
} }
} }
// slower code path in case the mapping axis is not one of the coordinate system axes // slower code path in case the mapping axis is not one of the coordinate system axes
else { else {
aiMatrix4x4 mTrafo; aiMatrix4x4 mTrafo;
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
FindMeshCenterTransformed(mesh, center, min, max,mTrafo); FindMeshCenterTransformed(mesh, center, min, max, mTrafo);
const ai_real diff = max.y - min.y; const ai_real diff = max.y - min.y;
// again the same, except we're applying a transformation now // again the same, except we're applying a transformation now
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){ for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D pos = mTrafo* mesh->mVertices[pnt]; const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
aiVector3D& uv = out[pnt]; aiVector3D &uv = out[pnt];
uv.y = (pos.y - min.y) / diff; uv.y = (pos.y - min.y) / diff;
uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; uv.x = (std::atan2(pos.x - center.x, pos.z - center.z) + (ai_real)AI_MATH_PI) / (ai_real)AI_MATH_TWO_PI;
} }
} }
// Now find and remove UV seams. A seam occurs if a face has a tcoord // Now find and remove UV seams. A seam occurs if a face has a tcoord
// close to zero on the one side, and a tcoord close to one on the // close to zero on the one side, and a tcoord close to one on the
// other side. // other side.
RemoveUVSeams(mesh,out); RemoveUVSeams(mesh, out);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh *mesh, const aiVector3D &axis, aiVector3D *out) {
{ ai_real diffu, diffv;
ai_real diffu,diffv;
aiVector3D center, min, max; aiVector3D center, min, max;
// If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ...
// currently the mapping axis will always be one of x,y,z, except if the // currently the mapping axis will always be one of x,y,z, except if the
// PretransformVertices step is used (it transforms the meshes into worldspace, // PretransformVertices step is used (it transforms the meshes into worldspace,
// thus changing the mapping axis) // thus changing the mapping axis)
if (axis * base_axis_x >= angle_epsilon) { if (axis * base_axis_x >= angle_epsilon) {
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
diffu = max.z - min.z; diffu = max.z - min.z;
diffv = max.y - min.y; diffv = max.y - min.y;
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D& pos = mesh->mVertices[pnt]; const aiVector3D &pos = mesh->mVertices[pnt];
out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.0); out[pnt].Set((pos.z - min.z) / diffu, (pos.y - min.y) / diffv, 0.0);
} }
} } else if (axis * base_axis_y >= angle_epsilon) {
else if (axis * base_axis_y >= angle_epsilon) {
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
diffu = max.x - min.x; diffu = max.x - min.x;
diffv = max.z - min.z; diffv = max.z - min.z;
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D& pos = mesh->mVertices[pnt]; const aiVector3D &pos = mesh->mVertices[pnt];
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0); out[pnt].Set((pos.x - min.x) / diffu, (pos.z - min.z) / diffv, 0.0);
} }
} } else if (axis * base_axis_z >= angle_epsilon) {
else if (axis * base_axis_z >= angle_epsilon) {
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
diffu = max.x - min.x; diffu = max.x - min.x;
diffv = max.y - min.y; diffv = max.y - min.y;
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D& pos = mesh->mVertices[pnt]; const aiVector3D &pos = mesh->mVertices[pnt];
out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0); out[pnt].Set((pos.x - min.x) / diffu, (pos.y - min.y) / diffv, 0.0);
} }
} }
// slower code path in case the mapping axis is not one of the coordinate system axes // slower code path in case the mapping axis is not one of the coordinate system axes
else else {
{
aiMatrix4x4 mTrafo; aiMatrix4x4 mTrafo;
aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); aiMatrix4x4::FromToMatrix(axis, base_axis_y, mTrafo);
FindMeshCenterTransformed(mesh, center, min, max,mTrafo); FindMeshCenterTransformed(mesh, center, min, max, mTrafo);
diffu = max.x - min.x; diffu = max.x - min.x;
diffv = max.z - min.z; diffv = max.z - min.z;
// again the same, except we're applying a transformation now // again the same, except we're applying a transformation now
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices; ++pnt) {
const aiVector3D pos = mTrafo * mesh->mVertices[pnt]; const aiVector3D pos = mTrafo * mesh->mVertices[pnt];
out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0); out[pnt].Set((pos.x - min.x) / diffu, (pos.z - min.z) / diffv, 0.0);
} }
} }
@ -353,14 +337,12 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* ) void ComputeUVMappingProcess::ComputeBoxMapping(aiMesh *, aiVector3D *) {
{
ASSIMP_LOG_ERROR("Mapping type currently not implemented"); ASSIMP_LOG_ERROR("Mapping type currently not implemented");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::Execute( aiScene* pScene) void ComputeUVMappingProcess::Execute(aiScene *pScene) {
{
ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin"); ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
char buffer[1024]; char buffer[1024];
@ -371,23 +353,18 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
/* Iterate through all materials and search for non-UV mapped textures /* Iterate through all materials and search for non-UV mapped textures
*/ */
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
{
mappingStack.clear(); mappingStack.clear();
aiMaterial* mat = pScene->mMaterials[i]; aiMaterial *mat = pScene->mMaterials[i];
for (unsigned int a = 0; a < mat->mNumProperties;++a) for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
{ aiMaterialProperty *prop = mat->mProperties[a];
aiMaterialProperty* prop = mat->mProperties[a]; if (!::strcmp(prop->mKey.data, "$tex.mapping")) {
if (!::strcmp( prop->mKey.data, "$tex.mapping")) aiTextureMapping &mapping = *((aiTextureMapping *)prop->mData);
{ if (aiTextureMapping_UV != mapping) {
aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData); if (!DefaultLogger::isNullLogger()) {
if (aiTextureMapping_UV != mapping)
{
if (!DefaultLogger::isNullLogger())
{
ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s", ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
aiTextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex, aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex,
MappingTypeToString(mapping)); MappingTypeToString(mapping));
ASSIMP_LOG_INFO(buffer); ASSIMP_LOG_INFO(buffer);
} }
@ -395,70 +372,62 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
if (aiTextureMapping_OTHER == mapping) if (aiTextureMapping_OTHER == mapping)
continue; continue;
MappingInfo info (mapping); MappingInfo info(mapping);
// Get further properties - currently only the major axis // Get further properties - currently only the major axis
for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) for (unsigned int a2 = 0; a2 < mat->mNumProperties; ++a2) {
{ aiMaterialProperty *prop2 = mat->mProperties[a2];
aiMaterialProperty* prop2 = mat->mProperties[a2];
if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex)
continue; continue;
if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) { if (!::strcmp(prop2->mKey.data, "$tex.mapaxis")) {
info.axis = *((aiVector3D*)prop2->mData); info.axis = *((aiVector3D *)prop2->mData);
break; break;
} }
} }
unsigned int idx( 99999999 ); unsigned int idx(99999999);
// Check whether we have this mapping mode already // Check whether we have this mapping mode already
std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info); std::list<MappingInfo>::iterator it = std::find(mappingStack.begin(), mappingStack.end(), info);
if (mappingStack.end() != it) if (mappingStack.end() != it) {
{
idx = (*it).uv; idx = (*it).uv;
} } else {
else
{
/* We have found a non-UV mapped texture. Now /* We have found a non-UV mapped texture. Now
* we need to find all meshes using this material * we need to find all meshes using this material
* that we can compute UV channels for them. * that we can compute UV channels for them.
*/ */
for (unsigned int m = 0; m < pScene->mNumMeshes;++m) for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
{ aiMesh *mesh = pScene->mMeshes[m];
aiMesh* mesh = pScene->mMeshes[m];
unsigned int outIdx = 0; unsigned int outIdx = 0;
if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX || if (mesh->mMaterialIndex != i || (outIdx = FindEmptyUVChannel(mesh)) == UINT_MAX ||
!mesh->mNumVertices) !mesh->mNumVertices) {
{
continue; continue;
} }
// Allocate output storage // Allocate output storage
aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices]; aiVector3D *p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices];
switch (mapping) switch (mapping) {
{
case aiTextureMapping_SPHERE: case aiTextureMapping_SPHERE:
ComputeSphereMapping(mesh,info.axis,p); ComputeSphereMapping(mesh, info.axis, p);
break; break;
case aiTextureMapping_CYLINDER: case aiTextureMapping_CYLINDER:
ComputeCylinderMapping(mesh,info.axis,p); ComputeCylinderMapping(mesh, info.axis, p);
break; break;
case aiTextureMapping_PLANE: case aiTextureMapping_PLANE:
ComputePlaneMapping(mesh,info.axis,p); ComputePlaneMapping(mesh, info.axis, p);
break; break;
case aiTextureMapping_BOX: case aiTextureMapping_BOX:
ComputeBoxMapping(mesh,p); ComputeBoxMapping(mesh, p);
break; break;
default: default:
ai_assert(false); ai_assert(false);
} }
if (m && idx != outIdx) if (m && idx != outIdx) {
{
ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to " ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to "
"this material have equal numbers of UV channels. The UV index stored in " "this material have equal numbers of UV channels. The UV index stored in "
"the material structure does therefore not apply for all meshes. "); "the material structure does therefore not apply for all meshes. ");
} }
idx = outIdx; idx = outIdx;
} }
@ -468,7 +437,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
// Update the material property list // Update the material property list
mapping = aiTextureMapping_UV; mapping = aiTextureMapping_UV;
((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex)); ((aiMaterial *)mat)->AddProperty(&idx, 1, AI_MATKEY_UVWSRC(prop->mSemantic, prop->mIndex));
} }
} }
} }

View File

@ -42,27 +42,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/** @file Implementation of the post processing step to drop face /** @file Implementation of the post processing step to drop face
* normals for all imported faces. * normals for all imported faces.
*/ */
#include "DropFaceNormalsProcess.h" #include "DropFaceNormalsProcess.h"
#include <assimp/Exceptional.h>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Exceptional.h>
using namespace Assimp; using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const { bool DropFaceNormalsProcess::IsActive(unsigned int pFlags) const {
return (pFlags & aiProcess_DropNormals) != 0; return (pFlags & aiProcess_DropNormals) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void DropFaceNormalsProcess::Execute( aiScene* pScene) { void DropFaceNormalsProcess::Execute(aiScene *pScene) {
ASSIMP_LOG_DEBUG("DropFaceNormalsProcess begin"); ASSIMP_LOG_DEBUG("DropFaceNormalsProcess begin");
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
@ -70,21 +69,21 @@ void DropFaceNormalsProcess::Execute( aiScene* pScene) {
} }
bool bHas = false; bool bHas = false;
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
bHas |= this->DropMeshFaceNormals( pScene->mMeshes[a]); bHas |= this->DropMeshFaceNormals(pScene->mMeshes[a]);
} }
if (bHas) { if (bHas) {
ASSIMP_LOG_INFO("DropFaceNormalsProcess finished. " ASSIMP_LOG_INFO("DropFaceNormalsProcess finished. "
"Face normals have been removed"); "Face normals have been removed");
} else { } else {
ASSIMP_LOG_DEBUG("DropFaceNormalsProcess finished. " ASSIMP_LOG_DEBUG("DropFaceNormalsProcess finished. "
"No normals were present"); "No normals were present");
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
bool DropFaceNormalsProcess::DropMeshFaceNormals (aiMesh* mesh) { bool DropFaceNormalsProcess::DropMeshFaceNormals(aiMesh *mesh) {
ai_assert(nullptr != mesh); ai_assert(nullptr != mesh);
if (nullptr == mesh->mNormals) { if (nullptr == mesh->mNormals) {

View File

@ -41,11 +41,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file FindDegenerates.cpp /** @file FindDegenerates.cpp
* @brief Implementation of the FindDegenerates post-process step. * @brief Implementation of the FindDegenerates post-process step.
*/ */
#include "ProcessHelper.h"
#include "FindDegenerates.h" #include "FindDegenerates.h"
#include "Geometry/GeometryUtils.h" #include "Geometry/GeometryUtils.h"
#include "ProcessHelper.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
@ -54,35 +54,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
// Correct node indices to meshes and remove references to deleted mesh // Correct node indices to meshes and remove references to deleted mesh
static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap); static void updateSceneGraph(aiNode *pNode, const std::unordered_map<unsigned int, unsigned int> &meshMap);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
FindDegeneratesProcess::FindDegeneratesProcess() : FindDegeneratesProcess::FindDegeneratesProcess() :
mConfigRemoveDegenerates( false ), mConfigRemoveDegenerates(false),
mConfigCheckAreaOfTriangle( false ){ mConfigCheckAreaOfTriangle(false) {
// empty // empty
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const { bool FindDegeneratesProcess::IsActive(unsigned int pFlags) const {
return 0 != (pFlags & aiProcess_FindDegenerates); return 0 != (pFlags & aiProcess_FindDegenerates);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup import configuration // Setup import configuration
void FindDegeneratesProcess::SetupProperties(const Importer* pImp) { void FindDegeneratesProcess::SetupProperties(const Importer *pImp) {
// Get the current value of AI_CONFIG_PP_FD_REMOVE // Get the current value of AI_CONFIG_PP_FD_REMOVE
mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0)); mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE, 0));
mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) ); mConfigCheckAreaOfTriangle = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void FindDegeneratesProcess::Execute( aiScene* pScene) { void FindDegeneratesProcess::Execute(aiScene *pScene) {
ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin"); ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
if ( nullptr == pScene) { if (nullptr == pScene) {
return; return;
} }
@ -112,7 +112,7 @@ void FindDegeneratesProcess::Execute( aiScene* pScene) {
ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished"); ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
} }
static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap) { static void updateSceneGraph(aiNode *pNode, const std::unordered_map<unsigned int, unsigned int> &meshMap) {
unsigned int targetIndex = 0; unsigned int targetIndex = 0;
for (unsigned i = 0; i < pNode->mNumMeshes; ++i) { for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
const unsigned int sourceMeshIndex = pNode->mMeshes[i]; const unsigned int sourceMeshIndex = pNode->mMeshes[i];
@ -123,7 +123,7 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned in
} }
} }
pNode->mNumMeshes = targetIndex; pNode->mNumMeshes = targetIndex;
//recurse to all children // recurse to all children
for (unsigned i = 0; i < pNode->mNumChildren; ++i) { for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
updateSceneGraph(pNode->mChildren[i], meshMap); updateSceneGraph(pNode->mChildren[i], meshMap);
} }
@ -131,17 +131,17 @@ static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned in
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported mesh // Executes the post processing step on the given imported mesh
bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { bool FindDegeneratesProcess::ExecuteOnMesh(aiMesh *mesh) {
mesh->mPrimitiveTypes = 0; mesh->mPrimitiveTypes = 0;
std::vector<bool> remove_me; std::vector<bool> remove_me;
if (mConfigRemoveDegenerates) { if (mConfigRemoveDegenerates) {
remove_me.resize( mesh->mNumFaces, false ); remove_me.resize(mesh->mNumFaces, false);
} }
unsigned int deg = 0, limit; unsigned int deg = 0, limit;
for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) { for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
aiFace& face = mesh->mFaces[a]; aiFace &face = mesh->mFaces[a];
bool first = true; bool first = true;
// check whether the face contains degenerated entries // check whether the face contains degenerated entries
@ -151,43 +151,43 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
// double points may not come directly after another. // double points may not come directly after another.
limit = face.mNumIndices; limit = face.mNumIndices;
if (face.mNumIndices > 4) { if (face.mNumIndices > 4) {
limit = std::min( limit, i+2 ); limit = std::min(limit, i + 2);
} }
for (unsigned int t = i+1; t < limit; ++t) { for (unsigned int t = i + 1; t < limit; ++t) {
if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) { if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]]) {
// we have found a matching vertex position // we have found a matching vertex position
// remove the corresponding index from the array // remove the corresponding index from the array
--face.mNumIndices; --face.mNumIndices;
--limit; --limit;
for (unsigned int m = t; m < face.mNumIndices; ++m) { for (unsigned int m = t; m < face.mNumIndices; ++m) {
face.mIndices[ m ] = face.mIndices[ m+1 ]; face.mIndices[m] = face.mIndices[m + 1];
} }
--t; --t;
// NOTE: we set the removed vertex index to an unique value // NOTE: we set the removed vertex index to an unique value
// to make sure the developer gets notified when his // to make sure the developer gets notified when his
// application attempts to access this data. // application attempts to access this data.
face.mIndices[ face.mNumIndices ] = 0xdeadbeef; face.mIndices[face.mNumIndices] = 0xdeadbeef;
if(first) { if (first) {
++deg; ++deg;
first = false; first = false;
} }
if ( mConfigRemoveDegenerates ) { if (mConfigRemoveDegenerates) {
remove_me[ a ] = true; remove_me[a] = true;
goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby! goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
} }
} }
} }
if ( mConfigCheckAreaOfTriangle ) { if (mConfigCheckAreaOfTriangle) {
if ( face.mNumIndices == 3 ) { if (face.mNumIndices == 3) {
ai_real area = GeometryUtils::calculateAreaOfTriangle( face, mesh ); ai_real area = GeometryUtils::calculateAreaOfTriangle(face, mesh);
if (area < ai_epsilon) { if (area < ai_epsilon) {
if ( mConfigRemoveDegenerates ) { if (mConfigRemoveDegenerates) {
remove_me[ a ] = true; remove_me[a] = true;
++deg; ++deg;
goto evil_jump_outside; goto evil_jump_outside;
} }
@ -199,8 +199,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
} }
// We need to update the primitive flags array of the mesh. // We need to update the primitive flags array of the mesh.
switch (face.mNumIndices) switch (face.mNumIndices) {
{
case 1u: case 1u:
mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; mesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
break; break;
@ -214,22 +213,21 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
break; break;
}; };
evil_jump_outside: evil_jump_outside:
continue; continue;
} }
// If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
if (mConfigRemoveDegenerates && deg) { if (mConfigRemoveDegenerates && deg) {
unsigned int n = 0; unsigned int n = 0;
for (unsigned int a = 0; a < mesh->mNumFaces; ++a) for (unsigned int a = 0; a < mesh->mNumFaces; ++a) {
{ aiFace &face_src = mesh->mFaces[a];
aiFace& face_src = mesh->mFaces[a];
if (!remove_me[a]) { if (!remove_me[a]) {
aiFace& face_dest = mesh->mFaces[n++]; aiFace &face_dest = mesh->mFaces[n++];
// Do a manual copy, keep the index array // Do a manual copy, keep the index array
face_dest.mNumIndices = face_src.mNumIndices; face_dest.mNumIndices = face_src.mNumIndices;
face_dest.mIndices = face_src.mIndices; face_dest.mIndices = face_src.mIndices;
if (&face_src != &face_dest) { if (&face_src != &face_dest) {
// clear source // clear source
@ -246,15 +244,15 @@ evil_jump_outside:
// Just leave the rest of the array unreferenced, we don't care for now // Just leave the rest of the array unreferenced, we don't care for now
mesh->mNumFaces = n; mesh->mNumFaces = n;
if (!mesh->mNumFaces) { if (!mesh->mNumFaces) {
//The whole mesh consists of degenerated faces // The whole mesh consists of degenerated faces
//signal upward, that this mesh should be deleted. // signal upward, that this mesh should be deleted.
ASSIMP_LOG_VERBOSE_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives"); ASSIMP_LOG_VERBOSE_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
return true; return true;
} }
} }
if (deg && !DefaultLogger::isNullLogger()) { if (deg && !DefaultLogger::isNullLogger()) {
ASSIMP_LOG_WARN( "Found ", deg, " degenerated primitives"); ASSIMP_LOG_WARN("Found ", deg, " degenerated primitives");
} }
return false; return false;
} }

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -41,9 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
*/ */
/** @file PretransformVertices.cpp /// @file PretransformVertices.cpp
* @brief Implementation of the "PretransformVertices" post processing step /// @brief Implementation of the "PretransformVertices" post processing step
*/
#include "PretransformVertices.h" #include "PretransformVertices.h"
#include "ConvertToLHProcess.h" #include "ConvertToLHProcess.h"
@ -57,16 +54,44 @@ using namespace Assimp;
#define AI_PTVS_VERTEX 0x0 #define AI_PTVS_VERTEX 0x0
#define AI_PTVS_FACE 0x1 #define AI_PTVS_FACE 0x1
namespace {
// Get a bitwise combination identifying the vertex format of a mesh
static unsigned int GetMeshVFormat(aiMesh *pcMesh) {
// 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;
}
// Get a list of all vertex formats that occur for a given material index
// The output list contains duplicate elements
static void GetVFormatList(const aiScene *pcScene, unsigned int iMat, std::list<unsigned int> &aiOut) {
for (unsigned int i = 0; i < pcScene->mNumMeshes; ++i) {
aiMesh *pcMesh = pcScene->mMeshes[i];
if (iMat == pcMesh->mMaterialIndex) {
aiOut.push_back(GetMeshVFormat(pcMesh));
}
}
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
PretransformVertices::PretransformVertices() : PretransformVertices::PretransformVertices() :
configKeepHierarchy(false), mConfigKeepHierarchy(false),
configNormalize(false), mConfigNormalize(false),
configTransform(false), mConfigTransform(false),
configTransformation(), mConfigTransformation(),
mConfigPointCloud(false) { mConfigPointCloud(false) {}
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
@ -79,11 +104,11 @@ bool PretransformVertices::IsActive(unsigned int pFlags) const {
void PretransformVertices::SetupProperties(const Importer *pImp) { void PretransformVertices::SetupProperties(const Importer *pImp) {
// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE, // 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 // 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)); mConfigKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY, 0));
configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0)); mConfigNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE, 0));
configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0)); mConfigTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION, 0));
configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4()); mConfigTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4());
mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
} }
@ -99,25 +124,7 @@ unsigned int PretransformVertices::CountNodes(const aiNode *pcNode) const {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get a bitwise combination identifying the vertex format of a mesh // Count the number of vertices in the whole scene and a given material index
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;
}
// ------------------------------------------------------------------------------------------------
// Count the number of vertices in the whole scene and a given
// material index
void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat, void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const aiNode *pcNode, unsigned int iMat,
unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const { unsigned int iVFormat, unsigned int *piFaces, unsigned int *piVertices) const {
for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) { for (unsigned int i = 0; i < pcNode->mNumMeshes; ++i) {
@ -128,8 +135,7 @@ void PretransformVertices::CountVerticesAndFaces(const aiScene *pcScene, const a
} }
} }
for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) { for (unsigned int i = 0; i < pcNode->mNumChildren; ++i) {
CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat, CountVerticesAndFaces(pcScene, pcNode->mChildren[i], iMat, iVFormat, piFaces, piVertices);
iVFormat, piFaces, piVertices);
} }
} }
@ -272,19 +278,6 @@ void PretransformVertices::CollectData(const aiScene *pcScene, const aiNode *pcN
} }
} }
// ------------------------------------------------------------------------------------------------
// Get a list of all vertex formats that occur for a given material index
// The output list contains duplicate elements
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));
}
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Compute the absolute transformation matrices of each node // Compute the absolute transformation matrices of each node
void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) { void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) {
@ -297,39 +290,44 @@ void PretransformVertices::ComputeAbsoluteTransform(aiNode *pcNode) {
} }
} }
static void normalizeVectorArray(aiVector3D *vectorArrayIn, aiVector3D *vectorArrayOut, size_t numVectors) {
for (size_t i=0; i<numVectors; ++i) {
vectorArrayOut[i] = vectorArrayIn[i].Normalize();
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Apply the node transformation to a mesh // Apply the node transformation to a mesh
void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const { void PretransformVertices::ApplyTransform(aiMesh *mesh, const aiMatrix4x4 &mat) const {
// Check whether we need to transform the coordinates at all // Check whether we need to transform the coordinates at all
if (!mat.IsIdentity()) { if (mat.IsIdentity()) {
return;
}
// Check for odd negative scale (mirror) // Check for odd negative scale (mirror)
if (mesh->HasFaces() && mat.Determinant() < 0) { if (mesh->HasFaces() && mat.Determinant() < 0) {
// Reverse the mesh face winding order // Reverse the mesh face winding order
FlipWindingOrderProcess::ProcessMesh(mesh); 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 positions // Update normals and tangents
if (mesh->HasPositions()) { if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
const aiMatrix3x3 m = aiMatrix3x3(mat).Inverse().Transpose();
if (mesh->HasNormals()) {
normalizeVectorArray(mesh->mNormals, mesh->mNormals, mesh->mNumVertices);
}
if (mesh->HasTangentsAndBitangents()) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
mesh->mVertices[i] = mat * mesh->mVertices[i]; mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize();
} mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
}
// 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();
}
} }
} }
} }
@ -352,40 +350,41 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh *> &out, aiMesh **i
// yes, we can. // yes, we can.
mesh->mBones = reinterpret_cast<aiBone **>(&node->mTransformation); mesh->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
mesh->mNumBones = UINT_MAX; mesh->mNumBones = UINT_MAX;
} else { continue;
}
// try to find us in the list of newly created meshes // try to find us in the list of newly created meshes
for (unsigned int n = 0; n < out.size(); ++n) { for (unsigned int n = 0; n < out.size(); ++n) {
aiMesh *ctz = out[n]; aiMesh *ctz = out[n];
if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4 *>(ctz->mBones) == node->mTransformation) { if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4 *>(ctz->mBones) == node->mTransformation) {
// ok, use this one. Update node mesh index // ok, use this one. Update node mesh index
node->mMeshes[i] = numIn + n; node->mMeshes[i] = numIn + n;
}
} }
if (node->mMeshes[i] < numIn) { }
// Worst case. Need to operate on a full copy of the mesh if (node->mMeshes[i] < numIn) {
ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms"); // Worst case. Need to operate on a full copy of the mesh
aiMesh *ntz; ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms");
aiMesh *ntz;
const unsigned int tmp = mesh->mNumBones; // const unsigned int cacheNumBones = mesh->mNumBones; //
mesh->mNumBones = 0; mesh->mNumBones = 0;
SceneCombiner::Copy(&ntz, mesh); SceneCombiner::Copy(&ntz, mesh);
mesh->mNumBones = tmp; mesh->mNumBones = cacheNumBones;
ntz->mNumBones = node->mMeshes[i]; ntz->mNumBones = node->mMeshes[i];
ntz->mBones = reinterpret_cast<aiBone **>(&node->mTransformation); ntz->mBones = reinterpret_cast<aiBone **>(&node->mTransformation);
out.push_back(ntz); out.push_back(ntz);
node->mMeshes[i] = static_cast<unsigned int>(numIn + out.size() - 1); node->mMeshes[i] = static_cast<unsigned int>(numIn + out.size() - 1);
}
} }
} }
// call children // call children
for (unsigned int i = 0; i < node->mNumChildren; ++i) for (unsigned int i = 0; i < node->mNumChildren; ++i) {
BuildWCSMeshes(out, in, numIn, node->mChildren[i]); BuildWCSMeshes(out, in, numIn, node->mChildren[i]);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -394,8 +393,9 @@ void PretransformVertices::MakeIdentityTransform(aiNode *nd) const {
nd->mTransformation = aiMatrix4x4(); nd->mTransformation = aiMatrix4x4();
// call children // call children
for (unsigned int i = 0; i < nd->mNumChildren; ++i) for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
MakeIdentityTransform(nd->mChildren[i]); MakeIdentityTransform(nd->mChildren[i]);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -405,8 +405,27 @@ void PretransformVertices::BuildMeshRefCountArray(const aiNode *nd, unsigned int
refs[nd->mMeshes[i]]++; refs[nd->mMeshes[i]]++;
// call children // call children
for (unsigned int i = 0; i < nd->mNumChildren; ++i) for (unsigned int i = 0; i < nd->mNumChildren; ++i) {
BuildMeshRefCountArray(nd->mChildren[i], refs); BuildMeshRefCountArray(nd->mChildren[i], refs);
}
}
// ------------------------------------------------------------------------------------------------
static void appendNewMeshesToScene(aiScene *pScene, std::vector<aiMesh*> &apcOutMeshes) {
ai_assert(pScene != nullptr);
if (apcOutMeshes.empty()) {
return;
}
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;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -418,12 +437,12 @@ void PretransformVertices::Execute(aiScene *pScene) {
if (!pScene->mNumMeshes) if (!pScene->mNumMeshes)
return; return;
const unsigned int iOldMeshes = pScene->mNumMeshes; const unsigned int oldMeshes = pScene->mNumMeshes;
const unsigned int iOldAnimationChannels = pScene->mNumAnimations; const unsigned int oldAnimationChannels = pScene->mNumAnimations;
const unsigned int iOldNodes = CountNodes(pScene->mRootNode); const unsigned int oldNodes = CountNodes(pScene->mRootNode);
if (configTransform) { if (mConfigTransform) {
pScene->mRootNode->mTransformation = configTransformation * pScene->mRootNode->mTransformation; pScene->mRootNode->mTransformation = mConfigTransformation * pScene->mRootNode->mTransformation;
} }
// first compute absolute transformation matrices for all nodes // first compute absolute transformation matrices for all nodes
@ -449,22 +468,13 @@ void PretransformVertices::Execute(aiScene *pScene) {
// we go on and transform all meshes, if one is referenced by nodes // we go on and transform all meshes, if one is referenced by nodes
// with different absolute transformations a depth copy of the mesh // with different absolute transformations a depth copy of the mesh
// is required. // is required.
if (configKeepHierarchy) { if (mConfigKeepHierarchy) {
// Hack: store the matrix we're transforming a mesh with in aiMesh::mBones // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones
BuildWCSMeshes(apcOutMeshes, pScene->mMeshes, pScene->mNumMeshes, pScene->mRootNode); BuildWCSMeshes(apcOutMeshes, pScene->mMeshes, pScene->mNumMeshes, pScene->mRootNode);
// ... if new meshes have been generated, append them to the end of the scene // ... if new meshes have been generated, append them to the end of the scene
if (apcOutMeshes.size() > 0) { appendNewMeshesToScene(pScene, apcOutMeshes);
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;
}
// now iterate through all meshes and transform them to world-space // now iterate through all meshes and transform them to world-space
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
@ -488,34 +498,35 @@ void PretransformVertices::Execute(aiScene *pScene) {
aiVFormats.sort(); aiVFormats.sort();
aiVFormats.unique(); aiVFormats.unique();
for (std::list<unsigned int>::const_iterator j = aiVFormats.begin(); j != aiVFormats.end(); ++j) { for (std::list<unsigned int>::const_iterator j = aiVFormats.begin(); j != aiVFormats.end(); ++j) {
unsigned int iVertices = 0; unsigned int numVertices = 0u;
unsigned int iFaces = 0; unsigned int numFaces = 0u;
CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &iFaces, &iVertices); CountVerticesAndFaces(pScene, pScene->mRootNode, i, *j, &numFaces, &numVertices);
if (0 != iFaces && 0 != iVertices) { if (0 != numFaces && 0 != numVertices) {
apcOutMeshes.push_back(new aiMesh()); apcOutMeshes.push_back(new aiMesh());
aiMesh *pcMesh = apcOutMeshes.back(); aiMesh *pcMesh = apcOutMeshes.back();
pcMesh->mNumFaces = iFaces; pcMesh->mNumFaces = numFaces;
pcMesh->mNumVertices = iVertices; pcMesh->mNumVertices = numVertices;
pcMesh->mFaces = new aiFace[iFaces]; pcMesh->mFaces = new aiFace[numFaces];
pcMesh->mVertices = new aiVector3D[iVertices]; pcMesh->mVertices = new aiVector3D[numVertices];
pcMesh->mMaterialIndex = i; pcMesh->mMaterialIndex = i;
if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[iVertices]; if ((*j) & 0x2) pcMesh->mNormals = new aiVector3D[numVertices];
if ((*j) & 0x4) { if ((*j) & 0x4) {
pcMesh->mTangents = new aiVector3D[iVertices]; pcMesh->mTangents = new aiVector3D[numVertices];
pcMesh->mBitangents = new aiVector3D[iVertices]; pcMesh->mBitangents = new aiVector3D[numVertices];
} }
iFaces = 0; numFaces = 0;
while ((*j) & (0x100 << iFaces)) { while ((*j) & (0x100 << numFaces)) {
pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; pcMesh->mTextureCoords[numFaces] = new aiVector3D[numVertices];
if ((*j) & (0x10000 << iFaces)) if ((*j) & (0x10000 << numFaces)) {
pcMesh->mNumUVComponents[iFaces] = 3; pcMesh->mNumUVComponents[numFaces] = 3;
else } else {
pcMesh->mNumUVComponents[iFaces] = 2; pcMesh->mNumUVComponents[numFaces] = 2;
iFaces++; }
++numFaces;
} }
iFaces = 0; numFaces = 0;
while ((*j) & (0x1000000 << iFaces)) while ((*j) & (0x1000000 << numFaces))
pcMesh->mColors[iFaces++] = new aiColor4D[iVertices]; pcMesh->mColors[numFaces++] = new aiColor4D[numVertices];
// fill the mesh ... // fill the mesh ...
unsigned int aiTemp[2] = { 0, 0 }; unsigned int aiTemp[2] = { 0, 0 };
@ -593,7 +604,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp; l->mUp = aiMatrix3x3(nd->mTransformation) * l->mUp;
} }
if (!configKeepHierarchy) { if (!mConfigKeepHierarchy) {
// now delete all nodes in the scene and build a new // now delete all nodes in the scene and build a new
// flat node graph with a root node and some level 1 children // flat node graph with a root node and some level 1 children
@ -644,7 +655,7 @@ void PretransformVertices::Execute(aiScene *pScene) {
MakeIdentityTransform(pScene->mRootNode); MakeIdentityTransform(pScene->mRootNode);
} }
if (configNormalize) { if (mConfigNormalize) {
// compute the boundary of all meshes // compute the boundary of all meshes
aiVector3D min, max; aiVector3D min, max;
MinMaxChooser<aiVector3D>()(min, max); MinMaxChooser<aiVector3D>()(min, max);
@ -674,9 +685,9 @@ void PretransformVertices::Execute(aiScene *pScene) {
if (!DefaultLogger::isNullLogger()) { if (!DefaultLogger::isNullLogger()) {
ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished"); ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished");
ASSIMP_LOG_INFO("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (", ASSIMP_LOG_INFO("Removed ", oldNodes, " nodes and ", oldAnimationChannels, " animation channels (",
CountNodes(pScene->mRootNode), " output nodes)"); CountNodes(pScene->mRootNode), " output nodes)");
ASSIMP_LOG_INFO("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras."); ASSIMP_LOG_INFO("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras.");
ASSIMP_LOG_INFO("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")"); ASSIMP_LOG_INFO("Moved ", oldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")");
} }
} }

View File

@ -90,7 +90,7 @@ public:
* @param keep true for keep configuration. * @param keep true for keep configuration.
*/ */
void KeepHierarchy(bool keep) { void KeepHierarchy(bool keep) {
configKeepHierarchy = keep; mConfigKeepHierarchy = keep;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -98,7 +98,7 @@ public:
* @return ... * @return ...
*/ */
bool IsHierarchyKept() const { bool IsHierarchyKept() const {
return configKeepHierarchy; return mConfigKeepHierarchy;
} }
private: private:
@ -108,7 +108,7 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get a bitwise combination identifying the vertex format of a mesh // Get a bitwise combination identifying the vertex format of a mesh
unsigned int GetMeshVFormat(aiMesh *pcMesh) const; //unsigned int GetMeshVFormat(aiMesh *pcMesh) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Count the number of vertices in the whole scene and a given // Count the number of vertices in the whole scene and a given
@ -131,8 +131,8 @@ private:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Get a list of all vertex formats that occur for a given material // Get a list of all vertex formats that occur for a given material
// The output list contains duplicate elements // The output list contains duplicate elements
void GetVFormatList(const aiScene *pcScene, unsigned int iMat, /*void GetVFormatList(const aiScene *pcScene, unsigned int iMat,
std::list<unsigned int> &aiOut) const; std::list<unsigned int> &aiOut) const;*/
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Compute the absolute transformation matrices of each node // Compute the absolute transformation matrices of each node
@ -156,10 +156,10 @@ private:
void BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const; void BuildMeshRefCountArray(const aiNode *nd, unsigned int *refs) const;
//! Configuration option: keep scene hierarchy as long as possible //! Configuration option: keep scene hierarchy as long as possible
bool configKeepHierarchy; bool mConfigKeepHierarchy;
bool configNormalize; bool mConfigNormalize;
bool configTransform; bool mConfigTransform;
aiMatrix4x4 configTransformation; aiMatrix4x4 mConfigTransformation;
bool mConfigPointCloud; bool mConfigPointCloud;
}; };

View File

@ -175,10 +175,9 @@ unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh) {
// tangents and bitangents // tangents and bitangents
if (pcMesh->HasTangentsAndBitangents()) iRet |= 0x4; if (pcMesh->HasTangentsAndBitangents()) iRet |= 0x4;
#ifdef BOOST_STATIC_ASSERT
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS); static_assert(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); static_assert(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS);
#endif
// texture coordinates // texture coordinates
unsigned int p = 0; unsigned int p = 0;

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -45,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
// internal headers // internal headers
#include "RemoveRedundantMaterials.h" #include "RemoveRedundantMaterials.h"
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include "ProcessHelper.h" #include "ProcessHelper.h"
@ -57,35 +54,28 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() : mConfigFixedMaterials() {}
: mConfigFixedMaterials() {
// nothing to do here
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const {
{
return (pFlags & aiProcess_RemoveRedundantMaterials) != 0; return (pFlags & aiProcess_RemoveRedundantMaterials) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup import properties // Setup import properties
void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) {
{
// Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST
mConfigFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,""); mConfigFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,"");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void RemoveRedundantMatsProcess::Execute( aiScene* pScene) void RemoveRedundantMatsProcess::Execute( aiScene* pScene) {
{
ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin"); ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin");
unsigned int redundantRemoved = 0, unreferencedRemoved = 0; unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
if (pScene->mNumMaterials) if (pScene->mNumMaterials) {
{
// Find out which materials are referenced by meshes // Find out which materials are referenced by meshes
std::vector<bool> abReferenced(pScene->mNumMaterials,false); std::vector<bool> abReferenced(pScene->mNumMaterials,false);
for (unsigned int i = 0;i < pScene->mNumMeshes;++i) for (unsigned int i = 0;i < pScene->mNumMeshes;++i)
@ -134,8 +124,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
// we do already have a specific hash. This allows us to // we do already have a specific hash. This allows us to
// determine which materials are identical. // determine which materials are identical.
uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];;
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) for (unsigned int i = 0; i < pScene->mNumMaterials;++i) {
{
// No mesh is referencing this material, remove it. // No mesh is referencing this material, remove it.
if (!abReferenced[i]) { if (!abReferenced[i]) {
++unreferencedRemoved; ++unreferencedRemoved;
@ -147,8 +136,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
// Check all previously mapped materials for a matching hash. // Check all previously mapped materials for a matching hash.
// On a match we can delete this material and just make it ref to the same index. // On a match we can delete this material and just make it ref to the same index.
uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]); uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
for (unsigned int a = 0; a < i;++a) for (unsigned int a = 0; a < i;++a) {
{
if (abReferenced[a] && me == aiHashes[a]) { if (abReferenced[a] && me == aiHashes[a]) {
++redundantRemoved; ++redundantRemoved;
me = 0; me = 0;
@ -205,12 +193,9 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
delete[] aiHashes; delete[] aiHashes;
delete[] aiMappingTable; delete[] aiMappingTable;
} }
if (redundantRemoved == 0 && unreferencedRemoved == 0) if (redundantRemoved == 0 && unreferencedRemoved == 0) {
{
ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished "); ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished ");
} } else {
else
{
ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ", ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ",
unreferencedRemoved, " unused materials."); unreferencedRemoved, " unused materials.");
} }

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -99,8 +99,9 @@ void UpdateNodes(const std::vector<unsigned int> &replaceMeshIndex, aiNode *node
} }
// call all subnodes recursively // call all subnodes recursively
for (unsigned int m = 0; m < node->mNumChildren; ++m) for (unsigned int m = 0; m < node->mNumChildren; ++m) {
UpdateNodes(replaceMeshIndex, node->mChildren[m]); UpdateNodes(replaceMeshIndex, node->mChildren[m]);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -57,9 +57,7 @@ using namespace Assimp::Formatter;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor // Constructor
SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) { SplitByBoneCountProcess::SplitByBoneCountProcess() : mMaxBoneCount(AI_SBBC_DEFAULT_MAX_BONES) {}
// empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag. // Returns whether the processing step is present in the given flag.

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -40,9 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
/** /// @file Implementation of the SplitLargeMeshes postprocessing step
* @file Implementation of the SplitLargeMeshes postprocessing step
*/
// internal headers of the post-processing framework // internal headers of the post-processing framework
#include "SplitLargeMeshes.h" #include "SplitLargeMeshes.h"
@ -75,22 +72,22 @@ void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) {
this->SplitMesh(a, pScene->mMeshes[a],avList); this->SplitMesh(a, pScene->mMeshes[a],avList);
} }
if (avList.size() != pScene->mNumMeshes) { if (avList.size() == pScene->mNumMeshes) {
// it seems something has been split. rebuild the mesh list
delete[] pScene->mMeshes;
pScene->mNumMeshes = (unsigned int)avList.size();
pScene->mMeshes = new aiMesh*[avList.size()];
for (unsigned int i = 0; i < avList.size();++i) {
pScene->mMeshes[i] = avList[i].first;
}
// now we need to update all nodes
this->UpdateNode(pScene->mRootNode,avList);
ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
} else {
ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do"); ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
} }
// it seems something has been split. rebuild the mesh list
delete[] pScene->mMeshes;
pScene->mNumMeshes = (unsigned int)avList.size();
pScene->mMeshes = new aiMesh*[avList.size()];
for (unsigned int i = 0; i < avList.size();++i) {
pScene->mMeshes[i] = avList[i].first;
}
// now we need to update all nodes
this->UpdateNode(pScene->mRootNode,avList);
ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -102,8 +99,7 @@ void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Update a node after some meshes have been split // Update a node after some meshes have been split
void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
// for every index in out list build a new entry // for every index in out list build a new entry
std::vector<unsigned int> aiEntries; std::vector<unsigned int> aiEntries;
aiEntries.reserve(pcNode->mNumMeshes + 1); aiEntries.reserve(pcNode->mNumMeshes + 1);

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -42,8 +41,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/** @file A helper class that processes texture transformations */ /** @file A helper class that processes texture transformations */
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
@ -494,8 +491,9 @@ void TextureTransformStep::Execute( aiScene* pScene) {
ai_assert(nullptr != src); ai_assert(nullptr != src);
// Copy the data to the destination array // Copy the data to the destination array
if (dest != src) if (dest != src) {
::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices); ::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices);
}
end = dest + mesh->mNumVertices; end = dest + mesh->mNumVertices;

View File

@ -158,15 +158,13 @@ namespace {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool TriangulateProcess::IsActive( unsigned int pFlags) const bool TriangulateProcess::IsActive( unsigned int pFlags) const {
{
return (pFlags & aiProcess_Triangulate) != 0; return (pFlags & aiProcess_Triangulate) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void TriangulateProcess::Execute( aiScene* pScene) void TriangulateProcess::Execute( aiScene* pScene) {
{
ASSIMP_LOG_DEBUG("TriangulateProcess begin"); ASSIMP_LOG_DEBUG("TriangulateProcess begin");
bool bHas = false; bool bHas = false;
@ -187,8 +185,7 @@ void TriangulateProcess::Execute( aiScene* pScene)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Triangulates the given mesh. // Triangulates the given mesh.
bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) {
{
// Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
if (!pMesh->mPrimitiveTypes) { if (!pMesh->mPrimitiveTypes) {
bool bNeed = false; bool bNeed = false;
@ -218,8 +215,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
if( face.mNumIndices <= 3) { if( face.mNumIndices <= 3) {
numOut++; numOut++;
} } else {
else {
numOut += face.mNumIndices-2; numOut += face.mNumIndices-2;
max_out = std::max(max_out,face.mNumIndices); max_out = std::max(max_out,face.mNumIndices);
} }
@ -511,22 +507,6 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
#endif #endif
num = 0; num = 0;
break; break;
/*curOut -= (max-num); // undo all previous work
for (tmp = 0; tmp < max-2; ++tmp) {
aiFace& nface = *curOut++;
nface.mNumIndices = 3;
if (!nface.mIndices)
nface.mIndices = new unsigned int[3];
nface.mIndices[0] = 0;
nface.mIndices[1] = tmp+1;
nface.mIndices[2] = tmp+2;
}
num = 0;
break;*/
} }
aiFace& nface = *curOut++; aiFace& nface = *curOut++;
@ -580,23 +560,6 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
for(aiFace* f = last_face; f != curOut; ) { for(aiFace* f = last_face; f != curOut; ) {
unsigned int* i = f->mIndices; unsigned int* i = f->mIndices;
// drop dumb 0-area triangles - deactivated for now:
//FindDegenerates post processing step can do the same thing
//if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) {
// ASSIMP_LOG_VERBOSE_DEBUG("Dropping triangle with area 0");
// --curOut;
// delete[] f->mIndices;
// f->mIndices = nullptr;
// for(aiFace* ff = f; ff != curOut; ++ff) {
// ff->mNumIndices = (ff+1)->mNumIndices;
// ff->mIndices = (ff+1)->mIndices;
// (ff+1)->mIndices = nullptr;
// }
// continue;
//}
i[0] = idx[i[0]]; i[0] = idx[i[0]];
i[1] = idx[i[1]]; i[1] = idx[i[1]];
i[2] = idx[i[2]]; i[2] = idx[i[2]];

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -110,18 +108,21 @@ inline int HasNameMatch(const aiString &in, aiNode *node) {
template <typename T> template <typename T>
inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) { inline void ValidateDSProcess::DoValidation(T **parray, unsigned int size, const char *firstName, const char *secondName) {
// validate all entries // validate all entries
if (size) { if (size == 0) {
if (!parray) { return;
ReportError("aiScene::%s is nullptr (aiScene::%s is %i)", }
firstName, secondName, size);
} if (!parray) {
for (unsigned int i = 0; i < size; ++i) { ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
if (!parray[i]) { firstName, secondName, size);
ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)", }
firstName, i, secondName, size);
} for (unsigned int i = 0; i < size; ++i) {
Validate(parray[i]); if (!parray[i]) {
ReportError("aiScene::%s[%i] is nullptr (aiScene::%s is %i)",
firstName, i, secondName, size);
} }
Validate(parray[i]);
} }
} }
@ -130,25 +131,27 @@ template <typename T>
inline void ValidateDSProcess::DoValidationEx(T **parray, unsigned int size, inline void ValidateDSProcess::DoValidationEx(T **parray, unsigned int size,
const char *firstName, const char *secondName) { const char *firstName, const char *secondName) {
// validate all entries // validate all entries
if (size) { if (size == 0) {
if (!parray) { return;
ReportError("aiScene::%s is nullptr (aiScene::%s is %i)", }
firstName, secondName, size);
}
for (unsigned int i = 0; i < size; ++i) {
if (!parray[i]) {
ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
firstName, i, secondName, size);
}
Validate(parray[i]);
// check whether there are duplicate names if (!parray) {
for (unsigned int a = i + 1; a < size; ++a) { ReportError("aiScene::%s is nullptr (aiScene::%s is %i)",
if (parray[i]->mName == parray[a]->mName) { firstName, secondName, size);
ReportError("aiScene::%s[%u] has the same name as " }
"aiScene::%s[%u]", for (unsigned int i = 0; i < size; ++i) {
firstName, i, secondName, a); if (!parray[i]) {
} ReportError("aiScene::%s[%u] is nullptr (aiScene::%s is %u)",
firstName, i, secondName, size);
}
Validate(parray[i]);
// check whether there are duplicate names
for (unsigned int a = i + 1; a < size; ++a) {
if (parray[i]->mName == parray[a]->mName) {
ReportError("aiScene::%s[%u] has the same name as "
"aiScene::%s[%u]",
firstName, i, secondName, a);
} }
} }
} }
@ -229,12 +232,6 @@ void ValidateDSProcess::Execute(aiScene *pScene) {
if (pScene->mNumMaterials) { if (pScene->mNumMaterials) {
DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials"); DoValidation(pScene->mMaterials, pScene->mNumMaterials, "mMaterials", "mNumMaterials");
} }
#if 0
// NOTE: ScenePreprocessor generates a default material if none is there
else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) {
ReportError("aiScene::mNumMaterials is 0. At least one material must be there");
}
#endif
else if (pScene->mMaterials) { else if (pScene->mMaterials) {
ReportError("aiScene::mMaterials is non-null although there are no materials"); ReportError("aiScene::mMaterials is non-null although there are no materials");
} }
@ -267,8 +264,7 @@ void ValidateDSProcess::Validate(const aiCamera *pCamera) {
if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear) if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear)
ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear"); ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear");
// FIX: there are many 3ds files with invalid FOVs. No reason to // There are many 3ds files with invalid FOVs. No reason to reject them at all ... a warning is appropriate.
// reject them at all ... a warning is appropriate.
if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI) if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI)
ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV", pCamera->mHorizontalFOV); ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV", pCamera->mHorizontalFOV);
} }
@ -362,15 +358,6 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh) {
if (face.mIndices[a] >= pMesh->mNumVertices) { if (face.mIndices[a] >= pMesh->mNumVertices) {
ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a); ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range", i, a);
} }
// the MSB flag is temporarily used by the extra verbose
// mode to tell us that the JoinVerticesProcess might have
// been executed already.
/*if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && !(this->mScene->mFlags & AI_SCENE_FLAGS_ALLOW_SHARED) &&
abRefList[face.mIndices[a]])
{
ReportError("aiMesh::mVertices[%i] is referenced twice - second "
"time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a);
}*/
abRefList[face.mIndices[a]] = true; abRefList[face.mIndices[a]] = true;
} }
} }
@ -466,7 +453,7 @@ void ValidateDSProcess::Validate(const aiMesh *pMesh, const aiBone *pBone, float
this->Validate(&pBone->mName); this->Validate(&pBone->mName);
if (!pBone->mNumWeights) { if (!pBone->mNumWeights) {
//ReportError("aiBone::mNumWeights is zero"); ReportWarning("aiBone::mNumWeights is zero");
} }
// check whether all vertices affected by this bone are valid // check whether all vertices affected by this bone are valid

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -68,8 +66,7 @@ namespace Assimp {
*/ */
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
template <bool SwapEndianess = false, bool RuntimeSwitch = false> template <bool SwapEndianess = false, bool RuntimeSwitch = false>
class StreamWriter class StreamWriter {
{
enum { enum {
INITIAL_CAPACITY = 1024 INITIAL_CAPACITY = 1024
}; };

View File

@ -97,14 +97,20 @@ namespace Assimp {
* to *all* vertex components equally. This is useful for stuff like interpolation * to *all* vertex components equally. This is useful for stuff like interpolation
* or subdivision, but won't work if special handling is required for some vertex components. */ * or subdivision, but won't work if special handling is required for some vertex components. */
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
class Vertex { struct Vertex {
friend Vertex operator + (const Vertex&,const Vertex&); friend Vertex operator + (const Vertex&,const Vertex&);
friend Vertex operator - (const Vertex&,const Vertex&); friend Vertex operator - (const Vertex&,const Vertex&);
friend Vertex operator * (const Vertex&,ai_real); friend Vertex operator * (const Vertex&,ai_real);
friend Vertex operator / (const Vertex&,ai_real); friend Vertex operator / (const Vertex&,ai_real);
friend Vertex operator * (ai_real, const Vertex&); friend Vertex operator * (ai_real, const Vertex&);
public: aiVector3D position;
aiVector3D normal;
aiVector3D tangent, bitangent;
aiVector3D texcoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
Vertex() = default; Vertex() = default;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -178,7 +184,7 @@ public:
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Convert back to non-interleaved storage */ /// Convert back to non-interleaved storage
void SortBack(aiMesh* out, unsigned int idx) const { void SortBack(aiMesh* out, unsigned int idx) const {
ai_assert(idx<out->mNumVertices); ai_assert(idx<out->mNumVertices);
out->mVertices[idx] = position; out->mVertices[idx] = position;
@ -204,7 +210,7 @@ public:
private: private:
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Construct from two operands and a binary operation to combine them */ /// Construct from two operands and a binary operation to combine them
template <template <typename t> class op> static Vertex BinaryOp(const Vertex& v0, const Vertex& v1) { template <template <typename t> class op> static Vertex BinaryOp(const Vertex& v0, const Vertex& v1) {
// this is a heavy task for the compiler to optimize ... *pray* // this is a heavy task for the compiler to optimize ... *pray*
@ -224,7 +230,7 @@ private:
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** This time binary arithmetic of v0 with a floating-point number */ /// This time binary arithmetic of v0 with a floating-point number
template <template <typename, typename, typename> class op> static Vertex BinaryOp(const Vertex& v0, ai_real f) { template <template <typename, typename, typename> class op> static Vertex BinaryOp(const Vertex& v0, ai_real f) {
// this is a heavy task for the compiler to optimize ... *pray* // this is a heavy task for the compiler to optimize ... *pray*
@ -262,15 +268,6 @@ private:
} }
return res; return res;
} }
public:
aiVector3D position;
aiVector3D normal;
aiVector3D tangent, bitangent;
aiVector3D texcoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -102,6 +102,10 @@ SET( COMMON
unit/Common/utBaseProcess.cpp unit/Common/utBaseProcess.cpp
) )
SET(Geometry
unit/Geometry/utGeometryUtils.cpp
)
SET( IMPORTERS SET( IMPORTERS
unit/ImportExport/Assxml/utAssxmlImportExport.cpp unit/ImportExport/Assxml/utAssxmlImportExport.cpp
unit/utLWSImportExport.cpp unit/utLWSImportExport.cpp
@ -200,12 +204,13 @@ SET( POST_PROCESSES
unit/utGenBoundingBoxesProcess.cpp unit/utGenBoundingBoxesProcess.cpp
) )
SOURCE_GROUP( UnitTests\\Compiler FILES unit/CCompilerTest.c ) SOURCE_GROUP( UnitTests\\Compiler FILES unit/CCompilerTest.c )
SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} ) SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} )
SOURCE_GROUP( UnitTests\\ImportExport FILES ${IMPORTERS} ) SOURCE_GROUP( UnitTests\\GeometryTools FILES ${Geometry} )
SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} ) SOURCE_GROUP( UnitTests\\ImportExport FILES ${IMPORTERS} )
SOURCE_GROUP( UnitTests\\Math FILES ${MATH} ) SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} )
SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES}) SOURCE_GROUP( UnitTests\\Math FILES ${MATH} )
SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES})
add_executable( unit add_executable( unit
unit/CCompilerTest.c unit/CCompilerTest.c
@ -213,6 +218,7 @@ add_executable( unit
../code/Common/Version.cpp ../code/Common/Version.cpp
../code/Common/Base64.cpp ../code/Common/Base64.cpp
${COMMON} ${COMMON}
${Geometry}
${IMPORTERS} ${IMPORTERS}
${MATERIAL} ${MATERIAL}
${MATH} ${MATH}

View File

@ -0,0 +1,68 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
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.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
#include "UnitTestPCH.h"
#include "Geometry/GeometryUtils.h"
using namespace Assimp;
class utGeometryUtils : public ::testing::Test {
protected:
void SetUp() override {
}
void TearDown() override {
}
};
static constexpr size_t NumVectors = 100;
TEST_F(utGeometryUtils, normalizeVectorArrayTest) {
aiVector3D *inNormals = new aiVector3D[NumVectors];
for (uint32_t i=0; i<NumVectors; ++i){
inNormals[i].x = static_cast<ai_real>(i);
inNormals[i].y = static_cast<ai_real>(i);
inNormals[i].z = static_cast<ai_real>(i);
}
aiVector3D *outNormals = new aiVector3D[NumVectors];
GeometryUtils::normalizeVectorArray(inNormals, outNormals, NumVectors);
delete[] outNormals;
delete[] inNormals;
}