Merge branch 'master' into kimkulling/create_skeleton_data_issue_4015

kimkulling/create_skeleton_data_issue_4015
Kim Kulling 2022-03-08 19:10:53 +01:00
commit 7aa87a9765
31 changed files with 402 additions and 317 deletions

View File

@ -13,8 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
#name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter, windows-msvc-hunter]
name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter]
name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter, windows-msvc-hunter]
# For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
include:
- name: windows-latest-cl.exe
@ -39,9 +38,9 @@ jobs:
- name: macos-clang-hunter
os: macos-latest
toolchain: ninja-clang-cxx17-fpic
#- name: windows-msvc-hunter
# os: windows-latest
# toolchain: ninja-vs-win64-cxx17
- name: windows-msvc-hunter
os: windows-latest
toolchain: ninja-vs-win64-cxx17
steps:
- uses: actions/checkout@v2

View File

@ -10,16 +10,15 @@
:: Also see: https://github.com/assimp/assimp/pull/2646
SET SOURCE_DIR=.
SET GENERATOR=Visual Studio 16 2019
:: For generators see "cmake --help"
SET GENERATOR=Visual Studio 15 2017
SET BINARIES_DIR="./BINARIES/Win32"
cmake CMakeLists.txt -G "%GENERATOR%" -S %SOURCE_DIR% -B %BINARIES_DIR%
SET BINARIES_DIR="./build/Win32"
cmake . -G "%GENERATOR%" -A Win32 -S %SOURCE_DIR% -B %BINARIES_DIR%
cmake --build %BINARIES_DIR% --config debug
cmake --build %BINARIES_DIR% --config release
SET BINARIES_DIR="./BINARIES/x64"
cmake CMakeLists.txt -G "%GENERATOR% Win64" -S %SOURCE_DIR% -B %BINARIES_DIR%
SET BINARIES_DIR="./build/x64"
cmake . -G "%GENERATOR%" -A x64 -S %SOURCE_DIR% -B %BINARIES_DIR%
cmake --build %BINARIES_DIR% --config debug
cmake --build %BINARIES_DIR% --config release

View File

@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED)
include("cmake-modules/HunterGate.cmake")
HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.23.311.tar.gz"
SHA1 "1a82b9b73055879181cb1466b2ab5d48ee8ae410"
URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz"
SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd"
)
add_definitions(-DASSIMP_USE_HUNTER)
@ -134,12 +134,12 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
OFF
)
IF ( WIN32 )
IF (WIN32)
# Use subset of Windows.h
ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
IF(MSVC)
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
OPTION (ASSIMP_BUILD_ASSIMP_VIEW
"If the Assimp view tool is built. (requires DirectX)"
OFF )
@ -243,6 +243,13 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
IF( UNIX )
# Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs)
# Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
IF( ${OPERATING_SYSTEM} MATCHES "Android")
ELSE()
IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
ENDIF()
ENDIF()
ENDIF()
# Grouped compiler settings ########################################
@ -687,11 +694,13 @@ ENDIF()
ADD_SUBDIRECTORY( code/ )
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
# The viewer for windows only
IF ( WIN32 )
IF (WIN32)
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF )
IF ( ASSIMP_BUILD_ASSIMP_VIEW )
ADD_SUBDIRECTORY( tools/assimp_view/ )
ENDIF ()
ELSE()
MESSAGE("Building Assimp Viewer only supported on Windows.")
ENDIF ()
# The command line tool
ADD_SUBDIRECTORY( tools/assimp_cmd/ )

View File

@ -357,9 +357,9 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Node
out->mAngleInnerCone = AI_DEG_TO_RAD(srcLight->mFalloffAngle);
// ... some extension magic.
if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) {
if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - ai_epsilon)) {
// ... some deprecation magic.
if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) {
if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - ai_epsilon)) {
// Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
// epsilon chosen to be 0.1
float f = 1.0f;
@ -1065,7 +1065,7 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
return;
}
for (unsigned int i = 0; i < values.size(); i++) {
if (std::abs(time - values[i].mTime) < 1e-6f) {
if (std::abs(time - values[i].mTime) < ai_epsilon) {
values[i].mKeys.push_back(k);
return;
} else if (time > values[i].mTime && time < values[i + 1].mTime) {

View File

@ -80,8 +80,10 @@ enum TransformInheritance {
TransformInheritance_MAX // end-of-enum sentinel
};
} // namespace FBX
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXCOMMON_H_INC

View File

@ -653,7 +653,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
const PropertyTable &props = model.Props();
bool ok;
const float zero_epsilon = 1e-6f;
const float zero_epsilon = ai_epsilon;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
const TransformationComp comp = static_cast<TransformationComp>(i);
@ -1267,7 +1267,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
const std::vector<aiVector3D> &normals = mesh.GetNormals();
if (normals.size()) {
ai_assert(normals.size() == vertices.size());
out_mesh->mNormals = new aiVector3D[vertices.size()];
out_mesh->mNormals = new aiVector3D[count_vertices];
}
// allocate tangents, binormals.
@ -1295,8 +1295,8 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
ai_assert(tangents.size() == vertices.size());
ai_assert(binormals->size() == vertices.size());
out_mesh->mTangents = new aiVector3D[vertices.size()];
out_mesh->mBitangents = new aiVector3D[vertices.size()];
out_mesh->mTangents = new aiVector3D[count_vertices];
out_mesh->mBitangents = new aiVector3D[count_vertices];
}
}
@ -1308,7 +1308,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
break;
}
out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()];
out_mesh->mTextureCoords[i] = new aiVector3D[count_vertices];
out_mesh->mNumUVComponents[i] = 2;
}
@ -1320,7 +1320,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
break;
}
out_mesh->mColors[i] = new aiColor4D[vertices.size()];
out_mesh->mColors[i] = new aiColor4D[count_vertices];
}
unsigned int cursor = 0, in_cursor = 0;
@ -3187,7 +3187,8 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
}
bool ok = false;
const float zero_epsilon = 1e-6f;
const float zero_epsilon = ai_epsilon;
const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
if (ok && preRotation.SquareLength() > zero_epsilon) {

View File

@ -66,12 +66,12 @@ bool IntersectSegmentPlane(const IfcVector3 &p, const IfcVector3 &n, const IfcVe
// if segment ends on plane, do not report a hit. We stay on that side until a following segment starting at this
// point leaves the plane through the other side
if (std::abs(dotOne + dotTwo) < 1e-6)
if (std::abs(dotOne + dotTwo) < ai_epsilon)
return false;
// if segment starts on the plane, report a hit only if the end lies on the *other* side
if (std::abs(dotTwo) < 1e-6) {
if ((assumeStartOnWhiteSide && dotOne + dotTwo < 1e-6) || (!assumeStartOnWhiteSide && dotOne + dotTwo > -1e-6)) {
if (std::abs(dotTwo) < ai_epsilon) {
if ((assumeStartOnWhiteSide && dotOne + dotTwo < ai_epsilon) || (!assumeStartOnWhiteSide && dotOne + dotTwo > -ai_epsilon)) {
out = e0;
return true;
} else {
@ -81,7 +81,7 @@ bool IntersectSegmentPlane(const IfcVector3 &p, const IfcVector3 &n, const IfcVe
// ignore if segment is parallel to plane and far away from it on either side
// Warning: if there's a few thousand of such segments which slowly accumulate beyond the epsilon, no hit would be registered
if (std::abs(dotOne) < 1e-6)
if (std::abs(dotOne) < ai_epsilon)
return false;
// t must be in [0..1] if the intersection point is within the given segment
@ -163,7 +163,7 @@ void ProcessBooleanHalfSpaceDifference(const Schema_2x3::IfcHalfSpaceSolid *hs,
for (iit = begin; iit != end; vidx += *iit++) {
unsigned int newcount = 0;
bool isAtWhiteSide = (in[vidx] - p) * n > -1e-6;
bool isAtWhiteSide = (in[vidx] - p) * n > -ai_epsilon;
for (unsigned int i = 0; i < *iit; ++i) {
const IfcVector3 &e0 = in[vidx + i], e1 = in[vidx + (i + 1) % *iit];
@ -259,7 +259,7 @@ bool IntersectsBoundaryProfile(const IfcVector3 &e0, const IfcVector3 &e1, const
// segment-segment intersection
// solve b0 + b*s = e0 + e*t for (s,t)
const IfcFloat det = (-b.x * e.y + e.x * b.y);
if (std::abs(det) < 1e-6) {
if (std::abs(det) < ai_epsilon) {
// no solutions (parallel lines)
continue;
}
@ -316,7 +316,7 @@ bool IntersectsBoundaryProfile(const IfcVector3 &e0, const IfcVector3 &e1, const
// for a valid intersection, s and t should be in range [0,1]. Including a bit of epsilon on s, potential double
// hits on two consecutive boundary segments are filtered
if (s >= -1e-6 * b_sqlen_inv && s <= 1.0 + 1e-6 * b_sqlen_inv && t >= 0.0 && (t <= 1.0 || halfOpen)) {
if (s >= -ai_epsilon * b_sqlen_inv && s <= 1.0 + ai_epsilon * b_sqlen_inv && t >= 0.0 && (t <= 1.0 || halfOpen)) {
// only insert the point into the list if it is sufficiently far away from the previous intersection point.
// This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments.
if (!intersect_results.empty() && intersect_results.back().first == i - 1) {
@ -431,14 +431,14 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const Schema_2x3::IfcPoly
// if the poly is parallel to the plane, put it completely on the black or white side
if (std::abs(polyNormal * n) > 0.9999) {
bool isOnWhiteSide = (srcVertices[0] - p) * n > -1e-6;
bool isOnWhiteSide = (srcVertices[0] - p) * n > -ai_epsilon;
std::vector<IfcVector3> &targetSide = isOnWhiteSide ? whiteside : blackside;
targetSide.insert(targetSide.end(), srcVertices, srcVertices + srcVtxCount);
} else {
// otherwise start building one polygon for each side. Whenever the current line segment intersects the plane
// we put a point there as an end of the current segment. Then we switch to the other side, put a point there, too,
// as a beginning of the current segment, and simply continue accumulating vertices.
bool isCurrentlyOnWhiteSide = ((srcVertices[0]) - p) * n > -1e-6;
bool isCurrentlyOnWhiteSide = ((srcVertices[0]) - p) * n > -ai_epsilon;
for (size_t a = 0; a < srcVtxCount; ++a) {
IfcVector3 e0 = srcVertices[a];
IfcVector3 e1 = srcVertices[(a + 1) % srcVtxCount];

View File

@ -380,21 +380,19 @@ void ProcessSweptDiskSolid(const Schema_2x3::IfcSweptDiskSolid &solid, TempMesh&
bool take_any = false;
for (unsigned int j = 0; j < 2; ++j, take_any = true) {
if ((last_dir == 0 || take_any) && std::abs(d.x) > 1e-6) {
if ((last_dir == 0 || take_any) && std::abs(d.x) > ai_epsilon) {
q.y = startvec.y;
q.z = startvec.z;
q.x = -(d.y * q.y + d.z * q.z) / d.x;
last_dir = 0;
break;
}
else if ((last_dir == 1 || take_any) && std::abs(d.y) > 1e-6) {
} else if ((last_dir == 1 || take_any) && std::abs(d.y) > ai_epsilon) {
q.x = startvec.x;
q.z = startvec.z;
q.y = -(d.x * q.x + d.z * q.z) / d.y;
last_dir = 1;
break;
}
else if ((last_dir == 2 && std::abs(d.z) > 1e-6) || take_any) {
} else if ((last_dir == 2 && std::abs(d.z) > ai_epsilon) || take_any) {
q.y = startvec.y;
q.x = startvec.x;
q.z = -(d.y * q.y + d.x * q.x) / d.z;
@ -529,7 +527,7 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVect
return m;
}
const auto closeDistance = 1e-6;
const auto closeDistance = ai_epsilon;
bool areClose(Schema_2x3::IfcCartesianPoint pt1,Schema_2x3::IfcCartesianPoint pt2) {
if(pt1.Coordinates.size() != pt2.Coordinates.size())
@ -561,7 +559,7 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
// Outline: 'curve' is now a list of vertex points forming the underlying profile, extrude along the given axis,
// forming new triangles.
const bool has_area = solid.SweptArea->ProfileType == "AREA" && curve.mVerts.size() > 2;
if( solid.Depth < 1e-6 ) {
if (solid.Depth < ai_epsilon) {
if( has_area ) {
result.Append(curve);
}

View File

@ -1133,7 +1133,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
}
for(size_t i = 0; i < out_contour.size(); ++i) {
ai_assert((out_contour[i]-out_contour2[i]).SquareLength() < 1e-6);
ai_assert((out_contour[i] - out_contour2[i]).SquareLength() < ai_epsilon);
}
#endif
@ -1435,7 +1435,7 @@ std::vector<IfcVector2> GetContourInPlane2D(std::shared_ptr<TempMesh> mesh,IfcMa
const auto outernor = ((mesh->mVerts[2] - mesh->mVerts[0]) ^ (mesh->mVerts[1] - mesh->mVerts[0])).Normalize();
const IfcFloat dot = planeNor * outernor;
if(std::fabs(dot) < 1.f - 1e-6f) {
if (std::fabs(dot) < 1.f - ai_epsilon) {
std::stringstream msg;
msg << "Skipping: Unaligned opening (" << planeNor.x << ", " << planeNor.y << ", " << planeNor.z << ")";
msg << " . ( " << outernor.x << ", " << outernor.y << ", " << outernor.z << ") = " << dot;
@ -1476,7 +1476,7 @@ std::vector<IfcVector2> GetContourInPlane2D(std::shared_ptr<TempMesh> mesh,IfcMa
return contour;
}
const float close { 1e-6f };
const float close{ ai_epsilon };
static bool isClose(IfcVector2 first,IfcVector2 second) {
auto diff = (second - first);

View File

@ -228,25 +228,24 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
// ------------------------------------------------------------------------------------------------
// Compute the normal of the last polygon in the given mesh
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const
{
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize);
}
struct CompareVector
{
bool operator () (const IfcVector3& a, const IfcVector3& b) const
{
struct CompareVector {
bool operator () (const IfcVector3& a, const IfcVector3& b) const {
IfcVector3 d = a - b;
IfcFloat eps = 1e-6;
IfcFloat eps = ai_epsilon;
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
}
};
struct FindVector
{
struct FindVector {
IfcVector3 v;
FindVector(const IfcVector3& p) : v(p) { }
bool operator () (const IfcVector3& p) { return FuzzyVectorCompare(1e-6)(p, v); }
bool operator()(const IfcVector3 &p) {
return FuzzyVectorCompare(ai_epsilon)(p, v);
}
};
// ------------------------------------------------------------------------------------------------
@ -357,8 +356,7 @@ void TempMesh::FixupFaceOrientation()
// to reverse the neighbour
nb_vidx = (nb_vidx + 1) % nbvc;
size_t oursideidx = (a + 1) % vc;
if( FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx]) )
{
if (FuzzyVectorCompare(ai_epsilon)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx])) {
std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
for (size_t aa = 0; aa < nbvc - 1; ++aa) {
@ -564,7 +562,7 @@ void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
out[static_cast<unsigned int>(i)] = in.DirectionRatios[i];
}
const IfcFloat len = out.Length();
if (len<1e-6) {
if (len < ai_epsilon) {
IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero");
return;
}

View File

@ -195,6 +195,9 @@ struct Material {
//! PBR Anisotropy
ai_real anisotropy;
//! bump map multipler (normal map scalar)(-bm)
ai_real bump_multiplier;
//! Constructor
Material() :
diffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
@ -208,7 +211,8 @@ struct Material {
sheen(ai_real(1.0), ai_real(1.0), ai_real(1.0)),
clearcoat_thickness(ai_real(0.0)),
clearcoat_roughness(ai_real(0.0)),
anisotropy(ai_real(0.0)) {
anisotropy(ai_real(0.0)),
bump_multiplier(ai_real(1.0)) {
std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false);
}

View File

@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <assimp/ObjMaterial.h>
#include <memory>
static const aiImporterDesc desc = {
@ -604,6 +605,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
mat->AddProperty<int>(&sm, 1, AI_MATKEY_SHADING_MODEL);
// Preserve the original illum value
mat->AddProperty<int>(&pCurrentMaterial->illumination_model, 1, AI_MATKEY_OBJ_ILLUM);
// Adding material colors
mat->AddProperty(&pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT);
mat->AddProperty(&pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
@ -657,6 +661,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
if (0 != pCurrentMaterial->textureBump.length) {
mat->AddProperty(&pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_HEIGHT(0));
if (pCurrentMaterial->bump_multiplier != 1.0) {
mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_HEIGHT(0));
}
if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) {
addTextureMappingModeProperty(mat, aiTextureType_HEIGHT);
}
@ -665,6 +672,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
if (0 != pCurrentMaterial->textureNormal.length) {
mat->AddProperty(&pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_NORMALS(0));
if (pCurrentMaterial->bump_multiplier != 1.0) {
mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_NORMALS(0));
}
if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) {
addTextureMappingModeProperty(mat, aiTextureType_NORMALS);
}

View File

@ -472,7 +472,11 @@ void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString
}
skipToken = 2;
} else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size()))) {
} else if (!ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size()))) {
DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
getFloat(it, m_DataItEnd, m_pModel->m_pCurrentMaterial->bump_multiplier);
skipToken = 2;
} else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size()))) {
skipToken = 2;
} else if (!ASSIMP_strincmp(pPtr, ModifyMapOption.c_str(), static_cast<unsigned int>(ModifyMapOption.size()))) {
skipToken = 3;

View File

@ -260,20 +260,9 @@ public:
VEC4,
MAT2,
MAT3,
MAT4 };
private:
static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
struct Info {
const char *name;
unsigned int numComponents;
MAT4
};
template <int N>
struct data { static const Info infos[NUM_VALUES]; };
public:
inline static Value FromString(const char *str) {
for (size_t i = 0; i < NUM_VALUES; ++i) {
if (strcmp(data<0>::infos[i].name, str) == 0) {
@ -290,40 +279,31 @@ public:
inline static unsigned int GetNumComponents(Value type) {
return data<0>::infos[static_cast<size_t>(type)].numComponents;
}
private:
static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
struct Info {
const char *name;
unsigned int numComponents;
};
template <int N>
struct data {
static const Info infos[NUM_VALUES];
};
};
// must match the order of the AttribTypeTraits::Value enum!
template <int N>
const AttribType::Info
AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
{ "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 }
};
/*
//! A reference to one top-level object, which is valid
//! until the Asset instance is destroyed
template<class T>
class Ref
{
std::vector<T*>* vector;
unsigned int index;
public:
Ref() : vector(0), index(0) {}
Ref(std::vector<T*>& vec, unsigned int idx) : vector(&vec), index(idx) {}
inline unsigned int GetIndex() const
{ return index; }
operator bool() const
{ return vector != 0; }
T* operator->()
{ return (*vector)[index]; }
T& operator*()
{ return *((*vector)[index]); }
};*/
const AttribType::Info AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
{ "SCALAR", 1 },
{ "VEC2", 2 },
{ "VEC3", 3 },
{ "VEC4", 4 },
{ "MAT2", 4 },
{ "MAT3", 9 },
{ "MAT4", 16 }
};
//! Base class for all glTF top-level objects
struct Object {
@ -333,6 +313,7 @@ struct Object {
//! Objects marked as special are not exported (used to emulate the binary body buffer)
virtual bool IsSpecial() const { return false; }
Object() = default;
virtual ~Object() {}
//! Maps special IDs to another ID, where needed. Subclasses may override it (statically)
@ -401,21 +382,19 @@ struct Accessor : public Object {
return Indexer(*this);
}
Accessor() {}
Accessor() = default;
void Read(Value &obj, Asset &r);
};
//! A buffer points to binary geometry, animation, or skins.
struct Buffer : public Object {
/********************* Types *********************/
public:
enum Type {
Type_arraybuffer,
Type_text
};
/// \struct SEncodedRegion
/// Descriptor of encoded region in "bufferView".
/// @brief Descriptor of encoded region in "bufferView".
struct SEncodedRegion {
const size_t Offset; ///< Offset from begin of "bufferView" to encoded region, in bytes.
const size_t EncodedData_Length; ///< Size of encoded region, in bytes.
@ -423,8 +402,7 @@ public:
const size_t DecodedData_Length; ///< Size of decoded region, in bytes.
const std::string ID; ///< ID of the region.
/// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID)
/// Constructor.
/// @brief Constructor.
/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
/// \param [in] pEncodedData_Length - size of encoded region, in bytes.
/// \param [in] pDecodedData - pointer to decoded data array.
@ -433,16 +411,13 @@ public:
SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) :
Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {}
/// \fn ~SEncodedRegion()
/// Destructor.
~SEncodedRegion() { delete[] DecodedData; }
};
/******************* Variables *******************/
//std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
//std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
Type type;
@ -486,7 +461,6 @@ public:
bool LoadFromStream(IOStream &stream, size_t length = 0, size_t baseOffset = 0);
/// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
/// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data.
/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
/// \param [in] pEncodedData_Length - size of encoded region, in bytes.
@ -495,12 +469,10 @@ public:
/// \param [in] pID - ID of the region.
void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID);
/// \fn void EncodedRegion_SetCurrent(const std::string& pID)
/// Select current encoded region by ID. \sa EncodedRegion_Current.
/// \param [in] pID - ID of the region.
void EncodedRegion_SetCurrent(const std::string &pID);
/// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
/// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions.
/// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed.
/// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced.
@ -558,37 +530,29 @@ struct Camera : public Object {
} ortographic;
};
Camera() {}
Camera() = default;
void Read(Value &obj, Asset &r);
};
//! Image data used to create a texture.
struct Image : public Object {
std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required)
Ref<BufferView> bufferView;
std::string mimeType;
int width, height;
private:
std::unique_ptr<uint8_t[]> mData;
size_t mDataLength;
public:
Image();
void Read(Value &obj, Asset &r);
inline bool HasData() const { return mDataLength > 0; }
inline size_t GetDataLength() const { return mDataLength; }
inline const uint8_t *GetData() const { return mData.get(); }
inline uint8_t *StealData();
inline void SetData(uint8_t *data, size_t length, Asset &r);
private:
std::unique_ptr<uint8_t[]> mData;
size_t mDataLength;
};
//! Holds a material property that can be a texture or a color
@ -671,6 +635,7 @@ struct Mesh : public Object {
};
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
/// \struct SCompression_Open3DGC
/// Compression of mesh data using Open3DGC algorithm.
struct SCompression_Open3DGC : public SExtension {
@ -703,7 +668,6 @@ struct Mesh : public Object {
Mesh() {}
/// \fn ~Mesh()
/// Destructor.
~Mesh() {
for (std::list<SExtension *>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) {
@ -711,15 +675,13 @@ struct Mesh : public Object {
};
}
/// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root)
/// Get mesh data from JSON-object and place them to root asset.
/// @brief Get mesh data from JSON-object and place them to root asset.
/// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
/// \param [out] pAsset_Root - reference to root asset where data will be stored.
void Read(Value &pJSON_Object, Asset &pAsset_Root);
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
/// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
/// Decode part of "buffer" which encoded with Open3DGC algorithm.
/// @brief Decode part of "buffer" which encoded with Open3DGC algorithm.
/// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region.
/// \param [out] pAsset_Root - reference to root assed where data will be stored.
void Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DGC, Asset &pAsset_Root);
@ -759,7 +721,7 @@ struct Sampler : public Object {
SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required)
SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required)
Sampler() {}
Sampler() = default;
void Read(Value &obj, Asset &r);
void SetDefaults();
};
@ -767,12 +729,12 @@ struct Sampler : public Object {
struct Scene : public Object {
std::vector<Ref<Node>> nodes;
Scene() {}
Scene() = default;
void Read(Value &obj, Asset &r);
};
struct Shader : public Object {
Shader() {}
Shader() = default;
void Read(Value &obj, Asset &r);
};
@ -782,7 +744,7 @@ struct Skin : public Object {
std::vector<Ref<Node>> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin.
std::string name; //!< The user-defined name of this object.
Skin() {}
Skin() = default;
void Read(Value &obj, Asset &r);
};
@ -796,7 +758,7 @@ struct Technique : public Object {
struct Functions {
};
Technique() {}
Technique() = default;
void Read(Value &obj, Asset &r);
};
@ -805,13 +767,7 @@ struct Texture : public Object {
Ref<Sampler> sampler; //!< The ID of the sampler used by this texture. (required)
Ref<Image> source; //!< The ID of the image used by this texture. (required)
//TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA)
//TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA)
//TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D)
//TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE)
Texture() {}
Texture() = default;
void Read(Value &obj, Asset &r);
};
@ -826,7 +782,6 @@ struct Light : public Object {
};
Type type;
vec4 color;
float distance;
float constantAttenuation;
@ -835,9 +790,8 @@ struct Light : public Object {
float falloffAngle;
float falloffExponent;
Light() {}
Light() = default;
void Read(Value &obj, Asset &r);
void SetDefaults();
};
@ -865,15 +819,11 @@ struct Animation : public Object {
Ref<Accessor> translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors.
};
// AnimChannel Channels[3]; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
// AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
// AnimSampler Samplers[3]; //!< The parameterized inputs representing the key-frame data.
std::vector<AnimChannel> Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
std::vector<AnimSampler> Samplers; //!< The parameterized inputs representing the key-frame data.
Animation() {}
Animation() = default;
void Read(Value &obj, Asset &r);
};
@ -963,13 +913,11 @@ struct AssetMetadata {
//! Root object for a glTF asset
class Asset {
typedef std::gltf_unordered_map<std::string, int> IdMap;
using IdMap = std::gltf_unordered_map<std::string, int>;
template <class T>
friend class LazyDict;
friend struct Buffer; // To access OpenFile
friend class AssetWriter;
private:
@ -1010,12 +958,9 @@ public:
LazyDict<Material> materials;
LazyDict<Mesh> meshes;
LazyDict<Node> nodes;
//LazyDict<Program> programs;
LazyDict<Sampler> samplers;
LazyDict<Scene> scenes;
//LazyDict<Shader> shaders;
LazyDict<Skin> skins;
//LazyDict<Technique> techniques;
LazyDict<Texture> textures;
LazyDict<Light> lights; // KHR_materials_common ext
@ -1024,16 +969,20 @@ public:
public:
Asset(IOSystem *io = 0) :
mIOSystem(io), asset(), accessors(*this, "accessors"), animations(*this, "animations"), buffers(*this, "buffers"), bufferViews(*this, "bufferViews"), cameras(*this, "cameras"), images(*this, "images"), materials(*this, "materials"), meshes(*this, "meshes"), nodes(*this, "nodes")
//, programs (*this, "programs")
,
mIOSystem(io),
asset(),
accessors(*this, "accessors"),
animations(*this, "animations"),
buffers(*this, "buffers"),
bufferViews(*this, "bufferViews"),
cameras(*this, "cameras"),
images(*this, "images"),
materials(*this, "materials"),
meshes(*this, "meshes"),
nodes(*this, "nodes"),
samplers(*this, "samplers"),
scenes(*this, "scenes")
//, shaders (*this, "shaders")
,
skins(*this, "skins")
//, techniques (*this, "techniques")
,
scenes(*this, "scenes"),
skins(*this, "skins"),
textures(*this, "textures"),
lights(*this, "lights", "KHR_materials_common") {
memset(&extensionsUsed, 0, sizeof(extensionsUsed));

View File

@ -237,8 +237,6 @@ bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out);
#define CHECK_EXT(EXT) \
if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
//! Helper struct to represent values that might not be present
template <class T>
struct Nullable {

View File

@ -106,7 +106,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# define gltf_unordered_map tr1::unordered_map
# define gltf_unordered_set tr1::unordered_set
# else
# define gltf_unordered_map unordered_map
# define gltf_unordered_map unordered_map
# define gltf_unordered_set unordered_set
# endif
#endif
@ -1087,29 +1087,11 @@ class Asset {
template <class T>
friend class LazyDict;
friend struct Buffer; // To access OpenFile
friend class AssetWriter;
private:
IOSystem *mIOSystem;
rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
std::string mCurrentAssetDir;
size_t mSceneLength;
size_t mBodyOffset, mBodyLength;
std::vector<LazyDictBase *> mDicts;
IdMap mUsedIds;
Ref<Buffer> mBodyBuffer;
Asset(Asset &);
Asset &operator=(const Asset &);
public:
//! Keeps info about the enabled extensions
struct Extensions {
@ -1125,16 +1107,36 @@ public:
bool KHR_draco_mesh_compression;
bool FB_ngon_encoding;
bool KHR_texture_basisu;
Extensions() :
KHR_materials_pbrSpecularGlossiness(false),
KHR_materials_unlit(false),
KHR_lights_punctual(false),
KHR_texture_transform(false),
KHR_materials_sheen(false),
KHR_materials_clearcoat(false),
KHR_materials_transmission(false),
KHR_materials_volume(false),
KHR_materials_ior(false),
KHR_draco_mesh_compression(false),
FB_ngon_encoding(false),
KHR_texture_basisu(false) {
// empty
}
} extensionsUsed;
//! Keeps info about the required extensions
struct RequiredExtensions {
bool KHR_draco_mesh_compression;
bool KHR_texture_basisu;
RequiredExtensions() : KHR_draco_mesh_compression(false), KHR_texture_basisu(false) {
// empty
}
} extensionsRequired;
AssetMetadata asset;
Value *extras = nullptr;
Value *extras;
// Dictionaries for each type of object
@ -1156,10 +1158,12 @@ public:
Ref<Scene> scene;
public:
Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) :
mIOSystem(io),
mSchemaDocumentProvider(schemaDocumentProvider),
Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) :
mDicts(),
extensionsUsed(),
extensionsRequired(),
asset(),
extras(nullptr),
accessors(*this, "accessors"),
animations(*this, "animations"),
buffers(*this, "buffers"),
@ -1173,9 +1177,10 @@ public:
samplers(*this, "samplers"),
scenes(*this, "scenes"),
skins(*this, "skins"),
textures(*this, "textures") {
memset(&extensionsUsed, 0, sizeof(extensionsUsed));
memset(&extensionsRequired, 0, sizeof(extensionsRequired));
textures(*this, "textures") ,
mIOSystem(io),
mSchemaDocumentProvider(schemaDocumentProvider) {
// empty
}
//! Main function
@ -1192,18 +1197,31 @@ public:
Ref<Buffer> GetBodyBuffer() { return mBodyBuffer; }
Asset(Asset &) = delete;
Asset &operator=(const Asset &) = delete;
private:
void ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData);
//! Obtain a JSON document from the stream.
// \param second argument is a buffer used by the document. It must be kept
// alive while the document is in use.
/// Obtain a JSON document from the stream.
/// \param second argument is a buffer used by the document. It must be kept
/// alive while the document is in use.
Document ReadDocument(IOStream& stream, bool isBinary, std::vector<char>& sceneData);
void ReadExtensionsUsed(Document &doc);
void ReadExtensionsRequired(Document &doc);
IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false);
private:
IOSystem *mIOSystem;
rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
std::string mCurrentAssetDir;
size_t mSceneLength;
size_t mBodyOffset;
size_t mBodyLength;
IdMap mUsedIds;
Ref<Buffer> mBodyBuffer;
};
inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) {

View File

@ -515,72 +515,74 @@ void glTF2Exporter::GetMatTexProp(const aiMaterial &mat, float &prop, const char
}
void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot = 0) {
if (mat.GetTextureCount(tt) > 0) {
aiString tex;
if (mat.GetTextureCount(tt) == 0) {
return;
}
aiString tex;
// Read texcoord (UV map index)
mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord);
// Read texcoord (UV map index)
mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord);
if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
std::string path = tex.C_Str();
if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
std::string path = tex.C_Str();
if (path.size() > 0) {
std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path);
if (it != mTexturesByPath.end()) {
texture = mAsset->textures.Get(it->second);
}
if (path.size() > 0) {
std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path);
if (it != mTexturesByPath.end()) {
texture = mAsset->textures.Get(it->second);
}
bool useBasisUniversal = false;
if (!texture) {
std::string texId = mAsset->FindUniqueID("", "texture");
texture = mAsset->textures.Create(texId);
mTexturesByPath[path] = texture.GetIndex();
bool useBasisUniversal = false;
if (!texture) {
std::string texId = mAsset->FindUniqueID("", "texture");
texture = mAsset->textures.Create(texId);
mTexturesByPath[path] = texture.GetIndex();
std::string imgId = mAsset->FindUniqueID("", "image");
texture->source = mAsset->images.Create(imgId);
std::string imgId = mAsset->FindUniqueID("", "image");
texture->source = mAsset->images.Create(imgId);
const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str());
if (curTex != nullptr) { // embedded
texture->source->name = curTex->mFilename.C_Str();
const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str());
if (curTex != nullptr) { // embedded
texture->source->name = curTex->mFilename.C_Str();
//basisu: embedded ktx2, bu
if (curTex->achFormatHint[0]) {
std::string mimeType = "image/";
if (memcmp(curTex->achFormatHint, "jpg", 3) == 0)
mimeType += "jpeg";
else if (memcmp(curTex->achFormatHint, "ktx", 3) == 0) {
useBasisUniversal = true;
mimeType += "ktx";
} else if (memcmp(curTex->achFormatHint, "kx2", 3) == 0) {
useBasisUniversal = true;
mimeType += "ktx2";
} else if (memcmp(curTex->achFormatHint, "bu", 2) == 0) {
useBasisUniversal = true;
mimeType += "basis";
} else
mimeType += curTex->achFormatHint;
texture->source->mimeType = mimeType;
}
// The asset has its own buffer, see Image::SetData
//basisu: "image/ktx2", "image/basis" as is
texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
} else {
texture->source->uri = path;
if (texture->source->uri.find(".ktx") != std::string::npos ||
texture->source->uri.find(".basis") != std::string::npos) {
//basisu: embedded ktx2, bu
if (curTex->achFormatHint[0]) {
std::string mimeType = "image/";
if (memcmp(curTex->achFormatHint, "jpg", 3) == 0)
mimeType += "jpeg";
else if (memcmp(curTex->achFormatHint, "ktx", 3) == 0) {
useBasisUniversal = true;
}
mimeType += "ktx";
} else if (memcmp(curTex->achFormatHint, "kx2", 3) == 0) {
useBasisUniversal = true;
mimeType += "ktx2";
} else if (memcmp(curTex->achFormatHint, "bu", 2) == 0) {
useBasisUniversal = true;
mimeType += "basis";
} else
mimeType += curTex->achFormatHint;
texture->source->mimeType = mimeType;
}
//basisu
if (useBasisUniversal) {
mAsset->extensionsUsed.KHR_texture_basisu = true;
mAsset->extensionsRequired.KHR_texture_basisu = true;
// The asset has its own buffer, see Image::SetData
//basisu: "image/ktx2", "image/basis" as is
texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
} else {
texture->source->uri = path;
if (texture->source->uri.find(".ktx") != std::string::npos ||
texture->source->uri.find(".basis") != std::string::npos) {
useBasisUniversal = true;
}
GetTexSampler(mat, texture, tt, slot);
}
//basisu
if (useBasisUniversal) {
mAsset->extensionsUsed.KHR_texture_basisu = true;
mAsset->extensionsRequired.KHR_texture_basisu = true;
}
GetTexSampler(mat, texture, tt, slot);
}
}
}
@ -588,12 +590,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
void glTF2Exporter::GetMatTex(const aiMaterial &mat, TextureInfo &prop, aiTextureType tt, unsigned int slot = 0) {
Ref<Texture> &texture = prop.texture;
GetMatTex(mat, texture, prop.texCoord, tt, slot);
//if (texture) {
// GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
//}
}
void glTF2Exporter::GetMatTex(const aiMaterial &mat, NormalTextureInfo &prop, aiTextureType tt, unsigned int slot = 0) {
@ -681,12 +678,14 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) {
// Return true if got any valid Sheen properties or textures
if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS)
if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) {
return false;
}
// Default Sheen color factor {0,0,0} disables Sheen, so do not export
if (sheen.sheenColorFactor == defaultSheenFactor)
if (sheen.sheenColorFactor == defaultSheenFactor) {
return false;
}
mat.Get(AI_MATKEY_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor);
@ -781,9 +780,7 @@ void glTF2Exporter::ExportMaterials() {
aiColor4D specularColor;
ai_real shininess;
if (
mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS &&
mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
if (mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
// convert specular color to luminance
float specularIntensity = specularColor[0] * 0.2125f + specularColor[1] * 0.7154f + specularColor[2] * 0.0721f;
//normalize shininess (assuming max is 1000) with an inverse exponentional curve
@ -916,7 +913,8 @@ Ref<Node> FindSkeletonRootJoint(Ref<Skin> &skinRef) {
return parentNodeRef;
}
void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buffer> &bufferRef, Ref<Skin> &skinRef, std::vector<aiMatrix4x4> &inverseBindMatricesData) {
void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buffer> &bufferRef, Ref<Skin> &skinRef,
std::vector<aiMatrix4x4> &inverseBindMatricesData) {
if (aimesh->mNumBones < 1) {
return;
}
@ -986,7 +984,8 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buf
} // End: for-loop mNumMeshes
Mesh::Primitive &p = meshRef->primitives.back();
Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices,
vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
if (vertexJointAccessor) {
size_t offset = vertexJointAccessor->bufferView->byteOffset;
size_t bytesLen = vertexJointAccessor->bufferView->byteLength;
@ -1069,8 +1068,11 @@ void glTF2Exporter::ExportMeshes() {
p.ngonEncoded = (aim->mPrimitiveTypes & aiPrimitiveType_NGONEncodingFlag) != 0;
/******************* Vertices ********************/
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (v) p.attributes.position.push_back(v);
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3,
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (v) {
p.attributes.position.push_back(v);
}
/******************** Normals ********************/
// Normalize all normals as the validator can emit a warning otherwise
@ -1080,13 +1082,17 @@ void glTF2Exporter::ExportMeshes() {
}
}
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (n) p.attributes.normal.push_back(n);
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3,
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (n) {
p.attributes.normal.push_back(n);
}
/************** Texture coordinates **************/
for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
if (!aim->HasTextureCoords(i))
if (!aim->HasTextureCoords(i)) {
continue;
}
// Flip UV y coords
if (aim->mNumUVComponents[i] > 1) {
@ -1098,16 +1104,21 @@ void glTF2Exporter::ExportMeshes() {
if (aim->mNumUVComponents[i] > 0) {
AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (tc) p.attributes.texcoord.push_back(tc);
Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i],
AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (tc) {
p.attributes.texcoord.push_back(tc);
}
}
}
/*************** Vertex colors ****************/
for (unsigned int indexColorChannel = 0; indexColorChannel < aim->GetNumColorChannels(); ++indexColorChannel) {
Ref<Accessor> c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel], AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (c)
Ref<Accessor> c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel],
AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (c) {
p.attributes.color.push_back(c);
}
}
/*************** Vertices indices ****************/
@ -1121,7 +1132,8 @@ void glTF2Exporter::ExportMeshes() {
}
}
p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER);
p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR,
ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER);
}
switch (aim->mPrimitiveTypes) {
@ -1136,6 +1148,7 @@ void glTF2Exporter::ExportMeshes() {
break;
default: // aiPrimitiveType_TRIANGLE
p.mode = PrimitiveMode_TRIANGLES;
break;
}
/*************** Skins ****************/
@ -1155,8 +1168,9 @@ void glTF2Exporter::ExportMeshes() {
p.targets.resize(aim->mNumAnimMeshes);
for (unsigned int am = 0; am < aim->mNumAnimMeshes; ++am) {
aiAnimMesh *pAnimMesh = aim->mAnimMeshes[am];
if (bExportTargetNames)
m->targetNames.push_back(pAnimMesh->mName.data);
if (bExportTargetNames) {
m->targetNames.emplace_back(pAnimMesh->mName.data);
}
// position
if (pAnimMesh->HasPositions()) {
// NOTE: in gltf it is the diff stored
@ -1319,12 +1333,12 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) {
}
for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
node->meshes.emplace_back(mAsset->meshes.Get(n->mMeshes[i]));
}
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
unsigned int idx = ExportNode(n->mChildren[i], node);
node->children.push_back(mAsset->nodes.Get(idx));
node->children.emplace_back(mAsset->nodes.Get(idx));
}
return node.GetIndex();
@ -1366,12 +1380,12 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref<Node> &parent) {
}
for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
node->meshes.emplace_back(mAsset->meshes.Get(n->mMeshes[i]));
}
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
unsigned int idx = ExportNode(n->mChildren[i], node);
node->children.push_back(mAsset->nodes.Get(idx));
node->children.emplace_back(mAsset->nodes.Get(idx));
}
return node.GetIndex();
@ -1386,7 +1400,7 @@ void glTF2Exporter::ExportScene() {
// root node will be the first one exported (idx 0)
if (mAsset->nodes.Size() > 0) {
scene->nodes.push_back(mAsset->nodes.Get(0u));
scene->nodes.emplace_back(mAsset->nodes.Get(0u));
}
// set as the default scene
@ -1521,12 +1535,6 @@ void glTF2Exporter::ExportAnimations() {
AddSampler(animRef, animNode, scaleSampler, AnimationPath_SCALE);
}
}
// Assimp documentation states this is not used (not implemented)
// for (unsigned int channelIndex = 0; channelIndex < anim->mNumMeshChannels; ++channelIndex) {
// const aiMeshAnim* meshChannel = anim->mMeshChannels[channelIndex];
// }
} // End: for-loop mNumAnimations
}

View File

@ -1317,11 +1317,10 @@ ENDIF ()
INSTALL( TARGETS assimp
EXPORT "${TARGETS_EXPORT_NAME}"
LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR}
FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
COMPONENT ${LIBASSIMP_COMPONENT}
LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}
ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP-DEV_COMPONENT}
RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}
FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}
INCLUDES DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
)
INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)

View File

@ -191,9 +191,9 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
bitangent.x = (- w.x * sx + v.x * tx) * dirCorrection;
bitangent.y = (- w.y * sx + v.y * tx) * dirCorrection;
bitangent.z = (- w.z * sx + v.z * tx) * dirCorrection;
// store for every vertex of that face
for (unsigned int b = 0; b < face.mNumIndices; ++b) {
@ -201,7 +201,7 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
// project tangent and bitangent into the plane formed by the vertex' normal
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]) - localTangent * (bitangent * localTangent);
localTangent.NormalizeSafe();
localBitangent.NormalizeSafe();

View File

@ -221,7 +221,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
if ( mConfigCheckAreaOfTriangle ) {
if ( face.mNumIndices == 3 ) {
ai_real area = calculateAreaOfTriangle( face, mesh );
if ( area < 1e-6 ) {
if (area < ai_epsilon) {
if ( mConfigRemoveDegenerates ) {
remove_me[ a ] = true;
++deg;

View File

@ -4,7 +4,6 @@ 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,
@ -76,7 +75,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inline uint32_t SuperFastHash (const char * data, uint32_t len = 0, uint32_t hash = 0) {
uint32_t tmp;
int rem;
size_t offset;
if (!data) return 0;
if (!len)len = (uint32_t)::strlen(data);
@ -96,7 +96,11 @@ int rem;
switch (rem) {
case 3: hash += get16bits (data);
hash ^= hash << 16;
hash ^= data[sizeof (uint16_t)] << 18;
offset = static_cast<size_t>(sizeof(uint16_t));
if (offset < 0) {
return 0;
}
hash ^= data[offset] << 18;
hash += hash >> 11;
break;
case 2: hash += get16bits (data);

View File

@ -0,0 +1,84 @@
/*
---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------
*/
/** @file OBJMATERIAL.h
* @brief Obj-specific material macros
*
*/
#ifndef AI_OBJMATERIAL_H_INC
#define AI_OBJMATERIAL_H_INC
#ifdef __GNUC__
# pragma GCC system_header
#endif
#include <assimp/material.h>
// ---------------------------------------------------------------------------
// the original illum property
#define AI_MATKEY_OBJ_ILLUM "$mat.illum", 0, 0
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// Pure key names for all obj texture-related properties
//! @cond MATS_DOC_FULL
// support for bump -bm
#define _AI_MATKEY_OBJ_BUMPMULT_BASE "$tex.bumpmult"
//! @endcond
// ---------------------------------------------------------------------------
#define AI_MATKEY_OBJ_BUMPMULT(type, N) _AI_MATKEY_OBJ_BUMPMULT_BASE, type, N
//! @cond MATS_DOC_FULL
#define AI_MATKEY_OBJ_BUMPMULT_NORMALS(N) \
AI_MATKEY_OBJ_BUMPMULT(aiTextureType_NORMALS, N)
#define AI_MATKEY_OBJ_BUMPMULT_HEIGHT(N) \
AI_MATKEY_OBJ_BUMPMULT(aiTextureType_HEIGHT, N)
//! @endcond
#endif

View File

@ -279,11 +279,11 @@ typedef unsigned int ai_uint;
#define AI_MATH_HALF_PI_F (AI_MATH_PI_F * 0.5f)
/* Tiny macro to convert from radians to degrees and back */
#define AI_DEG_TO_RAD(x) ((x) * (ai_real)0.0174532925)
#define AI_RAD_TO_DEG(x) ((x) * (ai_real)57.2957795)
#define AI_DEG_TO_RAD(x) ((x) * (ai_real) 0.0174532925)
#define AI_RAD_TO_DEG(x) ((x) * (ai_real) 57.2957795)
/* Numerical limits */
static const ai_real ai_epsilon = (ai_real)0.00001;
static const ai_real ai_epsilon = (ai_real) 1e-6;
/* Support for big-endian builds */
#if defined(__BYTE_ORDER__)

View File

@ -95,7 +95,7 @@ public:
bool operator== (const aiMatrix3x3t<TReal>& m) const;
bool operator!= (const aiMatrix3x3t<TReal>& m) const;
bool Equal(const aiMatrix3x3t<TReal>& m, TReal epsilon = 1e-6) const;
bool Equal(const aiMatrix3x3t<TReal> &m, TReal epsilon = ai_epsilon) const;
template <typename TOther>
operator aiMatrix3x3t<TOther> () const;

View File

@ -110,7 +110,7 @@ public:
bool operator== (const aiMatrix4x4t& m) const;
bool operator!= (const aiMatrix4x4t& m) const;
bool Equal(const aiMatrix4x4t& m, TReal epsilon = 1e-6) const;
bool Equal(const aiMatrix4x4t &m, TReal epsilon = ai_epsilon) const;
// matrix multiplication.
aiMatrix4x4t& operator *= (const aiMatrix4x4t& m);

View File

@ -92,7 +92,7 @@ public:
// transform vector by matrix
aiQuaterniont& operator *= (const aiMatrix4x4t<TReal>& mat);
bool Equal(const aiQuaterniont& o, TReal epsilon = 1e-6) const;
bool Equal(const aiQuaterniont &o, TReal epsilon = ai_epsilon) const;
public:

View File

@ -85,7 +85,7 @@ public:
bool operator== (const aiVector2t& other) const;
bool operator!= (const aiVector2t& other) const;
bool Equal(const aiVector2t& other, TReal epsilon = 1e-6) const;
bool Equal(const aiVector2t &other, TReal epsilon = ai_epsilon) const;
aiVector2t& operator= (TReal f);
const aiVector2t SymMul(const aiVector2t& o);

View File

@ -114,7 +114,7 @@ public:
bool operator < (const aiVector3t& other) const;
/// @brief
bool Equal(const aiVector3t& other, TReal epsilon = 1e-6) const;
bool Equal(const aiVector3t &other, TReal epsilon = ai_epsilon) const;
template <typename TOther>
operator aiVector3t<TOther> () const;

View File

@ -60,7 +60,7 @@ protected:
};
TEST_F(utMesh, emptyMeshHasNoContentTest) {
EXPECT_EQ(0, mesh->mName.length);
EXPECT_EQ(0u, mesh->mName.length);
EXPECT_FALSE(mesh->HasPositions());
EXPECT_FALSE(mesh->HasFaces());
EXPECT_FALSE(mesh->HasNormals());
@ -69,8 +69,8 @@ TEST_F(utMesh, emptyMeshHasNoContentTest) {
EXPECT_FALSE(mesh->HasVertexColors(AI_MAX_NUMBER_OF_COLOR_SETS));
EXPECT_FALSE(mesh->HasTextureCoords(0));
EXPECT_FALSE(mesh->HasTextureCoords(AI_MAX_NUMBER_OF_TEXTURECOORDS));
EXPECT_EQ(0, mesh->GetNumUVChannels());
EXPECT_EQ(0, mesh->GetNumColorChannels());
EXPECT_EQ(0u, mesh->GetNumUVChannels());
EXPECT_EQ(0u, mesh->GetNumColorChannels());
EXPECT_FALSE(mesh->HasBones());
EXPECT_FALSE(mesh->HasTextureCoordsName(0));
EXPECT_FALSE(mesh->HasTextureCoordsName(AI_MAX_NUMBER_OF_TEXTURECOORDS));
@ -80,8 +80,8 @@ TEST_F(utMesh, setTextureCoordsName) {
EXPECT_FALSE(mesh->HasTextureCoordsName(0));
const aiString texcoords_name("texcoord_name");
mesh->SetTextureCoordsName(0, texcoords_name);
EXPECT_TRUE(mesh->HasTextureCoordsName(0));
EXPECT_FALSE(mesh->HasTextureCoordsName(1));
EXPECT_TRUE(mesh->HasTextureCoordsName(0u));
EXPECT_FALSE(mesh->HasTextureCoordsName(1u));
ASSERT_NE(nullptr, mesh->mTextureCoordsNames);
ASSERT_NE(nullptr, mesh->mTextureCoordsNames[0]);
EXPECT_STREQ(texcoords_name.C_Str(), mesh->mTextureCoordsNames[0]->C_Str());
@ -94,3 +94,4 @@ TEST_F(utMesh, setTextureCoordsName) {
EXPECT_EQ(nullptr, mesh->mTextureCoordsNames[0]);
EXPECT_EQ(nullptr, mesh->GetTextureCoordsName(0));
}

View File

@ -124,9 +124,9 @@ TEST_F(utColladaExport, testExportLight) {
ASSERT_NE(pTest, nullptr);
ASSERT_TRUE(pTest->HasLights());
const unsigned int origNumLights(pTest->mNumLights);
const unsigned int origNumLights = pTest->mNumLights;
// There are FIVE!!! LIGHTS!!!
EXPECT_EQ(5, origNumLights) << "lights.dae should contain five lights";
EXPECT_EQ(5u, origNumLights) << "lights.dae should contain five lights";
std::vector<aiLight> origLights(5);
for (size_t i = 0; i < origNumLights; i++) {

View File

@ -573,7 +573,7 @@ TEST_F(utglTF2ImportExport, export_normalized_normals) {
scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals_out.glb", aiProcess_ValidateDataStructure);
for ( auto i = 0u; i < scene->mMeshes[0]->mNumVertices; ++i ) {
const auto length = scene->mMeshes[0]->mNormals[i].Length();
EXPECT_TRUE(abs(length) < 1e-6 || abs(length - 1) < 1e-6);
EXPECT_TRUE(abs(length) < 1e-6 || abs(length - 1) < ai_epsilon);
}
}