mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-12 15:14:35 +00:00
update assimp lib
This commit is contained in:
parent
03a348deb7
commit
d3f8fee74e
1725 changed files with 196314 additions and 62009 deletions
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
Copyright (c) 2006-2024, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*
|
||||
* glTF Extensions Support:
|
||||
* KHR_materials_pbrSpecularGlossiness full
|
||||
* KHR_materials_specular full
|
||||
* KHR_materials_unlit full
|
||||
* KHR_lights_punctual full
|
||||
* KHR_materials_sheen full
|
||||
|
|
@ -51,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* KHR_materials_transmission full
|
||||
* KHR_materials_volume full
|
||||
* KHR_materials_ior full
|
||||
* KHR_materials_emissive_strength full
|
||||
*/
|
||||
#ifndef GLTF2ASSET_H_INC
|
||||
#define GLTF2ASSET_H_INC
|
||||
|
|
@ -364,20 +366,20 @@ struct CustomExtension {
|
|||
|
||||
~CustomExtension() = default;
|
||||
|
||||
CustomExtension(const CustomExtension &other) :
|
||||
name(other.name),
|
||||
mStringValue(other.mStringValue),
|
||||
mDoubleValue(other.mDoubleValue),
|
||||
mUint64Value(other.mUint64Value),
|
||||
mInt64Value(other.mInt64Value),
|
||||
mBoolValue(other.mBoolValue),
|
||||
mValues(other.mValues) {
|
||||
// empty
|
||||
}
|
||||
CustomExtension(const CustomExtension &other) = default;
|
||||
|
||||
CustomExtension& operator=(const CustomExtension&) = default;
|
||||
};
|
||||
|
||||
//! Represents metadata in an glTF2 object
|
||||
struct Extras {
|
||||
std::vector<CustomExtension> mValues;
|
||||
|
||||
inline bool HasExtras() const {
|
||||
return !mValues.empty();
|
||||
}
|
||||
};
|
||||
|
||||
//! Base class for all glTF top-level objects
|
||||
struct Object {
|
||||
int index; //!< The index of this object within its property container
|
||||
|
|
@ -386,7 +388,7 @@ struct Object {
|
|||
std::string name; //!< The user-defined name of this object
|
||||
|
||||
CustomExtension customExtensions;
|
||||
CustomExtension extras;
|
||||
Extras extras;
|
||||
|
||||
//! Objects marked as special are not exported (used to emulate the binary body buffer)
|
||||
virtual bool IsSpecial() const { return false; }
|
||||
|
|
@ -491,7 +493,7 @@ private:
|
|||
|
||||
public:
|
||||
Buffer();
|
||||
~Buffer();
|
||||
~Buffer() override;
|
||||
|
||||
void Read(Value &obj, Asset &r);
|
||||
|
||||
|
|
@ -545,7 +547,7 @@ struct BufferView : public Object {
|
|||
BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
|
||||
|
||||
void Read(Value &obj, Asset &r);
|
||||
uint8_t *GetPointer(size_t accOffset);
|
||||
uint8_t *GetPointerAndTailSize(size_t accOffset, size_t& outTailSize);
|
||||
};
|
||||
|
||||
//! A typed view into a BufferView. A BufferView contains raw binary data.
|
||||
|
|
@ -573,7 +575,7 @@ struct Accessor : public Object {
|
|||
inline size_t GetMaxByteSize();
|
||||
|
||||
template <class T>
|
||||
void ExtractData(T *&outData);
|
||||
size_t ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices = nullptr);
|
||||
|
||||
void WriteData(size_t count, const void *src_buffer, size_t src_stride);
|
||||
void WriteSparseValues(size_t count, const void *src_data, size_t src_dataStride);
|
||||
|
|
@ -627,7 +629,7 @@ struct Accessor : public Object {
|
|||
|
||||
std::vector<uint8_t> data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it.
|
||||
|
||||
void PopulateData(size_t numBytes, uint8_t *bytes);
|
||||
void PopulateData(size_t numBytes, const uint8_t *bytes);
|
||||
void PatchData(unsigned int elementSize);
|
||||
};
|
||||
};
|
||||
|
|
@ -718,6 +720,7 @@ const vec4 defaultBaseColor = { 1, 1, 1, 1 };
|
|||
const vec3 defaultEmissiveFactor = { 0, 0, 0 };
|
||||
const vec4 defaultDiffuseFactor = { 1, 1, 1, 1 };
|
||||
const vec3 defaultSpecularFactor = { 1, 1, 1 };
|
||||
const vec3 defaultSpecularColorFactor = { 1, 1, 1 };
|
||||
const vec3 defaultSheenFactor = { 0, 0, 0 };
|
||||
const vec3 defaultAttenuationColor = { 1, 1, 1 };
|
||||
|
||||
|
|
@ -761,6 +764,16 @@ struct PbrSpecularGlossiness {
|
|||
void SetDefaults();
|
||||
};
|
||||
|
||||
struct MaterialSpecular {
|
||||
float specularFactor;
|
||||
vec3 specularColorFactor;
|
||||
TextureInfo specularTexture;
|
||||
TextureInfo specularColorTexture;
|
||||
|
||||
MaterialSpecular() { SetDefaults(); }
|
||||
void SetDefaults();
|
||||
};
|
||||
|
||||
struct MaterialSheen {
|
||||
vec3 sheenColorFactor;
|
||||
float sheenRoughnessFactor;
|
||||
|
|
@ -801,6 +814,13 @@ struct MaterialIOR {
|
|||
void SetDefaults();
|
||||
};
|
||||
|
||||
struct MaterialEmissiveStrength {
|
||||
float emissiveStrength = 0.f;
|
||||
|
||||
MaterialEmissiveStrength() { SetDefaults(); }
|
||||
void SetDefaults();
|
||||
};
|
||||
|
||||
//! The material appearance of a primitive.
|
||||
struct Material : public Object {
|
||||
//PBR metallic roughness properties
|
||||
|
|
@ -818,6 +838,9 @@ struct Material : public Object {
|
|||
//extension: KHR_materials_pbrSpecularGlossiness
|
||||
Nullable<PbrSpecularGlossiness> pbrSpecularGlossiness;
|
||||
|
||||
//extension: KHR_materials_specular
|
||||
Nullable<MaterialSpecular> materialSpecular;
|
||||
|
||||
//extension: KHR_materials_sheen
|
||||
Nullable<MaterialSheen> materialSheen;
|
||||
|
||||
|
|
@ -832,7 +855,10 @@ struct Material : public Object {
|
|||
|
||||
//extension: KHR_materials_ior
|
||||
Nullable<MaterialIOR> materialIOR;
|
||||
|
||||
|
||||
//extension: KHR_materials_emissive_strength
|
||||
Nullable<MaterialEmissiveStrength> materialEmissiveStrength;
|
||||
|
||||
//extension: KHR_materials_unlit
|
||||
bool unlit;
|
||||
|
||||
|
|
@ -1044,7 +1070,7 @@ class LazyDict : public LazyDictBase {
|
|||
Ref<T> Add(T *obj);
|
||||
|
||||
public:
|
||||
LazyDict(Asset &asset, const char *dictId, const char *extId = 0);
|
||||
LazyDict(Asset &asset, const char *dictId, const char *extId = nullptr);
|
||||
~LazyDict();
|
||||
|
||||
Ref<T> Retrieve(unsigned int i);
|
||||
|
|
@ -1075,8 +1101,7 @@ struct AssetMetadata {
|
|||
|
||||
void Read(Document &doc);
|
||||
|
||||
AssetMetadata() :
|
||||
version() {}
|
||||
AssetMetadata() = default;
|
||||
};
|
||||
|
||||
//
|
||||
|
|
@ -1098,6 +1123,7 @@ public:
|
|||
//! Keeps info about the enabled extensions
|
||||
struct Extensions {
|
||||
bool KHR_materials_pbrSpecularGlossiness;
|
||||
bool KHR_materials_specular;
|
||||
bool KHR_materials_unlit;
|
||||
bool KHR_lights_punctual;
|
||||
bool KHR_texture_transform;
|
||||
|
|
@ -1106,12 +1132,14 @@ public:
|
|||
bool KHR_materials_transmission;
|
||||
bool KHR_materials_volume;
|
||||
bool KHR_materials_ior;
|
||||
bool KHR_materials_emissive_strength;
|
||||
bool KHR_draco_mesh_compression;
|
||||
bool FB_ngon_encoding;
|
||||
bool KHR_texture_basisu;
|
||||
|
||||
Extensions() :
|
||||
KHR_materials_pbrSpecularGlossiness(false),
|
||||
KHR_materials_specular(false),
|
||||
KHR_materials_unlit(false),
|
||||
KHR_lights_punctual(false),
|
||||
KHR_texture_transform(false),
|
||||
|
|
@ -1120,6 +1148,7 @@ public:
|
|||
KHR_materials_transmission(false),
|
||||
KHR_materials_volume(false),
|
||||
KHR_materials_ior(false),
|
||||
KHR_materials_emissive_strength(false),
|
||||
KHR_draco_mesh_compression(false),
|
||||
FB_ngon_encoding(false),
|
||||
KHR_texture_basisu(false) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
Copyright (c) 2006-2024, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -45,6 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Base64.hpp>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/schema.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
|
||||
// clang-format off
|
||||
#ifdef ASSIMP_ENABLE_DRACO
|
||||
|
|
@ -139,6 +142,18 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
inline Extras ReadExtras(Value &obj) {
|
||||
Extras ret;
|
||||
|
||||
ret.mValues.reserve(obj.MemberCount());
|
||||
for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
|
||||
auto &val = it->value;
|
||||
ret.mValues.emplace_back(ReadExtensions(it->name.GetString(), val));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void CopyData(size_t count, const uint8_t *src, size_t src_stride,
|
||||
uint8_t *dst, size_t dst_stride) {
|
||||
if (src_stride == dst_stride) {
|
||||
|
|
@ -248,7 +263,7 @@ inline void Object::ReadExtensions(Value &val) {
|
|||
|
||||
inline void Object::ReadExtras(Value &val) {
|
||||
if (Value *curExtras = FindObject(val, "extras")) {
|
||||
this->extras = glTF2::ReadExtensions("extras", *curExtras);
|
||||
this->extras = glTF2::ReadExtras(*curExtras);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -279,6 +294,8 @@ inline void SetDecodedIndexBuffer_Draco(const draco::Mesh &dracoMesh, Mesh::Prim
|
|||
// Usually uint32_t but shouldn't assume
|
||||
if (sizeof(dracoMesh.face(draco::FaceIndex(0))[0]) == componentBytes) {
|
||||
memcpy(decodedIndexBuffer->GetPointer(), &dracoMesh.face(draco::FaceIndex(0))[0], decodedIndexBuffer->byteLength);
|
||||
// Assign this alternate data buffer to the accessor
|
||||
prim.indices->decodedBuffer.swap(decodedIndexBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -371,7 +388,7 @@ template <class T>
|
|||
inline LazyDict<T>::LazyDict(Asset &asset, const char *dictId, const char *extId) :
|
||||
mDictId(dictId),
|
||||
mExtId(extId),
|
||||
mDict(0),
|
||||
mDict(nullptr),
|
||||
mAsset(asset) {
|
||||
asset.mDicts.push_back(this); // register to the list of dictionaries
|
||||
}
|
||||
|
|
@ -770,12 +787,14 @@ inline void BufferView::Read(Value &obj, Asset &r) {
|
|||
}
|
||||
}
|
||||
|
||||
inline uint8_t *BufferView::GetPointer(size_t accOffset) {
|
||||
inline uint8_t *BufferView::GetPointerAndTailSize(size_t accOffset, size_t& outTailSize) {
|
||||
if (!buffer) {
|
||||
outTailSize = 0;
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t *basePtr = buffer->GetPointer();
|
||||
uint8_t * const basePtr = buffer->GetPointer();
|
||||
if (!basePtr) {
|
||||
outTailSize = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -784,17 +803,25 @@ inline uint8_t *BufferView::GetPointer(size_t accOffset) {
|
|||
const size_t begin = buffer->EncodedRegion_Current->Offset;
|
||||
const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length;
|
||||
if ((offset >= begin) && (offset < end)) {
|
||||
outTailSize = end - offset;
|
||||
return &buffer->EncodedRegion_Current->DecodedData[offset - begin];
|
||||
}
|
||||
}
|
||||
|
||||
if (offset >= buffer->byteLength)
|
||||
{
|
||||
outTailSize = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
outTailSize = buffer->byteLength - offset;
|
||||
return basePtr + offset;
|
||||
}
|
||||
|
||||
//
|
||||
// struct Accessor
|
||||
//
|
||||
inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
|
||||
inline void Accessor::Sparse::PopulateData(size_t numBytes, const uint8_t *bytes) {
|
||||
if (bytes) {
|
||||
data.assign(bytes, bytes + numBytes);
|
||||
} else {
|
||||
|
|
@ -803,11 +830,21 @@ inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) {
|
|||
}
|
||||
|
||||
inline void Accessor::Sparse::PatchData(unsigned int elementSize) {
|
||||
uint8_t *pIndices = indices->GetPointer(indicesByteOffset);
|
||||
size_t indicesTailDataSize;
|
||||
uint8_t *pIndices = indices->GetPointerAndTailSize(indicesByteOffset, indicesTailDataSize);
|
||||
const unsigned int indexSize = int(ComponentTypeSize(indicesType));
|
||||
uint8_t *indicesEnd = pIndices + count * indexSize;
|
||||
|
||||
uint8_t *pValues = values->GetPointer(valuesByteOffset);
|
||||
if ((uint64_t)indicesEnd > (uint64_t)pIndices + indicesTailDataSize) {
|
||||
throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
|
||||
}
|
||||
|
||||
size_t valuesTailDataSize;
|
||||
uint8_t* pValues = values->GetPointerAndTailSize(valuesByteOffset, valuesTailDataSize);
|
||||
|
||||
if (elementSize * count > valuesTailDataSize) {
|
||||
throw DeadlyImportError("Invalid sparse accessor. Indices outside allocated memory.");
|
||||
}
|
||||
while (pIndices != indicesEnd) {
|
||||
size_t offset;
|
||||
switch (indicesType) {
|
||||
|
|
@ -879,6 +916,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
|
|||
if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
|
||||
//indices bufferView
|
||||
Value *indiceViewID = FindUInt(*indicesValue, "bufferView");
|
||||
if (!indiceViewID) {
|
||||
throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
|
||||
}
|
||||
sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint());
|
||||
//indices byteOffset
|
||||
sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0));
|
||||
|
|
@ -894,6 +934,9 @@ inline void Accessor::Read(Value &obj, Asset &r) {
|
|||
if (Value *valuesValue = FindObject(*sparseValue, "values")) {
|
||||
//value bufferView
|
||||
Value *valueViewID = FindUInt(*valuesValue, "bufferView");
|
||||
if (!valueViewID) {
|
||||
throw DeadlyImportError("A bufferView value is required, when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
|
||||
}
|
||||
sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint());
|
||||
//value byteOffset
|
||||
sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0));
|
||||
|
|
@ -903,8 +946,18 @@ inline void Accessor::Read(Value &obj, Asset &r) {
|
|||
|
||||
const unsigned int elementSize = GetElementSize();
|
||||
const size_t dataSize = count * elementSize;
|
||||
sparse->PopulateData(dataSize, bufferView ? bufferView->GetPointer(byteOffset) : 0);
|
||||
sparse->PatchData(elementSize);
|
||||
if (bufferView) {
|
||||
size_t bufferViewTailSize;
|
||||
const uint8_t* bufferViewPointer = bufferView->GetPointerAndTailSize(byteOffset, bufferViewTailSize);
|
||||
if (dataSize > bufferViewTailSize) {
|
||||
throw DeadlyImportError("Invalid buffer when reading ", id.c_str(), name.empty() ? "" : " (" + name + ")");
|
||||
}
|
||||
sparse->PopulateData(dataSize, bufferViewPointer);
|
||||
}
|
||||
else {
|
||||
sparse->PopulateData(dataSize, nullptr);
|
||||
}
|
||||
sparse->PatchData(elementSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -962,14 +1015,15 @@ inline size_t Accessor::GetMaxByteSize() {
|
|||
}
|
||||
|
||||
template <class T>
|
||||
void Accessor::ExtractData(T *&outData) {
|
||||
size_t Accessor::ExtractData(T *&outData, const std::vector<unsigned int> *remappingIndices) {
|
||||
uint8_t *data = GetPointer();
|
||||
if (!data) {
|
||||
throw DeadlyImportError("GLTF2: data is null when extracting data from ", getContextForErrorMessages(id, name));
|
||||
}
|
||||
|
||||
const size_t usedCount = (remappingIndices != nullptr) ? remappingIndices->size() : count;
|
||||
const size_t elemSize = GetElementSize();
|
||||
const size_t totalSize = elemSize * count;
|
||||
const size_t totalSize = elemSize * usedCount;
|
||||
|
||||
const size_t stride = GetStride();
|
||||
|
||||
|
|
@ -980,18 +1034,31 @@ void Accessor::ExtractData(T *&outData) {
|
|||
}
|
||||
|
||||
const size_t maxSize = GetMaxByteSize();
|
||||
if (count * stride > maxSize) {
|
||||
throw DeadlyImportError("GLTF: count*stride ", (count * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
|
||||
}
|
||||
|
||||
outData = new T[count];
|
||||
if (stride == elemSize && targetElemSize == elemSize) {
|
||||
memcpy(outData, data, totalSize);
|
||||
} else {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
memcpy(outData + i, data + i * stride, elemSize);
|
||||
outData = new T[usedCount];
|
||||
|
||||
if (remappingIndices != nullptr) {
|
||||
const unsigned int maxIndexCount = static_cast<unsigned int>(maxSize / stride);
|
||||
for (size_t i = 0; i < usedCount; ++i) {
|
||||
size_t srcIdx = (*remappingIndices)[i];
|
||||
if (srcIdx >= maxIndexCount) {
|
||||
throw DeadlyImportError("GLTF: index*stride ", (srcIdx * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
|
||||
}
|
||||
memcpy(outData + i, data + srcIdx * stride, elemSize);
|
||||
}
|
||||
} else { // non-indexed cases
|
||||
if (usedCount * stride > maxSize) {
|
||||
throw DeadlyImportError("GLTF: count*stride ", (usedCount * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
|
||||
}
|
||||
if (stride == elemSize && targetElemSize == elemSize) {
|
||||
memcpy(outData, data, totalSize);
|
||||
} else {
|
||||
for (size_t i = 0; i < usedCount; ++i) {
|
||||
memcpy(outData + i, data + i * stride, elemSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
return usedCount;
|
||||
}
|
||||
|
||||
inline void Accessor::WriteData(size_t _count, const void *src_buffer, size_t src_stride) {
|
||||
|
|
@ -1249,6 +1316,19 @@ inline void Material::Read(Value &material, Asset &r) {
|
|||
this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
|
||||
}
|
||||
}
|
||||
|
||||
if (r.extensionsUsed.KHR_materials_specular) {
|
||||
if (Value *curMatSpecular = FindObject(*extensions, "KHR_materials_specular")) {
|
||||
MaterialSpecular specular;
|
||||
|
||||
ReadMember(*curMatSpecular, "specularFactor", specular.specularFactor);
|
||||
ReadTextureProperty(r, *curMatSpecular, "specularTexture", specular.specularTexture);
|
||||
ReadMember(*curMatSpecular, "specularColorFactor", specular.specularColorFactor);
|
||||
ReadTextureProperty(r, *curMatSpecular, "specularColorTexture", specular.specularColorTexture);
|
||||
|
||||
this->materialSpecular = Nullable<MaterialSpecular>(specular);
|
||||
}
|
||||
}
|
||||
|
||||
// Extension KHR_texture_transform is handled in ReadTextureProperty
|
||||
|
||||
|
|
@ -1313,6 +1393,16 @@ inline void Material::Read(Value &material, Asset &r) {
|
|||
}
|
||||
}
|
||||
|
||||
if (r.extensionsUsed.KHR_materials_emissive_strength) {
|
||||
if (Value *curMaterialEmissiveStrength = FindObject(*extensions, "KHR_materials_emissive_strength")) {
|
||||
MaterialEmissiveStrength emissiveStrength;
|
||||
|
||||
ReadMember(*curMaterialEmissiveStrength, "emissiveStrength", emissiveStrength.emissiveStrength);
|
||||
|
||||
this->materialEmissiveStrength = Nullable<MaterialEmissiveStrength>(emissiveStrength);
|
||||
}
|
||||
}
|
||||
|
||||
unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
|
||||
}
|
||||
}
|
||||
|
|
@ -1337,6 +1427,12 @@ inline void PbrSpecularGlossiness::SetDefaults() {
|
|||
glossinessFactor = 1.0f;
|
||||
}
|
||||
|
||||
inline void MaterialSpecular::SetDefaults() {
|
||||
//KHR_materials_specular properties
|
||||
SetVector(specularColorFactor, defaultSpecularColorFactor);
|
||||
specularFactor = 1.f;
|
||||
}
|
||||
|
||||
inline void MaterialSheen::SetDefaults() {
|
||||
//KHR_materials_sheen properties
|
||||
SetVector(sheenColorFactor, defaultSheenFactor);
|
||||
|
|
@ -1346,7 +1442,7 @@ inline void MaterialSheen::SetDefaults() {
|
|||
inline void MaterialVolume::SetDefaults() {
|
||||
//KHR_materials_volume properties
|
||||
thicknessFactor = 0.f;
|
||||
attenuationDistance = INFINITY;
|
||||
attenuationDistance = std::numeric_limits<float>::infinity();
|
||||
SetVector(attenuationColor, defaultAttenuationColor);
|
||||
}
|
||||
|
||||
|
|
@ -1355,6 +1451,11 @@ inline void MaterialIOR::SetDefaults() {
|
|||
ior = 1.5f;
|
||||
}
|
||||
|
||||
inline void MaterialEmissiveStrength::SetDefaults() {
|
||||
//KHR_materials_emissive_strength properties
|
||||
emissiveStrength = 0.f;
|
||||
}
|
||||
|
||||
inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
|
||||
Value *curName = FindMember(pJSON_Object, "name");
|
||||
if (nullptr != curName && curName->IsString()) {
|
||||
|
|
@ -1489,6 +1590,22 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(this->targetNames.empty())
|
||||
{
|
||||
Value *curExtras = FindObject(primitive, "extras");
|
||||
if (nullptr != curExtras) {
|
||||
if (Value *curTargetNames = FindArray(*curExtras, "targetNames")) {
|
||||
this->targetNames.resize(curTargetNames->Size());
|
||||
for (unsigned int j = 0; j < curTargetNames->Size(); ++j) {
|
||||
Value &targetNameValue = (*curTargetNames)[j];
|
||||
if (targetNameValue.IsString()) {
|
||||
this->targetNames[j] = targetNameValue.GetString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1888,7 +2005,7 @@ inline void Asset::Load(const std::string &pFile, bool isBinary)
|
|||
std::vector<char> sceneData;
|
||||
rapidjson::Document doc = ReadDocument(*stream, isBinary, sceneData);
|
||||
|
||||
// If a schemaDocumentProvider is available, see if the glTF schema is present.
|
||||
// If a schemaDocumentProvider is available, see if the glTF schema is present.
|
||||
// If so, use it to validate the document.
|
||||
if (mSchemaDocumentProvider) {
|
||||
if (const rapidjson::SchemaDocument *gltfSchema = mSchemaDocumentProvider->GetRemoteDocument("glTF.schema.json", 16)) {
|
||||
|
|
@ -2018,6 +2135,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
|
|||
}
|
||||
|
||||
CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
|
||||
CHECK_EXT(KHR_materials_specular);
|
||||
CHECK_EXT(KHR_materials_unlit);
|
||||
CHECK_EXT(KHR_lights_punctual);
|
||||
CHECK_EXT(KHR_texture_transform);
|
||||
|
|
@ -2026,6 +2144,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) {
|
|||
CHECK_EXT(KHR_materials_transmission);
|
||||
CHECK_EXT(KHR_materials_volume);
|
||||
CHECK_EXT(KHR_materials_ior);
|
||||
CHECK_EXT(KHR_materials_emissive_strength);
|
||||
CHECK_EXT(KHR_draco_mesh_compression);
|
||||
CHECK_EXT(KHR_texture_basisu);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
Copyright (c) 2006-2024, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -45,12 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*
|
||||
* glTF Extensions Support:
|
||||
* KHR_materials_pbrSpecularGlossiness: full
|
||||
* KHR_materials_specular: full
|
||||
* KHR_materials_unlit: full
|
||||
* KHR_materials_sheen: full
|
||||
* KHR_materials_clearcoat: full
|
||||
* KHR_materials_transmission: full
|
||||
* KHR_materials_volume: full
|
||||
* KHR_materials_ior: full
|
||||
* KHR_materials_emissive_strength: full
|
||||
*/
|
||||
#ifndef GLTF2ASSETWRITER_H_INC
|
||||
#define GLTF2ASSETWRITER_H_INC
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
Copyright (c) 2006-2024, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -418,6 +418,27 @@ namespace glTF2 {
|
|||
exts.AddMember("KHR_materials_unlit", unlit, w.mAl);
|
||||
}
|
||||
|
||||
if (m.materialSpecular.isPresent) {
|
||||
Value materialSpecular(rapidjson::Type::kObjectType);
|
||||
materialSpecular.SetObject();
|
||||
|
||||
MaterialSpecular &specular = m.materialSpecular.value;
|
||||
|
||||
if (specular.specularFactor != 0.0f) {
|
||||
WriteFloat(materialSpecular, specular.specularFactor, "specularFactor", w.mAl);
|
||||
}
|
||||
if (specular.specularColorFactor[0] != defaultSpecularColorFactor[0] && specular.specularColorFactor[1] != defaultSpecularColorFactor[1] && specular.specularColorFactor[2] != defaultSpecularColorFactor[2]) {
|
||||
WriteVec(materialSpecular, specular.specularColorFactor, "specularColorFactor", w.mAl);
|
||||
}
|
||||
|
||||
WriteTex(materialSpecular, specular.specularTexture, "specularTexture", w.mAl);
|
||||
WriteTex(materialSpecular, specular.specularColorTexture, "specularColorTexture", w.mAl);
|
||||
|
||||
if (!materialSpecular.ObjectEmpty()) {
|
||||
exts.AddMember("KHR_materials_specular", materialSpecular, w.mAl);
|
||||
}
|
||||
}
|
||||
|
||||
if (m.materialSheen.isPresent) {
|
||||
Value materialSheen(rapidjson::Type::kObjectType);
|
||||
|
||||
|
|
@ -486,7 +507,7 @@ namespace glTF2 {
|
|||
|
||||
WriteTex(materialVolume, volume.thicknessTexture, "thicknessTexture", w.mAl);
|
||||
|
||||
if (volume.attenuationDistance != INFINITY) {
|
||||
if (volume.attenuationDistance != std::numeric_limits<float>::infinity()) {
|
||||
WriteFloat(materialVolume, volume.attenuationDistance, "attenuationDistance", w.mAl);
|
||||
}
|
||||
|
||||
|
|
@ -511,6 +532,20 @@ namespace glTF2 {
|
|||
}
|
||||
}
|
||||
|
||||
if (m.materialEmissiveStrength.isPresent) {
|
||||
Value materialEmissiveStrength(rapidjson::Type::kObjectType);
|
||||
|
||||
MaterialEmissiveStrength &emissiveStrength = m.materialEmissiveStrength.value;
|
||||
|
||||
if (emissiveStrength.emissiveStrength != 0.f) {
|
||||
WriteFloat(materialEmissiveStrength, emissiveStrength.emissiveStrength, "emissiveStrength", w.mAl);
|
||||
}
|
||||
|
||||
if (!materialEmissiveStrength.ObjectEmpty()) {
|
||||
exts.AddMember("KHR_materials_emissive_strength", materialEmissiveStrength, w.mAl);
|
||||
}
|
||||
}
|
||||
|
||||
if (!exts.ObjectEmpty()) {
|
||||
obj.AddMember("extensions", exts, w.mAl);
|
||||
}
|
||||
|
|
@ -536,7 +571,7 @@ namespace glTF2 {
|
|||
|
||||
inline void Write(Value& obj, Mesh& m, AssetWriter& w)
|
||||
{
|
||||
/****************** Primitives *******************/
|
||||
/****************** Primitives *******************/
|
||||
Value primitives;
|
||||
primitives.SetArray();
|
||||
primitives.Reserve(unsigned(m.primitives.size()), w.mAl);
|
||||
|
|
@ -620,6 +655,44 @@ namespace glTF2 {
|
|||
}
|
||||
}
|
||||
|
||||
inline void WriteExtrasValue(Value &parent, const CustomExtension &value, AssetWriter &w) {
|
||||
Value valueNode;
|
||||
|
||||
if (value.mStringValue.isPresent) {
|
||||
MakeValue(valueNode, value.mStringValue.value.c_str(), w.mAl);
|
||||
} else if (value.mDoubleValue.isPresent) {
|
||||
MakeValue(valueNode, value.mDoubleValue.value, w.mAl);
|
||||
} else if (value.mUint64Value.isPresent) {
|
||||
MakeValue(valueNode, value.mUint64Value.value, w.mAl);
|
||||
} else if (value.mInt64Value.isPresent) {
|
||||
MakeValue(valueNode, value.mInt64Value.value, w.mAl);
|
||||
} else if (value.mBoolValue.isPresent) {
|
||||
MakeValue(valueNode, value.mBoolValue.value, w.mAl);
|
||||
} else if (value.mValues.isPresent) {
|
||||
valueNode.SetObject();
|
||||
for (auto const &subvalue : value.mValues.value) {
|
||||
WriteExtrasValue(valueNode, subvalue, w);
|
||||
}
|
||||
}
|
||||
|
||||
parent.AddMember(StringRef(value.name), valueNode, w.mAl);
|
||||
}
|
||||
|
||||
inline void WriteExtras(Value &obj, const Extras &extras, AssetWriter &w) {
|
||||
if (!extras.HasExtras()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Value extrasNode;
|
||||
extrasNode.SetObject();
|
||||
|
||||
for (auto const &value : extras.mValues) {
|
||||
WriteExtrasValue(extrasNode, value, w);
|
||||
}
|
||||
|
||||
obj.AddMember("extras", extrasNode, w.mAl);
|
||||
}
|
||||
|
||||
inline void Write(Value& obj, Node& n, AssetWriter& w)
|
||||
{
|
||||
if (n.matrix.isPresent) {
|
||||
|
|
@ -655,6 +728,8 @@ namespace glTF2 {
|
|||
if(n.skeletons.size()) {
|
||||
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
|
||||
}
|
||||
|
||||
WriteExtras(obj, n.extras, w);
|
||||
}
|
||||
|
||||
inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/)
|
||||
|
|
@ -728,7 +803,6 @@ namespace glTF2 {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
inline AssetWriter::AssetWriter(Asset& a)
|
||||
: mDoc()
|
||||
, mAsset(a)
|
||||
|
|
@ -758,7 +832,7 @@ namespace glTF2 {
|
|||
{
|
||||
std::unique_ptr<IOStream> jsonOutFile(mAsset.OpenFile(path, "wt", true));
|
||||
|
||||
if (jsonOutFile == 0) {
|
||||
if (jsonOutFile == nullptr) {
|
||||
throw DeadlyExportError("Could not open output file: " + std::string(path));
|
||||
}
|
||||
|
||||
|
|
@ -781,7 +855,7 @@ namespace glTF2 {
|
|||
|
||||
std::unique_ptr<IOStream> binOutFile(mAsset.OpenFile(binPath, "wb", true));
|
||||
|
||||
if (binOutFile == 0) {
|
||||
if (binOutFile == nullptr) {
|
||||
throw DeadlyExportError("Could not open output file: " + binPath);
|
||||
}
|
||||
|
||||
|
|
@ -797,7 +871,7 @@ namespace glTF2 {
|
|||
{
|
||||
std::unique_ptr<IOStream> outfile(mAsset.OpenFile(path, "wb", true));
|
||||
|
||||
if (outfile == 0) {
|
||||
if (outfile == nullptr) {
|
||||
throw DeadlyExportError("Could not open output file: " + std::string(path));
|
||||
}
|
||||
|
||||
|
|
@ -822,7 +896,7 @@ namespace glTF2 {
|
|||
throw DeadlyExportError("Failed to write scene data!");
|
||||
}
|
||||
|
||||
uint32_t jsonChunkLength = (docBuffer.GetSize() + 3) & ~3; // Round up to next multiple of 4
|
||||
uint32_t jsonChunkLength = static_cast<uint32_t>((docBuffer.GetSize() + 3) & ~3); // Round up to next multiple of 4
|
||||
auto paddingLength = jsonChunkLength - docBuffer.GetSize();
|
||||
|
||||
GLB_Chunk jsonChunk;
|
||||
|
|
@ -848,7 +922,7 @@ namespace glTF2 {
|
|||
int GLB_Chunk_count = 1;
|
||||
uint32_t binaryChunkLength = 0;
|
||||
if (bodyBuffer->byteLength > 0) {
|
||||
binaryChunkLength = (bodyBuffer->byteLength + 3) & ~3; // Round up to next multiple of 4
|
||||
binaryChunkLength = static_cast<uint32_t>((bodyBuffer->byteLength + 3) & ~3); // Round up to next multiple of 4
|
||||
|
||||
auto curPaddingLength = binaryChunkLength - bodyBuffer->byteLength;
|
||||
++GLB_Chunk_count;
|
||||
|
|
@ -866,7 +940,7 @@ namespace glTF2 {
|
|||
if (outfile->Write(bodyBuffer->GetPointer(), 1, bodyBuffer->byteLength) != bodyBuffer->byteLength) {
|
||||
throw DeadlyExportError("Failed to write body data!");
|
||||
}
|
||||
if (curPaddingLength && outfile->Write(&padding, 1, paddingLength) != paddingLength) {
|
||||
if (curPaddingLength && outfile->Write(&padding, 1, curPaddingLength) != curPaddingLength) {
|
||||
throw DeadlyExportError("Failed to write body data padding!");
|
||||
}
|
||||
}
|
||||
|
|
@ -915,6 +989,10 @@ namespace glTF2 {
|
|||
exts.PushBack(StringRef("KHR_materials_unlit"), mAl);
|
||||
}
|
||||
|
||||
if (this->mAsset.extensionsUsed.KHR_materials_specular) {
|
||||
exts.PushBack(StringRef("KHR_materials_specular"), mAl);
|
||||
}
|
||||
|
||||
if (this->mAsset.extensionsUsed.KHR_materials_sheen) {
|
||||
exts.PushBack(StringRef("KHR_materials_sheen"), mAl);
|
||||
}
|
||||
|
|
@ -935,6 +1013,10 @@ namespace glTF2 {
|
|||
exts.PushBack(StringRef("KHR_materials_ior"), mAl);
|
||||
}
|
||||
|
||||
if (this->mAsset.extensionsUsed.KHR_materials_emissive_strength) {
|
||||
exts.PushBack(StringRef("KHR_materials_emissive_strength"), mAl);
|
||||
}
|
||||
|
||||
if (this->mAsset.extensionsUsed.FB_ngon_encoding) {
|
||||
exts.PushBack(StringRef("FB_ngon_encoding"), mAl);
|
||||
}
|
||||
|
|
@ -962,7 +1044,7 @@ namespace glTF2 {
|
|||
if (d.mObjs.empty()) return;
|
||||
|
||||
Value* container = &mDoc;
|
||||
const char* context = "Document";
|
||||
const char* context = "Document";
|
||||
|
||||
if (d.mExtId) {
|
||||
Value* exts = FindObject(mDoc, "extensions");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
Copyright (c) 2006-2024, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -55,11 +55,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/version.h>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/config.h>
|
||||
|
||||
// Header files, standard library.
|
||||
#include <cinttypes>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
|
|
@ -90,6 +92,10 @@ glTF2Exporter::glTF2Exporter(const char *filename, IOSystem *pIOSystem, const ai
|
|||
// Always on as our triangulation process is aware of this type of encoding
|
||||
mAsset->extensionsUsed.FB_ngon_encoding = true;
|
||||
|
||||
configEpsilon = mProperties->GetPropertyFloat(
|
||||
AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON,
|
||||
(ai_real)AI_CONFIG_CHECK_IDENTITY_MATRIX_EPSILON_DEFAULT);
|
||||
|
||||
if (isBinary) {
|
||||
mAsset->SetAsBinary();
|
||||
}
|
||||
|
|
@ -172,22 +178,6 @@ static void IdentityMatrix4(mat4 &o) {
|
|||
o[15] = 1;
|
||||
}
|
||||
|
||||
static bool IsBoneWeightFitted(vec4 &weight) {
|
||||
return weight[0] + weight[1] + weight[2] + weight[3] >= 1.f;
|
||||
}
|
||||
|
||||
static int FitBoneWeight(vec4 &weight, float value) {
|
||||
int i = 0;
|
||||
for (; i < 4; ++i) {
|
||||
if (weight[i] < value) {
|
||||
weight[i] = value;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SetAccessorRange(Ref<Accessor> acc, void *data, size_t count,
|
||||
unsigned int numCompsIn, unsigned int numCompsOut) {
|
||||
|
|
@ -263,7 +253,7 @@ size_t NZDiff(void *data, void *dataBase, size_t count, unsigned int numCompsIn,
|
|||
for (short idx = 0; bufferData_ptr < bufferData_end; idx += 1, bufferData_ptr += numCompsIn) {
|
||||
bool bNonZero = false;
|
||||
|
||||
//for the data, check any component Non Zero
|
||||
// for the data, check any component Non Zero
|
||||
for (unsigned int j = 0; j < numCompsOut; j++) {
|
||||
double valueData = bufferData_ptr[j];
|
||||
double valueBase = bufferBase_ptr ? bufferBase_ptr[j] : 0;
|
||||
|
|
@ -273,11 +263,11 @@ size_t NZDiff(void *data, void *dataBase, size_t count, unsigned int numCompsIn,
|
|||
}
|
||||
}
|
||||
|
||||
//all zeros, continue
|
||||
// all zeros, continue
|
||||
if (!bNonZero)
|
||||
continue;
|
||||
|
||||
//non zero, store the data
|
||||
// non zero, store the data
|
||||
for (unsigned int j = 0; j < numCompsOut; j++) {
|
||||
T valueData = bufferData_ptr[j];
|
||||
T valueBase = bufferBase_ptr ? bufferBase_ptr[j] : 0;
|
||||
|
|
@ -286,14 +276,14 @@ size_t NZDiff(void *data, void *dataBase, size_t count, unsigned int numCompsIn,
|
|||
vNZIdx.push_back(idx);
|
||||
}
|
||||
|
||||
//avoid all-0, put 1 item
|
||||
// avoid all-0, put 1 item
|
||||
if (vNZDiff.size() == 0) {
|
||||
for (unsigned int j = 0; j < numCompsOut; j++)
|
||||
vNZDiff.push_back(0);
|
||||
vNZIdx.push_back(0);
|
||||
}
|
||||
|
||||
//process data
|
||||
// process data
|
||||
outputNZDiff = new T[vNZDiff.size()];
|
||||
memcpy(outputNZDiff, vNZDiff.data(), vNZDiff.size() * sizeof(T));
|
||||
|
||||
|
|
@ -321,7 +311,7 @@ inline size_t NZDiff(ComponentType compType, void *data, void *dataBase, size_t
|
|||
}
|
||||
|
||||
inline Ref<Accessor> ExportDataSparse(Asset &a, std::string &meshName, Ref<Buffer> &buffer,
|
||||
size_t count, void *data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, BufferViewTarget target = BufferViewTarget_NONE, void *dataBase = 0) {
|
||||
size_t count, void *data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, BufferViewTarget target = BufferViewTarget_NONE, void *dataBase = nullptr) {
|
||||
if (!count || !data) {
|
||||
return Ref<Accessor>();
|
||||
}
|
||||
|
|
@ -356,12 +346,12 @@ inline Ref<Accessor> ExportDataSparse(Asset &a, std::string &meshName, Ref<Buffe
|
|||
acc->type = typeOut;
|
||||
|
||||
if (data) {
|
||||
void *nzDiff = 0, *nzIdx = 0;
|
||||
void *nzDiff = nullptr, *nzIdx = nullptr;
|
||||
size_t nzCount = NZDiff(compType, data, dataBase, count, numCompsIn, numCompsOut, nzDiff, nzIdx);
|
||||
acc->sparse.reset(new Accessor::Sparse);
|
||||
acc->sparse->count = nzCount;
|
||||
|
||||
//indices
|
||||
// indices
|
||||
unsigned int bytesPerIdx = sizeof(unsigned short);
|
||||
size_t indices_offset = buffer->byteLength;
|
||||
size_t indices_padding = indices_offset % bytesPerIdx;
|
||||
|
|
@ -379,7 +369,7 @@ inline Ref<Accessor> ExportDataSparse(Asset &a, std::string &meshName, Ref<Buffe
|
|||
acc->sparse->indicesByteOffset = 0;
|
||||
acc->WriteSparseIndices(nzCount, nzIdx, 1 * bytesPerIdx);
|
||||
|
||||
//values
|
||||
// values
|
||||
size_t values_offset = buffer->byteLength;
|
||||
size_t values_padding = values_offset % bytesPerComp;
|
||||
values_offset += values_padding;
|
||||
|
|
@ -395,9 +385,9 @@ inline Ref<Accessor> ExportDataSparse(Asset &a, std::string &meshName, Ref<Buffe
|
|||
acc->sparse->valuesByteOffset = 0;
|
||||
acc->WriteSparseValues(nzCount, nzDiff, numCompsIn * bytesPerComp);
|
||||
|
||||
//clear
|
||||
delete[](char *) nzDiff;
|
||||
delete[](char *) nzIdx;
|
||||
// clear
|
||||
delete[] (char *)nzDiff;
|
||||
delete[] (char *)nzIdx;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
|
@ -443,6 +433,61 @@ inline Ref<Accessor> ExportData(Asset &a, std::string &meshName, Ref<Buffer> &bu
|
|||
return acc;
|
||||
}
|
||||
|
||||
inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, CustomExtension &value) {
|
||||
|
||||
value.name = name.C_Str();
|
||||
switch (metadataEntry.mType) {
|
||||
case AI_BOOL:
|
||||
value.mBoolValue.value = *static_cast<bool *>(metadataEntry.mData);
|
||||
value.mBoolValue.isPresent = true;
|
||||
break;
|
||||
case AI_INT32:
|
||||
value.mInt64Value.value = *static_cast<int32_t *>(metadataEntry.mData);
|
||||
value.mInt64Value.isPresent = true;
|
||||
break;
|
||||
case AI_UINT64:
|
||||
value.mUint64Value.value = *static_cast<uint64_t *>(metadataEntry.mData);
|
||||
value.mUint64Value.isPresent = true;
|
||||
break;
|
||||
case AI_FLOAT:
|
||||
value.mDoubleValue.value = *static_cast<float *>(metadataEntry.mData);
|
||||
value.mDoubleValue.isPresent = true;
|
||||
break;
|
||||
case AI_DOUBLE:
|
||||
value.mDoubleValue.value = *static_cast<double *>(metadataEntry.mData);
|
||||
value.mDoubleValue.isPresent = true;
|
||||
break;
|
||||
case AI_AISTRING:
|
||||
value.mStringValue.value = static_cast<aiString *>(metadataEntry.mData)->C_Str();
|
||||
value.mStringValue.isPresent = true;
|
||||
break;
|
||||
case AI_AIMETADATA: {
|
||||
const aiMetadata *subMetadata = static_cast<aiMetadata *>(metadataEntry.mData);
|
||||
value.mValues.value.resize(subMetadata->mNumProperties);
|
||||
value.mValues.isPresent = true;
|
||||
|
||||
for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) {
|
||||
ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mValues.value.at(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// AI_AIVECTOR3D not handled
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) {
|
||||
if (metadata == nullptr || metadata->mNumProperties == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
extras.mValues.resize(metadata->mNumProperties);
|
||||
for (unsigned int i = 0; i < metadata->mNumProperties; ++i) {
|
||||
ExportNodeExtras(metadata->mValues[i], metadata->mKeys[i], extras.mValues.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
inline void SetSamplerWrap(SamplerWrap &wrap, aiTextureMapMode map) {
|
||||
switch (map) {
|
||||
case aiTextureMapMode_Clamp:
|
||||
|
|
@ -516,11 +561,15 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
|
|||
if (mat.GetTextureCount(tt) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
aiString tex;
|
||||
|
||||
// Read texcoord (UV map index)
|
||||
mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord);
|
||||
// Note: must be an int to be successful.
|
||||
int tmp = 0;
|
||||
const auto ok = mat.Get(AI_MATKEY_UVWSRC(tt, slot), tmp);
|
||||
if (ok == aiReturn_SUCCESS) texCoord = tmp;
|
||||
|
||||
|
||||
if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
|
||||
std::string path = tex.C_Str();
|
||||
|
|
@ -544,7 +593,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
|
|||
if (curTex != nullptr) { // embedded
|
||||
texture->source->name = curTex->mFilename.C_Str();
|
||||
|
||||
//basisu: embedded ktx2, bu
|
||||
// basisu: embedded ktx2, bu
|
||||
if (curTex->achFormatHint[0]) {
|
||||
std::string mimeType = "image/";
|
||||
if (memcmp(curTex->achFormatHint, "jpg", 3) == 0)
|
||||
|
|
@ -564,7 +613,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
|
|||
}
|
||||
|
||||
// The asset has its own buffer, see Image::SetData
|
||||
//basisu: "image/ktx2", "image/basis" as is
|
||||
// basisu: "image/ktx2", "image/basis" as is
|
||||
texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
|
||||
} else {
|
||||
texture->source->uri = path;
|
||||
|
|
@ -574,7 +623,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
|
|||
}
|
||||
}
|
||||
|
||||
//basisu
|
||||
// basisu
|
||||
if (useBasisUniversal) {
|
||||
mAsset->extensionsUsed.KHR_texture_basisu = true;
|
||||
mAsset->extensionsRequired.KHR_texture_basisu = true;
|
||||
|
|
@ -597,7 +646,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, NormalTextureInfo &prop, ai
|
|||
GetMatTex(mat, texture, prop.texCoord, tt, slot);
|
||||
|
||||
if (texture) {
|
||||
//GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
|
||||
// GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
|
||||
GetMatTexProp(mat, prop.scale, "scale", tt, slot);
|
||||
}
|
||||
}
|
||||
|
|
@ -608,7 +657,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, OcclusionTextureInfo &prop,
|
|||
GetMatTex(mat, texture, prop.texCoord, tt, slot);
|
||||
|
||||
if (texture) {
|
||||
//GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
|
||||
// GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
|
||||
GetMatTexProp(mat, prop.strength, "strength", tt, slot);
|
||||
}
|
||||
}
|
||||
|
|
@ -640,11 +689,10 @@ aiReturn glTF2Exporter::GetMatColor(const aiMaterial &mat, vec3 &prop, const cha
|
|||
return result;
|
||||
}
|
||||
|
||||
// This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default.
|
||||
bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG) {
|
||||
bool result = false;
|
||||
// If has Glossiness, a Specular Color or Specular Texture, use the KHR_materials_pbrSpecularGlossiness extension
|
||||
// NOTE: This extension is being considered for deprecation (Dec 2020), may be replaced by KHR_material_specular
|
||||
|
||||
if (mat.Get(AI_MATKEY_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) == AI_SUCCESS) {
|
||||
result = true;
|
||||
} else {
|
||||
|
|
@ -674,6 +722,25 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
|
|||
return result;
|
||||
}
|
||||
|
||||
bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) {
|
||||
// Specular requires either/or, default factors of zero disables specular, so do not export
|
||||
if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS && mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
// The spec states that the default is 1.0 and [1.0, 1.0, 1.0]. We if both are 0, which should disable specular. Otherwise, if one is 0, set to 1.0
|
||||
const bool colorFactorIsZero = specular.specularColorFactor[0] == defaultSpecularColorFactor[0] && specular.specularColorFactor[1] == defaultSpecularColorFactor[1] && specular.specularColorFactor[2] == defaultSpecularColorFactor[2];
|
||||
if (specular.specularFactor == 0.0f && colorFactorIsZero) {
|
||||
return false;
|
||||
} else if (specular.specularFactor == 0.0f) {
|
||||
specular.specularFactor = 1.0f;
|
||||
} else if (colorFactorIsZero) {
|
||||
specular.specularColorFactor[0] = specular.specularColorFactor[1] = specular.specularColorFactor[2] = 1.0f;
|
||||
}
|
||||
GetMatTex(mat, specular.specularTexture, aiTextureType_SPECULAR, 0);
|
||||
GetMatTex(mat, specular.specularColorTexture, aiTextureType_SPECULAR, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
|
@ -733,6 +800,10 @@ bool glTF2Exporter::GetMatIOR(const aiMaterial &mat, glTF2::MaterialIOR &ior) {
|
|||
return mat.Get(AI_MATKEY_REFRACTI, ior.ior) == aiReturn_SUCCESS;
|
||||
}
|
||||
|
||||
bool glTF2Exporter::GetMatEmissiveStrength(const aiMaterial &mat, glTF2::MaterialEmissiveStrength &emissiveStrength) {
|
||||
return mat.Get(AI_MATKEY_EMISSIVE_INTENSITY, emissiveStrength.emissiveStrength) == aiReturn_SUCCESS;
|
||||
}
|
||||
|
||||
void glTF2Exporter::ExportMaterials() {
|
||||
aiString aiName;
|
||||
for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
|
||||
|
|
@ -755,20 +826,30 @@ void glTF2Exporter::ExportMaterials() {
|
|||
GetMatTex(mat, m->pbrMetallicRoughness.baseColorTexture, aiTextureType_BASE_COLOR);
|
||||
|
||||
if (!m->pbrMetallicRoughness.baseColorTexture.texture) {
|
||||
//if there wasn't a baseColorTexture defined in the source, fallback to any diffuse texture
|
||||
// if there wasn't a baseColorTexture defined in the source, fallback to any diffuse texture
|
||||
GetMatTex(mat, m->pbrMetallicRoughness.baseColorTexture, aiTextureType_DIFFUSE);
|
||||
}
|
||||
|
||||
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
|
||||
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, aiTextureType_DIFFUSE_ROUGHNESS);
|
||||
|
||||
if (!m->pbrMetallicRoughness.metallicRoughnessTexture.texture) {
|
||||
// if there wasn't a aiTextureType_DIFFUSE_ROUGHNESS defined in the source, fallback to aiTextureType_METALNESS
|
||||
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, aiTextureType_METALNESS);
|
||||
}
|
||||
|
||||
if (!m->pbrMetallicRoughness.metallicRoughnessTexture.texture) {
|
||||
// if there still wasn't a aiTextureType_METALNESS defined in the source, fallback to AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE
|
||||
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
|
||||
}
|
||||
|
||||
if (GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_BASE_COLOR) != AI_SUCCESS) {
|
||||
// if baseColorFactor wasn't defined, then the source is likely not a metallic roughness material.
|
||||
//a fallback to any diffuse color should be used instead
|
||||
// a fallback to any diffuse color should be used instead
|
||||
GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE);
|
||||
}
|
||||
|
||||
if (mat.Get(AI_MATKEY_METALLIC_FACTOR, m->pbrMetallicRoughness.metallicFactor) != AI_SUCCESS) {
|
||||
//if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0
|
||||
// if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0
|
||||
m->pbrMetallicRoughness.metallicFactor = 0;
|
||||
}
|
||||
|
||||
|
|
@ -781,10 +862,10 @@ void glTF2Exporter::ExportMaterials() {
|
|||
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
|
||||
// normalize shininess (assuming max is 1000) with an inverse exponentional curve
|
||||
float normalizedShininess = std::sqrt(shininess / 1000);
|
||||
|
||||
//clamp the shininess value between 0 and 1
|
||||
// clamp the shininess value between 0 and 1
|
||||
normalizedShininess = std::min(std::max(normalizedShininess, 0.0f), 1.0f);
|
||||
// low specular intensity values should produce a rough material even if shininess is high.
|
||||
normalizedShininess = normalizedShininess * specularIntensity;
|
||||
|
|
@ -814,9 +895,9 @@ void glTF2Exporter::ExportMaterials() {
|
|||
m->alphaMode = alphaMode.C_Str();
|
||||
}
|
||||
|
||||
{
|
||||
// This extension has been deprecated, only export with the specific flag enabled, defaults to false. Uses KHR_material_specular default.
|
||||
if (mProperties->GetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS)) {
|
||||
// KHR_materials_pbrSpecularGlossiness extension
|
||||
// NOTE: This extension is being considered for deprecation (Dec 2020)
|
||||
PbrSpecularGlossiness pbrSG;
|
||||
if (GetMatSpecGloss(mat, pbrSG)) {
|
||||
mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true;
|
||||
|
|
@ -833,7 +914,13 @@ void glTF2Exporter::ExportMaterials() {
|
|||
} else {
|
||||
// These extensions are not compatible with KHR_materials_unlit or KHR_materials_pbrSpecularGlossiness
|
||||
if (!m->pbrSpecularGlossiness.isPresent) {
|
||||
// Sheen
|
||||
MaterialSpecular specular;
|
||||
if (GetMatSpecular(mat, specular)) {
|
||||
mAsset->extensionsUsed.KHR_materials_specular = true;
|
||||
m->materialSpecular = Nullable<MaterialSpecular>(specular);
|
||||
GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE);
|
||||
}
|
||||
|
||||
MaterialSheen sheen;
|
||||
if (GetMatSheen(mat, sheen)) {
|
||||
mAsset->extensionsUsed.KHR_materials_sheen = true;
|
||||
|
|
@ -851,18 +938,24 @@ void glTF2Exporter::ExportMaterials() {
|
|||
mAsset->extensionsUsed.KHR_materials_transmission = true;
|
||||
m->materialTransmission = Nullable<MaterialTransmission>(transmission);
|
||||
}
|
||||
|
||||
|
||||
MaterialVolume volume;
|
||||
if (GetMatVolume(mat, volume)) {
|
||||
mAsset->extensionsUsed.KHR_materials_volume = true;
|
||||
m->materialVolume = Nullable<MaterialVolume>(volume);
|
||||
}
|
||||
|
||||
|
||||
MaterialIOR ior;
|
||||
if (GetMatIOR(mat, ior)) {
|
||||
mAsset->extensionsUsed.KHR_materials_ior = true;
|
||||
m->materialIOR = Nullable<MaterialIOR>(ior);
|
||||
}
|
||||
|
||||
MaterialEmissiveStrength emissiveStrength;
|
||||
if (GetMatEmissiveStrength(mat, emissiveStrength)) {
|
||||
mAsset->extensionsUsed.KHR_materials_emissive_strength = true;
|
||||
m->materialEmissiveStrength = Nullable<MaterialEmissiveStrength>(emissiveStrength);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -911,23 +1004,29 @@ 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) {
|
||||
struct boneIndexWeightPair {
|
||||
unsigned int indexJoint;
|
||||
float weight;
|
||||
bool operator()(boneIndexWeightPair &a, boneIndexWeightPair &b) {
|
||||
return a.weight > b.weight;
|
||||
}
|
||||
};
|
||||
|
||||
void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buffer> &bufferRef, Ref<Skin> &skinRef,
|
||||
std::vector<aiMatrix4x4> &inverseBindMatricesData, bool unlimitedBonesPerVertex) {
|
||||
if (aimesh->mNumBones < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the vertex joint and weight data.
|
||||
const size_t NumVerts(aimesh->mNumVertices);
|
||||
vec4 *vertexJointData = new vec4[NumVerts];
|
||||
vec4 *vertexWeightData = new vec4[NumVerts];
|
||||
int *jointsPerVertex = new int[NumVerts];
|
||||
std::vector<std::vector<boneIndexWeightPair>> allVerticesPairs;
|
||||
int maxJointsPerVertex = 0;
|
||||
for (size_t i = 0; i < NumVerts; ++i) {
|
||||
jointsPerVertex[i] = 0;
|
||||
for (size_t j = 0; j < 4; ++j) {
|
||||
vertexJointData[i][j] = 0;
|
||||
vertexWeightData[i][j] = 0;
|
||||
}
|
||||
std::vector<boneIndexWeightPair> vertexPair;
|
||||
allVerticesPairs.push_back(vertexPair);
|
||||
}
|
||||
|
||||
for (unsigned int idx_bone = 0; idx_bone < aimesh->mNumBones; ++idx_bone) {
|
||||
|
|
@ -957,61 +1056,88 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buf
|
|||
jointNamesIndex = static_cast<unsigned int>(inverseBindMatricesData.size() - 1);
|
||||
}
|
||||
|
||||
// aib->mWeights =====> vertexWeightData
|
||||
for (unsigned int idx_weights = 0; idx_weights < aib->mNumWeights; ++idx_weights) {
|
||||
// aib->mWeights =====> temp pairs data
|
||||
for (unsigned int idx_weights = 0; idx_weights < aib->mNumWeights;
|
||||
++idx_weights) {
|
||||
unsigned int vertexId = aib->mWeights[idx_weights].mVertexId;
|
||||
float vertWeight = aib->mWeights[idx_weights].mWeight;
|
||||
|
||||
// A vertex can only have at most four joint weights, which ideally sum up to 1
|
||||
if (IsBoneWeightFitted(vertexWeightData[vertexId])) {
|
||||
continue;
|
||||
}
|
||||
if (jointsPerVertex[vertexId] > 3) {
|
||||
int boneIndexFitted = FitBoneWeight(vertexWeightData[vertexId], vertWeight);
|
||||
if (boneIndexFitted != -1) {
|
||||
vertexJointData[vertexId][boneIndexFitted] = static_cast<float>(jointNamesIndex);
|
||||
}
|
||||
}else {
|
||||
vertexJointData[vertexId][jointsPerVertex[vertexId]] = static_cast<float>(jointNamesIndex);
|
||||
vertexWeightData[vertexId][jointsPerVertex[vertexId]] = vertWeight;
|
||||
|
||||
jointsPerVertex[vertexId] += 1;
|
||||
}
|
||||
allVerticesPairs[vertexId].push_back({jointNamesIndex, vertWeight});
|
||||
jointsPerVertex[vertexId] += 1;
|
||||
maxJointsPerVertex =
|
||||
std::max(maxJointsPerVertex, jointsPerVertex[vertexId]);
|
||||
}
|
||||
|
||||
} // 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);
|
||||
if (vertexJointAccessor) {
|
||||
size_t offset = vertexJointAccessor->bufferView->byteOffset;
|
||||
size_t bytesLen = vertexJointAccessor->bufferView->byteLength;
|
||||
unsigned int s_bytesPerComp = ComponentTypeSize(ComponentType_UNSIGNED_SHORT);
|
||||
unsigned int bytesPerComp = ComponentTypeSize(vertexJointAccessor->componentType);
|
||||
size_t s_bytesLen = bytesLen * s_bytesPerComp / bytesPerComp;
|
||||
Ref<Buffer> buf = vertexJointAccessor->bufferView->buffer;
|
||||
uint8_t *arrys = new uint8_t[bytesLen];
|
||||
unsigned int i = 0;
|
||||
for (unsigned int j = 0; j < bytesLen; j += bytesPerComp) {
|
||||
size_t len_p = offset + j;
|
||||
float f_value = *(float *)&buf->GetPointer()[len_p];
|
||||
unsigned short c = static_cast<unsigned short>(f_value);
|
||||
memcpy(&arrys[i * s_bytesPerComp], &c, s_bytesPerComp);
|
||||
++i;
|
||||
}
|
||||
buf->ReplaceData_joint(offset, bytesLen, arrys, bytesLen);
|
||||
vertexJointAccessor->componentType = ComponentType_UNSIGNED_SHORT;
|
||||
vertexJointAccessor->bufferView->byteLength = s_bytesLen;
|
||||
|
||||
p.attributes.joint.push_back(vertexJointAccessor);
|
||||
delete[] arrys;
|
||||
if (!unlimitedBonesPerVertex){
|
||||
// skinning limited only for 4 bones per vertex, default
|
||||
maxJointsPerVertex = 4;
|
||||
}
|
||||
|
||||
Ref<Accessor> vertexWeightAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices,
|
||||
vertexWeightData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||
if (vertexWeightAccessor) {
|
||||
p.attributes.weight.push_back(vertexWeightAccessor);
|
||||
// temp pairs data =====> vertexWeightData
|
||||
size_t numGroups = (maxJointsPerVertex - 1) / 4 + 1;
|
||||
vec4 *vertexJointData = new vec4[NumVerts * numGroups];
|
||||
vec4 *vertexWeightData = new vec4[NumVerts * numGroups];
|
||||
for (size_t indexVertex = 0; indexVertex < NumVerts; ++indexVertex) {
|
||||
// order pairs by weight for each vertex
|
||||
std::sort(allVerticesPairs[indexVertex].begin(),
|
||||
allVerticesPairs[indexVertex].end(),
|
||||
boneIndexWeightPair());
|
||||
for (size_t indexGroup = 0; indexGroup < numGroups; ++indexGroup) {
|
||||
for (size_t indexJoint = 0; indexJoint < 4; ++indexJoint) {
|
||||
size_t indexBone = indexGroup * 4 + indexJoint;
|
||||
size_t indexData = indexVertex + NumVerts * indexGroup;
|
||||
if (indexBone >= allVerticesPairs[indexVertex].size()) {
|
||||
vertexJointData[indexData][indexJoint] = 0.f;
|
||||
vertexWeightData[indexData][indexJoint] = 0.f;
|
||||
} else {
|
||||
vertexJointData[indexData][indexJoint] =
|
||||
static_cast<float>(
|
||||
allVerticesPairs[indexVertex][indexBone].indexJoint);
|
||||
vertexWeightData[indexData][indexJoint] =
|
||||
allVerticesPairs[indexVertex][indexBone].weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t idx_group = 0; idx_group < numGroups; ++idx_group) {
|
||||
Mesh::Primitive &p = meshRef->primitives.back();
|
||||
Ref<Accessor> vertexJointAccessor = ExportData(
|
||||
mAsset, skinRef->id, bufferRef, aimesh->mNumVertices,
|
||||
vertexJointData + idx_group * NumVerts,
|
||||
AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||
if (vertexJointAccessor) {
|
||||
size_t offset = vertexJointAccessor->bufferView->byteOffset;
|
||||
size_t bytesLen = vertexJointAccessor->bufferView->byteLength;
|
||||
unsigned int s_bytesPerComp =
|
||||
ComponentTypeSize(ComponentType_UNSIGNED_SHORT);
|
||||
unsigned int bytesPerComp =
|
||||
ComponentTypeSize(vertexJointAccessor->componentType);
|
||||
size_t s_bytesLen = bytesLen * s_bytesPerComp / bytesPerComp;
|
||||
Ref<Buffer> buf = vertexJointAccessor->bufferView->buffer;
|
||||
uint8_t *arrys = new uint8_t[bytesLen];
|
||||
unsigned int i = 0;
|
||||
for (unsigned int j = 0; j < bytesLen; j += bytesPerComp) {
|
||||
size_t len_p = offset + j;
|
||||
float f_value = *(float *)&buf->GetPointer()[len_p];
|
||||
unsigned short c = static_cast<unsigned short>(f_value);
|
||||
memcpy(&arrys[i * s_bytesPerComp], &c, s_bytesPerComp);
|
||||
++i;
|
||||
}
|
||||
buf->ReplaceData_joint(offset, bytesLen, arrys, bytesLen);
|
||||
vertexJointAccessor->componentType = ComponentType_UNSIGNED_SHORT;
|
||||
vertexJointAccessor->bufferView->byteLength = s_bytesLen;
|
||||
|
||||
p.attributes.joint.push_back(vertexJointAccessor);
|
||||
delete[] arrys;
|
||||
}
|
||||
Ref<Accessor> vertexWeightAccessor = ExportData(
|
||||
mAsset, skinRef->id, bufferRef, aimesh->mNumVertices,
|
||||
vertexWeightData + idx_group * NumVerts,
|
||||
AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||
if (vertexWeightAccessor) {
|
||||
p.attributes.weight.push_back(vertexWeightAccessor);
|
||||
}
|
||||
}
|
||||
delete[] jointsPerVertex;
|
||||
delete[] vertexWeightData;
|
||||
|
|
@ -1052,6 +1178,9 @@ void glTF2Exporter::ExportMeshes() {
|
|||
|
||||
for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
|
||||
const aiMesh *aim = mScene->mMeshes[idx_mesh];
|
||||
if (aim->mNumFaces == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name = aim->mName.C_Str();
|
||||
|
||||
|
|
@ -1067,7 +1196,7 @@ void glTF2Exporter::ExportMeshes() {
|
|||
|
||||
/******************* Vertices ********************/
|
||||
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3,
|
||||
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (v) {
|
||||
p.attributes.position.push_back(v);
|
||||
}
|
||||
|
|
@ -1080,8 +1209,8 @@ void glTF2Exporter::ExportMeshes() {
|
|||
}
|
||||
}
|
||||
|
||||
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3,
|
||||
AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
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);
|
||||
}
|
||||
|
|
@ -1102,8 +1231,8 @@ 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);
|
||||
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);
|
||||
}
|
||||
|
|
@ -1113,7 +1242,7 @@ void glTF2Exporter::ExportMeshes() {
|
|||
/*************** 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);
|
||||
AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
|
||||
if (c) {
|
||||
p.attributes.color.push_back(c);
|
||||
}
|
||||
|
|
@ -1130,8 +1259,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) {
|
||||
|
|
@ -1149,9 +1278,19 @@ void glTF2Exporter::ExportMeshes() {
|
|||
break;
|
||||
}
|
||||
|
||||
// /*************** Skins ****************/
|
||||
// if (aim->HasBones()) {
|
||||
// ExportSkin(*mAsset, aim, m, b, skinRef, inverseBindMatricesData);
|
||||
// }
|
||||
/*************** Skins ****************/
|
||||
if (aim->HasBones()) {
|
||||
ExportSkin(*mAsset, aim, m, b, skinRef, inverseBindMatricesData);
|
||||
bool unlimitedBonesPerVertex =
|
||||
this->mProperties->HasPropertyBool(
|
||||
AI_CONFIG_EXPORT_GLTF_UNLIMITED_SKINNING_BONES_PER_VERTEX) &&
|
||||
this->mProperties->GetPropertyBool(
|
||||
AI_CONFIG_EXPORT_GLTF_UNLIMITED_SKINNING_BONES_PER_VERTEX);
|
||||
ExportSkin(*mAsset, aim, m, b, skinRef, inverseBindMatricesData,
|
||||
unlimitedBonesPerVertex);
|
||||
}
|
||||
|
||||
/*************** Targets for blendshapes ****************/
|
||||
|
|
@ -1274,24 +1413,24 @@ void glTF2Exporter::MergeMeshes() {
|
|||
|
||||
unsigned int nMeshes = static_cast<unsigned int>(node->meshes.size());
|
||||
|
||||
//skip if it's 1 or less meshes per node
|
||||
// skip if it's 1 or less meshes per node
|
||||
if (nMeshes > 1) {
|
||||
Ref<Mesh> firstMesh = node->meshes.at(0);
|
||||
|
||||
//loop backwards to allow easy removal of a mesh from a node once it's merged
|
||||
// loop backwards to allow easy removal of a mesh from a node once it's merged
|
||||
for (unsigned int m = nMeshes - 1; m >= 1; --m) {
|
||||
Ref<Mesh> mesh = node->meshes.at(m);
|
||||
|
||||
//append this mesh's primitives to the first mesh's primitives
|
||||
// append this mesh's primitives to the first mesh's primitives
|
||||
firstMesh->primitives.insert(
|
||||
firstMesh->primitives.end(),
|
||||
mesh->primitives.begin(),
|
||||
mesh->primitives.end());
|
||||
|
||||
//remove the mesh from the list of meshes
|
||||
// remove the mesh from the list of meshes
|
||||
unsigned int removedIndex = mAsset->meshes.Remove(mesh->id.c_str());
|
||||
|
||||
//find the presence of the removed mesh in other nodes
|
||||
// find the presence of the removed mesh in other nodes
|
||||
for (unsigned int nn = 0; nn < mAsset->nodes.Size(); ++nn) {
|
||||
Ref<Node> curNode = mAsset->nodes.Get(nn);
|
||||
|
||||
|
|
@ -1310,7 +1449,7 @@ void glTF2Exporter::MergeMeshes() {
|
|||
}
|
||||
}
|
||||
|
||||
//since we were looping backwards, reverse the order of merged primitives to their original order
|
||||
// since we were looping backwards, reverse the order of merged primitives to their original order
|
||||
std::reverse(firstMesh->primitives.begin() + 1, firstMesh->primitives.end());
|
||||
}
|
||||
}
|
||||
|
|
@ -1325,7 +1464,7 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) {
|
|||
|
||||
node->name = n->mName.C_Str();
|
||||
|
||||
if (!n->mTransformation.IsIdentity()) {
|
||||
if (!n->mTransformation.IsIdentity(configEpsilon)) {
|
||||
node->matrix.isPresent = true;
|
||||
CopyValue(n->mTransformation, node->matrix.value);
|
||||
}
|
||||
|
|
@ -1353,7 +1492,9 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref<Node> &parent) {
|
|||
node->parent = parent;
|
||||
node->name = name;
|
||||
|
||||
if (!n->mTransformation.IsIdentity()) {
|
||||
ExportNodeExtras(n->mMetaData, node->extras);
|
||||
|
||||
if (!n->mTransformation.IsIdentity(configEpsilon)) {
|
||||
if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) {
|
||||
aiQuaternion quaternion;
|
||||
n->mTransformation.Decompose(*reinterpret_cast<aiVector3D *>(&node->scale.value), quaternion, *reinterpret_cast<aiVector3D *>(&node->translation.value));
|
||||
|
|
@ -1435,9 +1576,9 @@ inline void ExtractTranslationSampler(Asset &asset, std::string &animId, Ref<Buf
|
|||
const aiVectorKey &key = nodeChannel->mPositionKeys[i];
|
||||
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
|
||||
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
|
||||
values[(i * 3) + 0] = (ai_real) key.mValue.x;
|
||||
values[(i * 3) + 1] = (ai_real) key.mValue.y;
|
||||
values[(i * 3) + 2] = (ai_real) key.mValue.z;
|
||||
values[(i * 3) + 0] = (ai_real)key.mValue.x;
|
||||
values[(i * 3) + 1] = (ai_real)key.mValue.y;
|
||||
values[(i * 3) + 2] = (ai_real)key.mValue.z;
|
||||
}
|
||||
|
||||
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
|
||||
|
|
@ -1454,9 +1595,9 @@ inline void ExtractScaleSampler(Asset &asset, std::string &animId, Ref<Buffer> &
|
|||
const aiVectorKey &key = nodeChannel->mScalingKeys[i];
|
||||
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
|
||||
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
|
||||
values[(i * 3) + 0] = (ai_real) key.mValue.x;
|
||||
values[(i * 3) + 1] = (ai_real) key.mValue.y;
|
||||
values[(i * 3) + 2] = (ai_real) key.mValue.z;
|
||||
values[(i * 3) + 0] = (ai_real)key.mValue.x;
|
||||
values[(i * 3) + 1] = (ai_real)key.mValue.y;
|
||||
values[(i * 3) + 2] = (ai_real)key.mValue.z;
|
||||
}
|
||||
|
||||
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
|
||||
|
|
@ -1473,10 +1614,10 @@ inline void ExtractRotationSampler(Asset &asset, std::string &animId, Ref<Buffer
|
|||
const aiQuatKey &key = nodeChannel->mRotationKeys[i];
|
||||
// mTime is measured in ticks, but GLTF time is measured in seconds, so convert.
|
||||
times[i] = static_cast<float>(key.mTime / ticksPerSecond);
|
||||
values[(i * 4) + 0] = (ai_real) key.mValue.x;
|
||||
values[(i * 4) + 1] = (ai_real) key.mValue.y;
|
||||
values[(i * 4) + 2] = (ai_real) key.mValue.z;
|
||||
values[(i * 4) + 3] = (ai_real) key.mValue.w;
|
||||
values[(i * 4) + 0] = (ai_real)key.mValue.x;
|
||||
values[(i * 4) + 1] = (ai_real)key.mValue.y;
|
||||
values[(i * 4) + 2] = (ai_real)key.mValue.z;
|
||||
values[(i * 4) + 3] = (ai_real)key.mValue.w;
|
||||
}
|
||||
|
||||
sampler.input = GetSamplerInputRef(asset, animId, buffer, times);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
Copyright (c) 2006-2024, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/defs.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
|
@ -76,11 +77,13 @@ struct OcclusionTextureInfo;
|
|||
struct Node;
|
||||
struct Texture;
|
||||
struct PbrSpecularGlossiness;
|
||||
struct MaterialSpecular;
|
||||
struct MaterialSheen;
|
||||
struct MaterialClearcoat;
|
||||
struct MaterialTransmission;
|
||||
struct MaterialVolume;
|
||||
struct MaterialIOR;
|
||||
struct MaterialEmissiveStrength;
|
||||
|
||||
// Vec/matrix types, as raw float arrays
|
||||
typedef float(vec2)[2];
|
||||
|
|
@ -116,11 +119,13 @@ protected:
|
|||
aiReturn GetMatColor(const aiMaterial &mat, glTF2::vec4 &prop, const char *propName, int type, int idx) const;
|
||||
aiReturn GetMatColor(const aiMaterial &mat, glTF2::vec3 &prop, const char *propName, int type, int idx) const;
|
||||
bool GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG);
|
||||
bool GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular);
|
||||
bool GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen);
|
||||
bool GetMatClearcoat(const aiMaterial &mat, glTF2::MaterialClearcoat &clearcoat);
|
||||
bool GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTransmission &transmission);
|
||||
bool GetMatVolume(const aiMaterial &mat, glTF2::MaterialVolume &volume);
|
||||
bool GetMatIOR(const aiMaterial &mat, glTF2::MaterialIOR &ior);
|
||||
bool GetMatEmissiveStrength(const aiMaterial &mat, glTF2::MaterialEmissiveStrength &emissiveStrength);
|
||||
void ExportMetadata();
|
||||
void ExportMaterials();
|
||||
void ExportMeshes();
|
||||
|
|
@ -138,6 +143,7 @@ private:
|
|||
std::map<std::string, unsigned int> mTexturesByPath;
|
||||
std::shared_ptr<glTF2::Asset> mAsset;
|
||||
std::vector<unsigned char> mBodyData;
|
||||
ai_real configEpsilon;
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
Copyright (c) 2006-2024, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ struct Tangent {
|
|||
// glTF2Importer
|
||||
//
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
static constexpr aiImporterDesc desc = {
|
||||
"glTF2 Importer",
|
||||
"",
|
||||
"",
|
||||
|
|
@ -92,32 +92,31 @@ static const aiImporterDesc desc = {
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
"gltf glb"
|
||||
"gltf glb vrm"
|
||||
};
|
||||
|
||||
glTF2Importer::glTF2Importer() :
|
||||
BaseImporter(),
|
||||
meshOffsets(),
|
||||
mEmbeddedTexIdxs(),
|
||||
mScene(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
glTF2Importer::~glTF2Importer() = default;
|
||||
|
||||
const aiImporterDesc *glTF2Importer::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string extension = GetExtension(filename);
|
||||
if (!checkSig && (extension != "gltf") && (extension != "glb")) {
|
||||
if (!checkSig && (extension != "gltf") && (extension != "glb") && (extension != "vrm")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pIOHandler) {
|
||||
glTF2::Asset asset(pIOHandler);
|
||||
return asset.CanRead(filename, extension == "glb");
|
||||
return asset.CanRead(
|
||||
filename,
|
||||
CheckMagicToken(
|
||||
pIOHandler, filename, AI_GLB_MAGIC_NUMBER, 1, 0,
|
||||
static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -162,7 +161,7 @@ static void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
|
|||
if (texIdx != -1) { // embedded
|
||||
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||
uri.data[0] = '*';
|
||||
uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
|
||||
uri.length = 1 + ASSIMP_itoa10(uri.data + 1, AI_MAXLEN - 1, texIdx);
|
||||
}
|
||||
|
||||
mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot));
|
||||
|
|
@ -185,7 +184,6 @@ static void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
|
|||
const ai_real rsin(sin(-transform.mRotation));
|
||||
transform.mTranslation.x = (static_cast<ai_real>(0.5) * transform.mScaling.x) * (-rcos + rsin + 1) + prop.TextureTransformExt_t.offset[0];
|
||||
transform.mTranslation.y = ((static_cast<ai_real>(0.5) * transform.mScaling.y) * (rsin + rcos - 1)) + 1 - transform.mScaling.y - prop.TextureTransformExt_t.offset[1];
|
||||
;
|
||||
|
||||
mat->AddProperty(&transform, 1, _AI_MATKEY_UVTRANSFORM_BASE, texType, texSlot);
|
||||
}
|
||||
|
|
@ -236,7 +234,8 @@ inline void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
|
|||
SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot);
|
||||
|
||||
if (prop.texture && prop.texture->source) {
|
||||
mat->AddProperty(&prop.strength, 1, AI_MATKEY_GLTF_TEXTURE_STRENGTH(texType, texSlot));
|
||||
std::string textureStrengthKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + "strength";
|
||||
mat->AddProperty(&prop.strength, 1, textureStrengthKey.c_str(), texType, texSlot);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -282,8 +281,19 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
|
|||
aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE);
|
||||
aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF);
|
||||
|
||||
// KHR_materials_specular
|
||||
if (mat.materialSpecular.isPresent) {
|
||||
MaterialSpecular &specular = mat.materialSpecular.value;
|
||||
// Default values of zero disables Specular
|
||||
if (std::memcmp(specular.specularColorFactor, defaultSpecularColorFactor, sizeof(glTFCommon::vec3)) != 0 || specular.specularFactor != 0.0f) {
|
||||
SetMaterialColorProperty(r, specular.specularColorFactor, aimat, AI_MATKEY_COLOR_SPECULAR);
|
||||
aimat->AddProperty(&specular.specularFactor, 1, AI_MATKEY_SPECULAR_FACTOR);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularTexture, aimat, aiTextureType_SPECULAR, 0);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, specular.specularColorTexture, aimat, aiTextureType_SPECULAR, 1);
|
||||
}
|
||||
}
|
||||
// pbrSpecularGlossiness
|
||||
if (mat.pbrSpecularGlossiness.isPresent) {
|
||||
else if (mat.pbrSpecularGlossiness.isPresent) {
|
||||
PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
|
||||
|
||||
SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
|
||||
|
|
@ -357,6 +367,13 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
|
|||
aimat->AddProperty(&ior.ior, 1, AI_MATKEY_REFRACTI);
|
||||
}
|
||||
|
||||
// KHR_materials_emissive_strength
|
||||
if (mat.materialEmissiveStrength.isPresent) {
|
||||
MaterialEmissiveStrength &emissiveStrength = mat.materialEmissiveStrength.value;
|
||||
|
||||
aimat->AddProperty(&emissiveStrength.emissiveStrength, 1, AI_MATKEY_EMISSIVE_INTENSITY);
|
||||
}
|
||||
|
||||
return aimat;
|
||||
} catch (...) {
|
||||
delete aimat;
|
||||
|
|
@ -429,10 +446,10 @@ static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsign
|
|||
#endif // ASSIMP_BUILD_DEBUG
|
||||
|
||||
template <typename T>
|
||||
aiColor4D *GetVertexColorsForType(Ref<Accessor> input) {
|
||||
aiColor4D *GetVertexColorsForType(Ref<Accessor> input, std::vector<unsigned int> *vertexRemappingTable) {
|
||||
constexpr float max = std::numeric_limits<T>::max();
|
||||
aiColor4t<T> *colors;
|
||||
input->ExtractData(colors);
|
||||
input->ExtractData(colors, vertexRemappingTable);
|
||||
auto output = new aiColor4D[input->count];
|
||||
for (size_t i = 0; i < input->count; i++) {
|
||||
output[i] = aiColor4D(
|
||||
|
|
@ -447,18 +464,73 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
ASSIMP_LOG_DEBUG("Importing ", r.meshes.Size(), " meshes");
|
||||
std::vector<std::unique_ptr<aiMesh>> meshes;
|
||||
|
||||
unsigned int k = 0;
|
||||
meshOffsets.clear();
|
||||
meshOffsets.reserve(r.meshes.Size() + 1);
|
||||
mVertexRemappingTables.clear();
|
||||
|
||||
// Count the number of aiMeshes
|
||||
unsigned int num_aiMeshes = 0;
|
||||
for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
|
||||
meshOffsets.push_back(num_aiMeshes);
|
||||
num_aiMeshes += unsigned(r.meshes[m].primitives.size());
|
||||
}
|
||||
meshOffsets.push_back(num_aiMeshes); // add a last element so we can always do meshOffsets[n+1] - meshOffsets[n]
|
||||
|
||||
std::vector<unsigned int> reverseMappingIndices;
|
||||
std::vector<unsigned int> indexBuffer;
|
||||
meshes.reserve(num_aiMeshes);
|
||||
mVertexRemappingTables.resize(num_aiMeshes);
|
||||
|
||||
for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
|
||||
Mesh &mesh = r.meshes[m];
|
||||
|
||||
meshOffsets.push_back(k);
|
||||
k += unsigned(mesh.primitives.size());
|
||||
|
||||
for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
|
||||
Mesh::Primitive &prim = mesh.primitives[p];
|
||||
|
||||
Mesh::Primitive::Attributes &attr = prim.attributes;
|
||||
|
||||
// Find out the maximum number of vertices:
|
||||
size_t numAllVertices = 0;
|
||||
if (!attr.position.empty() && attr.position[0]) {
|
||||
numAllVertices = attr.position[0]->count;
|
||||
}
|
||||
|
||||
// Extract used vertices:
|
||||
bool useIndexBuffer = prim.indices;
|
||||
std::vector<unsigned int> *vertexRemappingTable = nullptr;
|
||||
|
||||
if (useIndexBuffer) {
|
||||
size_t count = prim.indices->count;
|
||||
indexBuffer.resize(count);
|
||||
reverseMappingIndices.clear();
|
||||
vertexRemappingTable = &mVertexRemappingTables[meshes.size()];
|
||||
vertexRemappingTable->reserve(count / 3); // this is a very rough heuristic to reduce re-allocations
|
||||
Accessor::Indexer data = prim.indices->GetIndexer();
|
||||
if (!data.IsValid()) {
|
||||
throw DeadlyImportError("GLTF: Invalid accessor without data in mesh ", getContextForErrorMessages(mesh.id, mesh.name));
|
||||
}
|
||||
|
||||
// Build the vertex remapping table and the modified index buffer (used later instead of the original one)
|
||||
// In case no index buffer is used, the original vertex arrays are being used so no remapping is required in the first place.
|
||||
const unsigned int unusedIndex = ~0u;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
unsigned int index = data.GetUInt(i);
|
||||
if (index >= numAllVertices) {
|
||||
// Out-of-range indices will be filtered out when adding the faces and then lead to a warning. At this stage, we just keep them.
|
||||
indexBuffer[i] = index;
|
||||
continue;
|
||||
}
|
||||
if (index >= reverseMappingIndices.size()) {
|
||||
reverseMappingIndices.resize(index + 1, unusedIndex);
|
||||
}
|
||||
if (reverseMappingIndices[index] == unusedIndex) {
|
||||
reverseMappingIndices[index] = static_cast<unsigned int>(vertexRemappingTable->size());
|
||||
vertexRemappingTable->push_back(index);
|
||||
}
|
||||
indexBuffer[i] = reverseMappingIndices[index];
|
||||
}
|
||||
}
|
||||
|
||||
aiMesh *aim = new aiMesh();
|
||||
meshes.push_back(std::unique_ptr<aiMesh>(aim));
|
||||
|
||||
|
|
@ -467,7 +539,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
if (mesh.primitives.size() > 1) {
|
||||
ai_uint32 &len = aim->mName.length;
|
||||
aim->mName.data[len] = '-';
|
||||
len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p);
|
||||
len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(AI_MAXLEN - len - 1), p);
|
||||
}
|
||||
|
||||
switch (prim.mode) {
|
||||
|
|
@ -488,28 +560,25 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
break;
|
||||
}
|
||||
|
||||
Mesh::Primitive::Attributes &attr = prim.attributes;
|
||||
|
||||
if (!attr.position.empty() && attr.position[0]) {
|
||||
aim->mNumVertices = static_cast<unsigned int>(attr.position[0]->count);
|
||||
attr.position[0]->ExtractData(aim->mVertices);
|
||||
aim->mNumVertices = static_cast<unsigned int>(attr.position[0]->ExtractData(aim->mVertices, vertexRemappingTable));
|
||||
}
|
||||
|
||||
if (!attr.normal.empty() && attr.normal[0]) {
|
||||
if (attr.normal[0]->count != aim->mNumVertices) {
|
||||
if (attr.normal[0]->count != numAllVertices) {
|
||||
DefaultLogger::get()->warn("Normal count in mesh \"", mesh.name, "\" does not match the vertex count, normals ignored.");
|
||||
} else {
|
||||
attr.normal[0]->ExtractData(aim->mNormals);
|
||||
attr.normal[0]->ExtractData(aim->mNormals, vertexRemappingTable);
|
||||
|
||||
// only extract tangents if normals are present
|
||||
if (!attr.tangent.empty() && attr.tangent[0]) {
|
||||
if (attr.tangent[0]->count != aim->mNumVertices) {
|
||||
if (attr.tangent[0]->count != numAllVertices) {
|
||||
DefaultLogger::get()->warn("Tangent count in mesh \"", mesh.name, "\" does not match the vertex count, tangents ignored.");
|
||||
} else {
|
||||
// generate bitangents from normals and tangents according to spec
|
||||
Tangent *tangents = nullptr;
|
||||
|
||||
attr.tangent[0]->ExtractData(tangents);
|
||||
attr.tangent[0]->ExtractData(tangents, vertexRemappingTable);
|
||||
|
||||
aim->mTangents = new aiVector3D[aim->mNumVertices];
|
||||
aim->mBitangents = new aiVector3D[aim->mNumVertices];
|
||||
|
|
@ -526,7 +595,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
}
|
||||
|
||||
for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) {
|
||||
if (attr.color[c]->count != aim->mNumVertices) {
|
||||
if (attr.color[c]->count != numAllVertices) {
|
||||
DefaultLogger::get()->warn("Color stream size in mesh \"", mesh.name,
|
||||
"\" does not match the vertex count");
|
||||
continue;
|
||||
|
|
@ -534,12 +603,12 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
|
||||
auto componentType = attr.color[c]->componentType;
|
||||
if (componentType == glTF2::ComponentType_FLOAT) {
|
||||
attr.color[c]->ExtractData(aim->mColors[c]);
|
||||
attr.color[c]->ExtractData(aim->mColors[c], vertexRemappingTable);
|
||||
} else {
|
||||
if (componentType == glTF2::ComponentType_UNSIGNED_BYTE) {
|
||||
aim->mColors[c] = GetVertexColorsForType<unsigned char>(attr.color[c]);
|
||||
aim->mColors[c] = GetVertexColorsForType<unsigned char>(attr.color[c], vertexRemappingTable);
|
||||
} else if (componentType == glTF2::ComponentType_UNSIGNED_SHORT) {
|
||||
aim->mColors[c] = GetVertexColorsForType<unsigned short>(attr.color[c]);
|
||||
aim->mColors[c] = GetVertexColorsForType<unsigned short>(attr.color[c], vertexRemappingTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -549,13 +618,13 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (attr.texcoord[tc]->count != aim->mNumVertices) {
|
||||
if (attr.texcoord[tc]->count != numAllVertices) {
|
||||
DefaultLogger::get()->warn("Texcoord stream size in mesh \"", mesh.name,
|
||||
"\" does not match the vertex count");
|
||||
continue;
|
||||
}
|
||||
|
||||
attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
|
||||
attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc], vertexRemappingTable);
|
||||
aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
|
||||
|
||||
aiVector3D *values = aim->mTextureCoords[tc];
|
||||
|
|
@ -580,11 +649,11 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
Mesh::Primitive::Target &target = targets[i];
|
||||
|
||||
if (needPositions) {
|
||||
if (target.position[0]->count != aim->mNumVertices) {
|
||||
if (target.position[0]->count != numAllVertices) {
|
||||
ASSIMP_LOG_WARN("Positions of target ", i, " in mesh \"", mesh.name, "\" does not match the vertex count");
|
||||
} else {
|
||||
aiVector3D *positionDiff = nullptr;
|
||||
target.position[0]->ExtractData(positionDiff);
|
||||
target.position[0]->ExtractData(positionDiff, vertexRemappingTable);
|
||||
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
|
||||
aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId];
|
||||
}
|
||||
|
|
@ -592,11 +661,11 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
}
|
||||
}
|
||||
if (needNormals) {
|
||||
if (target.normal[0]->count != aim->mNumVertices) {
|
||||
if (target.normal[0]->count != numAllVertices) {
|
||||
ASSIMP_LOG_WARN("Normals of target ", i, " in mesh \"", mesh.name, "\" does not match the vertex count");
|
||||
} else {
|
||||
aiVector3D *normalDiff = nullptr;
|
||||
target.normal[0]->ExtractData(normalDiff);
|
||||
target.normal[0]->ExtractData(normalDiff, vertexRemappingTable);
|
||||
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
|
||||
aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId];
|
||||
}
|
||||
|
|
@ -607,14 +676,14 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
if (!aiAnimMesh.HasNormals()) {
|
||||
// prevent nullptr access to aiAnimMesh.mNormals below when no normals are available
|
||||
ASSIMP_LOG_WARN("Bitangents of target ", i, " in mesh \"", mesh.name, "\" can't be computed, because mesh has no normals.");
|
||||
} else if (target.tangent[0]->count != aim->mNumVertices) {
|
||||
} else if (target.tangent[0]->count != numAllVertices) {
|
||||
ASSIMP_LOG_WARN("Tangents of target ", i, " in mesh \"", mesh.name, "\" does not match the vertex count");
|
||||
} else {
|
||||
Tangent *tangent = nullptr;
|
||||
attr.tangent[0]->ExtractData(tangent);
|
||||
attr.tangent[0]->ExtractData(tangent, vertexRemappingTable);
|
||||
|
||||
aiVector3D *tangentDiff = nullptr;
|
||||
target.tangent[0]->ExtractData(tangentDiff);
|
||||
target.tangent[0]->ExtractData(tangentDiff, vertexRemappingTable);
|
||||
|
||||
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) {
|
||||
tangent[vertexId].xyz += tangentDiff[vertexId];
|
||||
|
|
@ -638,20 +707,15 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
aiFace *facePtr = nullptr;
|
||||
size_t nFaces = 0;
|
||||
|
||||
if (prim.indices) {
|
||||
size_t count = prim.indices->count;
|
||||
|
||||
Accessor::Indexer data = prim.indices->GetIndexer();
|
||||
if (!data.IsValid()) {
|
||||
throw DeadlyImportError("GLTF: Invalid accessor without data in mesh ", getContextForErrorMessages(mesh.id, mesh.name));
|
||||
}
|
||||
if (useIndexBuffer) {
|
||||
size_t count = indexBuffer.size();
|
||||
|
||||
switch (prim.mode) {
|
||||
case PrimitiveMode_POINTS: {
|
||||
nFaces = count;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
SetFaceAndAdvance1(facePtr, aim->mNumVertices, data.GetUInt(i));
|
||||
SetFaceAndAdvance1(facePtr, aim->mNumVertices, indexBuffer[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -664,7 +728,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 2) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1));
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, indexBuffer[i], indexBuffer[i + 1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -673,12 +737,12 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
case PrimitiveMode_LINE_STRIP: {
|
||||
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1));
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, indexBuffer[0], indexBuffer[1]);
|
||||
for (unsigned int i = 2; i < count; ++i) {
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(i - 1), data.GetUInt(i));
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, indexBuffer[i - 1], indexBuffer[i]);
|
||||
}
|
||||
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, data.GetUInt(static_cast<int>(count) - 1), faces[0].mIndices[0]);
|
||||
SetFaceAndAdvance2(facePtr, aim->mNumVertices, indexBuffer[static_cast<int>(count) - 1], faces[0].mIndices[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -691,7 +755,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
}
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 3) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[i], indexBuffer[i + 1], indexBuffer[i + 2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -702,10 +766,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
// The ordering is to ensure that the triangles are all drawn with the same orientation
|
||||
if ((i + 1) % 2 == 0) {
|
||||
// For even n, vertices n + 1, n, and n + 2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[i + 1], indexBuffer[i], indexBuffer[i + 2]);
|
||||
} else {
|
||||
// For odd n, vertices n, n+1, and n+2 define triangle n
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[i], indexBuffer[i + 1], indexBuffer[i + 2]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -713,9 +777,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
nFaces = count - 2;
|
||||
facePtr = faces = new aiFace[nFaces];
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[0], indexBuffer[1], indexBuffer[2]);
|
||||
for (unsigned int i = 1; i < nFaces; ++i) {
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(0), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
SetFaceAndAdvance3(facePtr, aim->mNumVertices, indexBuffer[0], indexBuffer[i + 1], indexBuffer[i + 2]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -820,8 +884,6 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
|||
}
|
||||
}
|
||||
|
||||
meshOffsets.push_back(k);
|
||||
|
||||
CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
|
||||
}
|
||||
|
||||
|
|
@ -846,7 +908,7 @@ void glTF2Importer::ImportCameras(glTF2::Asset &r) {
|
|||
|
||||
if (cam.type == Camera::Perspective) {
|
||||
aicam->mAspect = cam.cameraProperties.perspective.aspectRatio;
|
||||
aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect);
|
||||
aicam->mHorizontalFOV = 2.0f * std::atan(std::tan(cam.cameraProperties.perspective.yfov * 0.5f) * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect));
|
||||
aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar;
|
||||
aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear;
|
||||
} else {
|
||||
|
|
@ -954,7 +1016,8 @@ static void GetNodeTransform(aiMatrix4x4 &matrix, const glTF2::Node &node) {
|
|||
}
|
||||
}
|
||||
|
||||
static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std::vector<aiVertexWeight>> &map) {
|
||||
static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std::vector<aiVertexWeight>> &map, std::vector<unsigned int>* vertexRemappingTablePtr) {
|
||||
|
||||
Mesh::Primitive::Attributes &attr = primitive.attributes;
|
||||
if (attr.weight.empty() || attr.joint.empty()) {
|
||||
return;
|
||||
|
|
@ -963,14 +1026,14 @@ static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std
|
|||
return;
|
||||
}
|
||||
|
||||
size_t num_vertices = attr.weight[0]->count;
|
||||
size_t num_vertices = 0;
|
||||
|
||||
struct Weights {
|
||||
float values[4];
|
||||
};
|
||||
Weights **weights = new Weights*[attr.weight.size()];
|
||||
for (size_t w = 0; w < attr.weight.size(); ++w) {
|
||||
attr.weight[w]->ExtractData(weights[w]);
|
||||
num_vertices = attr.weight[w]->ExtractData(weights[w], vertexRemappingTablePtr);
|
||||
}
|
||||
|
||||
struct Indices8 {
|
||||
|
|
@ -984,12 +1047,12 @@ static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std
|
|||
if (attr.joint[0]->GetElementSize() == 4) {
|
||||
indices8 = new Indices8*[attr.joint.size()];
|
||||
for (size_t j = 0; j < attr.joint.size(); ++j) {
|
||||
attr.joint[j]->ExtractData(indices8[j]);
|
||||
attr.joint[j]->ExtractData(indices8[j], vertexRemappingTablePtr);
|
||||
}
|
||||
} else {
|
||||
indices16 = new Indices16 *[attr.joint.size()];
|
||||
for (size_t j = 0; j < attr.joint.size(); ++j) {
|
||||
attr.joint[j]->ExtractData(indices16[j]);
|
||||
attr.joint[j]->ExtractData(indices16[j], vertexRemappingTablePtr);
|
||||
}
|
||||
}
|
||||
//
|
||||
|
|
@ -1048,15 +1111,13 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) {
|
|||
}
|
||||
}
|
||||
|
||||
void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) {
|
||||
if (extension.mValues.isPresent) {
|
||||
for (auto const &subExtension : extension.mValues.value) {
|
||||
ParseExtensions(metadata, subExtension);
|
||||
}
|
||||
void ParseExtras(aiMetadata* metadata, const Extras& extras) {
|
||||
for (auto const &value : extras.mValues) {
|
||||
ParseExtensions(metadata, value);
|
||||
}
|
||||
}
|
||||
|
||||
aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &meshOffsets, glTF2::Ref<glTF2::Node> &ptr) {
|
||||
aiNode *glTF2Importer::ImportNode(glTF2::Asset &r, glTF2::Ref<glTF2::Node> &ptr) {
|
||||
Node &node = *ptr;
|
||||
|
||||
aiNode *ainode = new aiNode(GetNodeName(node));
|
||||
|
|
@ -1068,18 +1129,18 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
|
|||
std::fill(ainode->mChildren, ainode->mChildren + ainode->mNumChildren, nullptr);
|
||||
|
||||
for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
|
||||
aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]);
|
||||
aiNode *child = ImportNode(r, node.children[i]);
|
||||
child->mParent = ainode;
|
||||
ainode->mChildren[i] = child;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.customExtensions || node.extras) {
|
||||
if (node.customExtensions || node.extras.HasExtras()) {
|
||||
ainode->mMetaData = new aiMetadata;
|
||||
if (node.customExtensions) {
|
||||
ParseExtensions(ainode->mMetaData, node.customExtensions);
|
||||
}
|
||||
if (node.extras) {
|
||||
if (node.extras.HasExtras()) {
|
||||
ParseExtras(ainode->mMetaData, node.extras);
|
||||
}
|
||||
}
|
||||
|
|
@ -1101,11 +1162,13 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
|
|||
|
||||
if (node.skin) {
|
||||
for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) {
|
||||
aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo];
|
||||
unsigned int aiMeshIdx = meshOffsets[mesh_idx] + primitiveNo;
|
||||
aiMesh *mesh = mScene->mMeshes[aiMeshIdx];
|
||||
unsigned int numBones = static_cast<unsigned int>(node.skin->jointNames.size());
|
||||
std::vector<unsigned int> *vertexRemappingTablePtr = mVertexRemappingTables[aiMeshIdx].empty() ? nullptr : &mVertexRemappingTables[aiMeshIdx];
|
||||
|
||||
std::vector<std::vector<aiVertexWeight>> weighting(numBones);
|
||||
BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting);
|
||||
BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting, vertexRemappingTablePtr);
|
||||
|
||||
mesh->mNumBones = static_cast<unsigned int>(numBones);
|
||||
mesh->mBones = new aiBone *[mesh->mNumBones];
|
||||
|
|
@ -1122,7 +1185,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
|
|||
// mapping which makes things doubly-slow.
|
||||
|
||||
mat4 *pbindMatrices = nullptr;
|
||||
node.skin->inverseBindMatrices->ExtractData(pbindMatrices);
|
||||
node.skin->inverseBindMatrices->ExtractData(pbindMatrices, nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < numBones; ++i) {
|
||||
const std::vector<aiVertexWeight> &weights = weighting[i];
|
||||
|
|
@ -1168,16 +1231,11 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
|
|||
}
|
||||
|
||||
if (node.camera) {
|
||||
pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
|
||||
if (node.translation.isPresent) {
|
||||
aiVector3D trans;
|
||||
CopyValue(node.translation.value, trans);
|
||||
pScene->mCameras[node.camera.GetIndex()]->mPosition = trans;
|
||||
}
|
||||
mScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
|
||||
}
|
||||
|
||||
if (node.light) {
|
||||
pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
|
||||
mScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
|
||||
|
||||
// range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
|
||||
// it is added to meta data of parent node, because there is no other place to put it
|
||||
|
|
@ -1209,7 +1267,7 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) {
|
|||
// The root nodes
|
||||
unsigned int numRootNodes = unsigned(rootNodes.size());
|
||||
if (numRootNodes == 1) { // a single root node: use it
|
||||
mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
|
||||
mScene->mRootNode = ImportNode(r, rootNodes[0]);
|
||||
} else if (numRootNodes > 1) { // more than one root node: create a fake root
|
||||
aiNode *root = mScene->mRootNode = new aiNode("ROOT");
|
||||
|
||||
|
|
@ -1217,7 +1275,7 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) {
|
|||
std::fill(root->mChildren, root->mChildren + numRootNodes, nullptr);
|
||||
|
||||
for (unsigned int i = 0; i < numRootNodes; ++i) {
|
||||
aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
|
||||
aiNode *node = ImportNode(r, rootNodes[i]);
|
||||
node->mParent = root;
|
||||
root->mChildren[root->mNumChildren++] = node;
|
||||
}
|
||||
|
|
@ -1572,7 +1630,7 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
|
|||
if (!img.mimeType.empty()) {
|
||||
const char *ext = strchr(img.mimeType.c_str(), '/') + 1;
|
||||
if (ext) {
|
||||
if (strcmp(ext, "jpeg") == 0) {
|
||||
if (strncmp(ext, "jpeg", 4) == 0) {
|
||||
ext = "jpg";
|
||||
} else if (strcmp(ext, "ktx2") == 0) { // basisu: ktx remains
|
||||
ext = "kx2";
|
||||
|
|
@ -1580,9 +1638,9 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
|
|||
ext = "bu";
|
||||
}
|
||||
|
||||
size_t len = strlen(ext);
|
||||
const size_t len = strlen(ext);
|
||||
if (len <= 3) {
|
||||
strcpy(tex->achFormatHint, ext);
|
||||
strncpy(tex->achFormatHint, ext, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1618,13 +1676,17 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
|
|||
|
||||
// clean all member arrays
|
||||
meshOffsets.clear();
|
||||
mVertexRemappingTables.clear();
|
||||
mEmbeddedTexIdxs.clear();
|
||||
|
||||
this->mScene = pScene;
|
||||
|
||||
// read the asset file
|
||||
glTF2::Asset asset(pIOHandler, static_cast<rapidjson::IRemoteSchemaDocumentProvider *>(mSchemaDocumentProvider));
|
||||
asset.Load(pFile, GetExtension(pFile) == "glb");
|
||||
asset.Load(pFile,
|
||||
CheckMagicToken(
|
||||
pIOHandler, pFile, AI_GLB_MAGIC_NUMBER, 1, 0,
|
||||
static_cast<unsigned int>(strlen(AI_GLB_MAGIC_NUMBER))));
|
||||
if (asset.scene) {
|
||||
pScene->mName = asset.scene->name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
Copyright (c) 2006-2024, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define AI_GLTF2IMPORTER_H_INC
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <AssetLib/glTF2/glTF2Asset.h>
|
||||
|
||||
struct aiNode;
|
||||
|
||||
|
|
@ -59,13 +60,13 @@ namespace Assimp {
|
|||
class glTF2Importer : public BaseImporter {
|
||||
public:
|
||||
glTF2Importer();
|
||||
~glTF2Importer() override;
|
||||
~glTF2Importer() override = default;
|
||||
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
|
||||
|
||||
protected:
|
||||
const aiImporterDesc *GetInfo() const override;
|
||||
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
|
||||
virtual void SetupProperties(const Importer *pImp) override;
|
||||
void SetupProperties(const Importer *pImp) override;
|
||||
|
||||
private:
|
||||
void ImportEmbeddedTextures(glTF2::Asset &a);
|
||||
|
|
@ -76,10 +77,12 @@ private:
|
|||
void ImportNodes(glTF2::Asset &a);
|
||||
void ImportAnimations(glTF2::Asset &a);
|
||||
void ImportCommonMetadata(glTF2::Asset &a);
|
||||
aiNode *ImportNode(glTF2::Asset &r, glTF2::Ref<glTF2::Node> &ptr);
|
||||
|
||||
private:
|
||||
std::vector<unsigned int> meshOffsets;
|
||||
std::vector<int> mEmbeddedTexIdxs;
|
||||
std::vector<std::vector<unsigned int>> mVertexRemappingTables; // for each converted aiMesh in the scene, it stores a list of vertices that are actually used
|
||||
aiScene *mScene;
|
||||
|
||||
/// An instance of rapidjson::IRemoteSchemaDocumentProvider
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue