From dcaadf5d7d09352ce1a637ec477bc4cc58cd118a Mon Sep 17 00:00:00 2001 From: David Steele Date: Thu, 18 May 2023 18:13:00 +0100 Subject: [PATCH] Updated model loader to handle multiple attr sets Modified GLTF parser for attributes to create attribute sets for joints/weights/texcoords/colors Added macro definitions to ShaderOptions, fixed hash to account for macro/def strings. Changed shader manager to create shader with extra attributes Change-Id: Iabe2772eaf767ca3055dd415752c5a612942f0a4 --- .../shaders/default-physically-based-shader.vert | 25 +- .../graphics/shaders/shadow-map-shader.vert | 32 +- dali-scene3d/internal/loader/dli-loader-impl.cpp | 53 ++-- dali-scene3d/internal/loader/gltf2-asset.cpp | 77 ++++- dali-scene3d/internal/loader/gltf2-asset.h | 56 +++- dali-scene3d/internal/loader/gltf2-util.cpp | 325 +++++++++++++-------- dali-scene3d/public-api/loader/mesh-definition.cpp | 151 ++++++---- dali-scene3d/public-api/loader/mesh-definition.h | 17 +- .../public-api/loader/shader-definition.cpp | 29 +- dali-scene3d/public-api/loader/shader-definition.h | 21 +- dali-scene3d/public-api/loader/shader-manager.cpp | 33 ++- dali-scene3d/public-api/loader/shader-option.cpp | 63 +++- dali-scene3d/public-api/loader/shader-option.h | 24 +- 13 files changed, 631 insertions(+), 275 deletions(-) diff --git a/dali-scene3d/internal/graphics/shaders/default-physically-based-shader.vert b/dali-scene3d/internal/graphics/shaders/default-physically-based-shader.vert index 2b4f000..7ea0654 100644 --- a/dali-scene3d/internal/graphics/shaders/default-physically-based-shader.vert +++ b/dali-scene3d/internal/graphics/shaders/default-physically-based-shader.vert @@ -6,6 +6,10 @@ #define MORPH defined(MORPH_POSITION) || defined(MORPH_NORMAL) || defined(MORPH_TANGENT) +// If needed, define these strings in code, insert after each. +#define ADD_EXTRA_SKINNING_ATTRIBUTES +#define ADD_EXTRA_WEIGHTS + #ifdef HIGHP precision highp float; #else @@ -25,8 +29,9 @@ in vec3 aTangent; in vec4 aVertexColor; #ifdef SKINNING -in vec4 aJoints; -in vec4 aWeights; +in vec4 aJoints0; +in vec4 aWeights0; +ADD_EXTRA_SKINNING_ATTRIBUTES; #endif #ifdef MORPH @@ -150,11 +155,18 @@ void main() #endif + + + #ifdef SKINNING - highp mat4 bone = uBone[int(aJoints.x)] * aWeights.x + - uBone[int(aJoints.y)] * aWeights.y + - uBone[int(aJoints.z)] * aWeights.z + - uBone[int(aJoints.w)] * aWeights.w; + highp mat4 bone = + uBone[int(aJoints0.x)] * aWeights0.x + + uBone[int(aJoints0.y)] * aWeights0.y + + uBone[int(aJoints0.z)] * aWeights0.z + + uBone[int(aJoints0.w)] * aWeights0.w; + + ADD_EXTRA_WEIGHTS; + position = bone * position; normal = uYDirection * (bone * vec4(normal, 0.0)).xyz; tangent = uYDirection * (bone * vec4(tangent, 0.0)).xyz; @@ -163,6 +175,7 @@ void main() #else highp vec4 positionW = uModelMatrix * position; #endif + highp vec4 positionV = uViewMatrix * positionW; vPositionToCamera = transpose(mat3(uViewMatrix)) * -vec3(positionV.xyz / positionV.w); diff --git a/dali-scene3d/internal/graphics/shaders/shadow-map-shader.vert b/dali-scene3d/internal/graphics/shaders/shadow-map-shader.vert index 73bb37c..945198b 100644 --- a/dali-scene3d/internal/graphics/shaders/shadow-map-shader.vert +++ b/dali-scene3d/internal/graphics/shaders/shadow-map-shader.vert @@ -1,11 +1,20 @@ #version 300 es +#define ADD_EXTRA_SKINNING_ATTRIBUTES +#define ADD_EXTRA_WEIGHTS + precision highp float; in vec3 aPosition; in vec2 aTexCoord; in vec4 aVertexColor; +#ifdef SKINNING +in vec4 aJoints0; +in vec4 aWeights0; +ADD_EXTRA_SKINNING_ATTRIBUTES; +#endif + out mediump vec2 vUV; out lowp vec4 vColor; @@ -14,11 +23,12 @@ uniform highp mat4 uModelMatrix; uniform highp mat4 uProjection; #ifdef SKINNING - in vec4 aJoints; - in vec4 aWeights; - #define MAX_BONES 64 - uniform mat4 uBone[MAX_BONES]; - uniform mediump vec3 uYDirection; +#define MAX_BONES 256 +layout(std140) uniform Bones +{ + mat4 uBone[MAX_BONES]; +}; +uniform mediump vec3 uYDirection; #endif #ifdef MORPH @@ -86,12 +96,14 @@ void main() #endif #ifdef SKINNING - highp mat4 bone = uBone[int(aJoints.x)] * aWeights.x + - uBone[int(aJoints.y)] * aWeights.y + - uBone[int(aJoints.z)] * aWeights.z + - uBone[int(aJoints.w)] * aWeights.w; - position = bone * position; + highp mat4 bone = uBone[int(aJoints0.x)] * aWeights0.x + + uBone[int(aJoints0.y)] * aWeights0.y + + uBone[int(aJoints0.z)] * aWeights0.z + + uBone[int(aJoints0.w)] * aWeights0.w; + ADD_EXTRA_WEIGHTS; + + position = bone * position; highp vec4 positionW = position; #else highp vec4 positionW = uModelMatrix * position; diff --git a/dali-scene3d/internal/loader/dli-loader-impl.cpp b/dali-scene3d/internal/loader/dli-loader-impl.cpp index 668a10c..1ed195d 100644 --- a/dali-scene3d/internal/loader/dli-loader-impl.cpp +++ b/dali-scene3d/internal/loader/dli-loader-impl.cpp @@ -667,8 +667,7 @@ void DliLoaderImpl::Impl::ParseShaders(const TreeNode* shaders, Dali::Scene3D::L auto& node = (*i0).second; ShaderDefinition shaderDef; ReadStringVector(node.GetChild("defines"), shaderDef.mDefines); - auto sssIter = std::find_if(shaderDef.mDefines.begin(), shaderDef.mDefines.end(), [](std::string& item) - { return (item == "SSS"); }); + auto sssIter = std::find_if(shaderDef.mDefines.begin(), shaderDef.mDefines.end(), [](std::string& item) { return (item == "SSS"); }); if(sssIter != shaderDef.mDefines.end()) { shaderDef.mDefines.erase(sssIter); @@ -843,10 +842,13 @@ void DliLoaderImpl::Impl::ParseMeshes(const TreeNode* meshes, Dali::Scene3D::Loa mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(), "normals")); } - if(MaskMatch(attributes, MeshDefinition::TEX_COORDS) && - !ReadAttribAccessor(node.GetChild("textures"), meshDef.mTexCoords)) + if(MaskMatch(attributes, MeshDefinition::TEX_COORDS)) { - mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(), "textures")); + meshDef.mTexCoords.emplace_back(MeshDefinition::Accessor{}); + if(!ReadAttribAccessor(node.GetChild("textures"), meshDef.mTexCoords[0])) + { + mOnError(FormatString("mesh %d: Failed to read %s.", resources.mMeshes.size(), "textures")); + } } if(MaskMatch(attributes, MeshDefinition::TANGENTS) && @@ -864,11 +866,16 @@ void DliLoaderImpl::Impl::ParseMeshes(const TreeNode* meshes, Dali::Scene3D::Loa mOnError(FormatString("mesh %d: Expected joints0 / weights0 attribute(s) missing.", resources.mMeshes.size())); } - else if(!ReadAttribAccessor(node.GetChild("joints0"), meshDef.mJoints0) || - !ReadAttribAccessor(node.GetChild("weights0"), meshDef.mWeights0)) + else { - mOnError(FormatString("mesh %d: Failed to read skinning information.", - resources.mMeshes.size())); + meshDef.mJoints.emplace_back(MeshDefinition::Accessor{}); + meshDef.mWeights.emplace_back(MeshDefinition::Accessor{}); + if(!ReadAttribAccessor(node.GetChild("joints0"), meshDef.mJoints[0]) || + !ReadAttribAccessor(node.GetChild("weights0"), meshDef.mWeights[0])) + { + mOnError(FormatString("mesh %d: Failed to read skinning information.", + resources.mMeshes.size())); + } } } @@ -1033,17 +1040,17 @@ void DliLoaderImpl::Impl::ParseMaterials(const TreeNode* materials, DliInputPara materialDef.mFlags |= semantic; } -/// @TODO : Some dli shader don't implement this subsurfaceMp usage. -/// To make visual test pass, Skip subsurfaceMap texture using -/// until dli shaders are support it. -// if(ReadString(node.GetChild("subsurfaceMap"), texturePath)) -// { -// ToUnixFileSeparators(texturePath); -// -// const auto semantic = MaterialDefinition::SUBSURFACE; -// materialDef.mTextureStages.push_back({semantic, TextureDefinition{std::move(texturePath)}}); -// materialDef.mFlags |= semantic; -// } + /// @TODO : Some dli shader don't implement this subsurfaceMp usage. + /// To make visual test pass, Skip subsurfaceMap texture using + /// until dli shaders are support it. + // if(ReadString(node.GetChild("subsurfaceMap"), texturePath)) + // { + // ToUnixFileSeparators(texturePath); + // + // const auto semantic = MaterialDefinition::SUBSURFACE; + // materialDef.mTextureStages.push_back({semantic, TextureDefinition{std::move(texturePath)}}); + // materialDef.mFlags |= semantic; + // } if(ReadString(node.GetChild("occlusionMap"), texturePath)) { @@ -1447,10 +1454,10 @@ void DliLoaderImpl::Impl::ParseAnimations(const TreeNode* tnAnimations, LoadPara iAnim != iAnimEnd; ++iAnim) { - const TreeNode& tnAnim = (*iAnim).second; - uint32_t animationPropertyIndex = 0; + const TreeNode& tnAnim = (*iAnim).second; + uint32_t animationPropertyIndex = 0; AnimationDefinition animDef; - std::string animationName; + std::string animationName; ReadString(tnAnim.GetChild(NAME), animationName); animDef.SetName(animationName); diff --git a/dali-scene3d/internal/loader/gltf2-asset.cpp b/dali-scene3d/internal/loader/gltf2-asset.cpp index a6ac398..bbc092e 100644 --- a/dali-scene3d/internal/loader/gltf2-asset.cpp +++ b/dali-scene3d/internal/loader/gltf2-asset.cpp @@ -63,21 +63,6 @@ const std::map& GetAlphaModeTypes() return ALPHA_MODE_TYPES; } -const std::map& GetAttributeTypes() -{ - static const std::map ATTRIBUTE_TYPES{ - ENUM_STRING_MAPPING(Attribute::Type, POSITION), - ENUM_STRING_MAPPING(Attribute::Type, NORMAL), - ENUM_STRING_MAPPING(Attribute::Type, TANGENT), - ENUM_STRING_MAPPING(Attribute::Type, TEXCOORD_0), - ENUM_STRING_MAPPING(Attribute::Type, TEXCOORD_1), - ENUM_STRING_MAPPING(Attribute::Type, COLOR_0), - ENUM_STRING_MAPPING(Attribute::Type, JOINTS_0), - ENUM_STRING_MAPPING(Attribute::Type, WEIGHTS_0), - }; - return ATTRIBUTE_TYPES; -} - const std::map& GetAnimationSamplerInterpolation() { static const std::map ANIMATION_SAMPLER_INTERPOLATION{ @@ -103,10 +88,70 @@ const std::map& GetAnimation ENUM_TYPE_FROM_STRING(AccessorType, GetAccessorTypes()) ENUM_TYPE_FROM_STRING(AlphaMode, GetAlphaModeTypes()) -ENUM_TYPE_FROM_STRING(Attribute, GetAttributeTypes()) ENUM_TYPE_FROM_STRING(Animation::Sampler::Interpolation, GetAnimationSamplerInterpolation()) ENUM_TYPE_FROM_STRING(Animation::Channel::Target, GetAnimationChannelTargetPathTypes()) +const std::map& GetTargetTypes() +{ + static const std::map TARGET_TYPES{ + ENUM_STRING_MAPPING(Attribute::Type, POSITION), + ENUM_STRING_MAPPING(Attribute::Type, TANGENT), + ENUM_STRING_MAPPING(Attribute::Type, NORMAL), + }; + return TARGET_TYPES; +} + +const std::map& GetAttributeSetTypes() +{ + static const std::map ATTRIBUTE_SET_TYPES{ + {Attribute::Type::TEXCOORD_N, "TEXCOORD_%u"}, + {Attribute::Type::COLOR_N, "COLOR_%u"}, + {Attribute::Type::JOINTS_N, "JOINTS_%u"}, + {Attribute::Type::WEIGHTS_N, "WEIGHTS_%u"}, + }; + return ATTRIBUTE_SET_TYPES; +} + +uint32_t Attribute::HashFromString(const char* token, size_t length) +{ + auto& table1 = GetTargetTypes(); + auto& table2 = GetAttributeSetTypes(); + + std::string target(token, length); + std::transform(target.begin(), target.end(), target.begin(), ::toupper); + + auto iFind = table1.find(std::string_view(target.c_str(), length)); + if(iFind != table1.end()) + { + return Attribute::ToHash(iFind->second, false, 0); + } + + uint32_t hash = Attribute::ToHash(Attribute::INVALID, false, 0); + for(const auto& [key, match] : table2) + { + int setIndex; + if(sscanf(target.c_str(), match, &setIndex) > 0) + { + hash = Attribute::ToHash(key, true, setIndex); + break; + } + } + return hash; +} + +Attribute::Type Attribute::TargetFromString(const char* token, size_t length) +{ + std::string target(token, length); + std::transform(target.begin(), target.end(), target.begin(), ::toupper); + + auto iFind = GetTargetTypes().find(std::string_view(target.c_str(), length)); + if(iFind != GetTargetTypes().end()) + { + return iFind->second; + } + return Attribute::INVALID; +} + bool Component::IsUnsigned(Type t) { return t == UNSIGNED_BYTE || t == UNSIGNED_SHORT || t == UNSIGNED_INT; diff --git a/dali-scene3d/internal/loader/gltf2-asset.h b/dali-scene3d/internal/loader/gltf2-asset.h index 8488c1e..e90cf38 100644 --- a/dali-scene3d/internal/loader/gltf2-asset.h +++ b/dali-scene3d/internal/loader/gltf2-asset.h @@ -180,15 +180,57 @@ struct Attribute POSITION, NORMAL, TANGENT, - TEXCOORD_0, - TEXCOORD_1, - COLOR_0, - JOINTS_0, - WEIGHTS_0, + TEXCOORD_N, + COLOR_N, + JOINTS_N, + WEIGHTS_N, INVALID }; - static Type FromString(const char* s, size_t len); + using HashType = uint32_t; + + // Hash bit layout + // +--+--+--+--+--+--+--+ + // |31|30|29|28|27|..| 0| bit index + // +--+--+--+--+--+--+--+ + // \_/ - Set is used + // \______/ - Type enum + // \_______/ - Set ID + static const HashType SET_SHIFT{31}; + static const HashType TYPE_SHIFT{28}; + static const HashType SET_MASK{0x01u << SET_SHIFT}; + static const HashType TYPE_MASK{0x07 << TYPE_SHIFT}; + static const HashType SET_ID_MASK{0x0fffffff}; + + static HashType ToHash(Type type, bool set, HashType setIndex) + { + return ((set << SET_SHIFT) & SET_MASK) | ((static_cast(type) << TYPE_SHIFT) & TYPE_MASK) | (setIndex & SET_ID_MASK); + } + + static Attribute::Type TypeFromHash(HashType hash) + { + return static_cast((hash & TYPE_MASK) >> TYPE_SHIFT); + } + + static bool SetFromHash(HashType hash) + { + return (hash & SET_SHIFT) != 0; + } + + static HashType SetIdFromHash(HashType hash) + { + return (hash & SET_ID_MASK); + } + + /** + * Convert to Type + setIndex, where setIndex is N for that attr, e.g. "JOINTS_1" => {JOINTS_N, 1} + */ + static HashType HashFromString(const char* s, size_t len); + + /** + * Convert to type only, there is no set for POSITION, NORMALS or TANGENT. + */ + static Attribute::Type TargetFromString(const char* s, size_t len); Attribute() = delete; }; @@ -416,7 +458,7 @@ struct Mesh : Named INVALID }; - std::map> mAttributes; + std::map> mAttributes; std::vector>> mTargets; Ref mIndices; Ref mMaterial; diff --git a/dali-scene3d/internal/loader/gltf2-util.cpp b/dali-scene3d/internal/loader/gltf2-util.cpp index a6e3462..8abb5bb 100644 --- a/dali-scene3d/internal/loader/gltf2-util.cpp +++ b/dali-scene3d/internal/loader/gltf2-util.cpp @@ -48,30 +48,14 @@ static const Geometry::Type GLTF2_TO_DALI_PRIMITIVES[]{ Geometry::TRIANGLE_STRIP, Geometry::TRIANGLE_FAN}; //...because Dali swaps the last two. -static struct AttributeMapping -{ - gltf2::Attribute::Type mType; - MeshDefinition::Accessor MeshDefinition::*mAccessor; - uint16_t mElementSizeRequired; -} ATTRIBUTE_MAPPINGS[]{ - {gltf2::Attribute::NORMAL, &MeshDefinition::mNormals, sizeof(Vector3)}, - {gltf2::Attribute::TANGENT, &MeshDefinition::mTangents, sizeof(Vector3)}, - {gltf2::Attribute::TEXCOORD_0, &MeshDefinition::mTexCoords, sizeof(Vector2)}, - {gltf2::Attribute::COLOR_0, &MeshDefinition::mColors, sizeof(Vector4)}, - {gltf2::Attribute::JOINTS_0, &MeshDefinition::mJoints0, sizeof(Vector4)}, - {gltf2::Attribute::WEIGHTS_0, &MeshDefinition::mWeights0, sizeof(Vector4)}, -}; - static const Dali::Scripting::StringEnum EXTENSION_STRING_TABLE[] = - { - {"NONE", gltf2::ExtensionFlags::NONE}, - {"KHR_mesh_quantization", gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION}, - {"KHR_texture_transform", gltf2::ExtensionFlags::KHR_TEXTURE_TRANSFORM}, - {"KHR_materials_ior", gltf2::ExtensionFlags::KHR_MATERIALS_IOR}, - {"KHR_materials_specular", gltf2::ExtensionFlags::KHR_MATERIALS_SPECULAR}, - +{ + {"NONE", gltf2::ExtensionFlags::NONE}, + {"KHR_mesh_quantization", gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION}, + {"KHR_texture_transform", gltf2::ExtensionFlags::KHR_TEXTURE_TRANSFORM}, + {"KHR_materials_ior", gltf2::ExtensionFlags::KHR_MATERIALS_IOR}, + {"KHR_materials_specular", gltf2::ExtensionFlags::KHR_MATERIALS_SPECULAR}, }; - static const unsigned int EXTENSION_STRING_TABLE_COUNT = sizeof(EXTENSION_STRING_TABLE) / sizeof(EXTENSION_STRING_TABLE[0]); std::vector ReadAnimationArray(const json_value_s& j) @@ -147,9 +131,7 @@ const json::Reader& GetAccessorReader() .Register(*new json::Property>("bufferView", gltf2::RefReader::Read, &gltf2::Accessor::mBufferView)) - .Register(*new json::Property("byteOffset", - json::Read::Number, - &gltf2::Accessor::mByteOffset)) + .Register(*new json::Property("byteOffset", json::Read::Number, &gltf2::Accessor::mByteOffset)) .Register(*new json::Property("componentType", json::Read::Enum, &gltf2::Accessor::mComponentType)) @@ -253,7 +235,26 @@ const json::Reader& GetMaterialReader() return MATERIAL_READER; } -std::map> ReadMeshPrimitiveAttributes(const json_value_s& j) +std::map> ReadMeshPrimitiveAttributes(const json_value_s& j) +{ + auto& jsonObject = json::Cast(j); + std::map> result; + + auto element = jsonObject.start; + while(element) + { + auto jsonString = *element->name; + + gltf2::Attribute::HashType hash = gltf2::Attribute::HashFromString(jsonString.string, jsonString.string_size); + + result[hash] = + gltf2::RefReader::Read(*element->value); + element = element->next; + } + return result; +} + +std::map> ReadMeshPrimitiveAttributes2(const json_value_s& j) { auto& jsonObject = json::Cast(j); std::map> result; @@ -261,9 +262,11 @@ std::map> ReadMeshPrimitiveA auto element = jsonObject.start; while(element) { - auto jsonString = *element->name; - result[gltf2::Attribute::FromString(jsonString.string, jsonString.string_size)] = gltf2::RefReader::Read(*element->value); - element = element->next; + auto jsonString = *element->name; + + result[gltf2::Attribute::TargetFromString(jsonString.string, jsonString.string_size)] = gltf2::RefReader::Read(*element->value); + + element = element->next; } return result; } @@ -278,7 +281,7 @@ std::vector>> ReadM auto element = jsonObject.start; while(element) { - result.push_back(std::move(ReadMeshPrimitiveAttributes(*element->value))); + result.push_back(std::move(ReadMeshPrimitiveAttributes2(*element->value))); element = element->next; } @@ -764,13 +767,155 @@ MeshDefinition::Accessor ConvertMeshPrimitiveAccessor(const gltf2::Accessor& acc return MeshDefinition::Accessor{ std::move(MeshDefinition::Blob{bufferViewOffset + accessor.mByteOffset, - accessor.GetBytesLength(), - static_cast(bufferViewStride), - static_cast(accessor.GetElementSizeBytes()), - accessor.mMin, - accessor.mMax}), - std::move(sparseBlob), - accessor.mBufferView ? accessor.mBufferView->mBuffer.GetIndex() : 0}; + accessor.GetBytesLength(), + static_cast(bufferViewStride), + static_cast(accessor.GetElementSizeBytes()), + accessor.mMin, + accessor.mMax}), + std::move(sparseBlob), + accessor.mBufferView ? accessor.mBufferView->mBuffer.GetIndex() : 0, + accessor.mNormalized}; +} + +MeshDefinition::Accessor* GetAccessorFromAttribute(gltf2::Attribute::HashType attributeHash, + MeshDefinition& meshDefinition, + bool& needNormals, bool& needTangents) +{ + MeshDefinition::Accessor* accessorDest{nullptr}; + + switch(gltf2::Attribute::TypeFromHash(attributeHash)) + { + case gltf2::Attribute::POSITION: + { + accessorDest = &meshDefinition.mPositions; + break; + } + case gltf2::Attribute::NORMAL: + { + accessorDest = &meshDefinition.mNormals; + needNormals = false; + break; + } + case gltf2::Attribute::TANGENT: + { + accessorDest = &meshDefinition.mTangents; + needTangents = false; + break; + } + case gltf2::Attribute::TEXCOORD_N: + { + meshDefinition.mTexCoords.emplace_back(MeshDefinition::Accessor{}); + accessorDest = &meshDefinition.mTexCoords.back(); + break; + } + case gltf2::Attribute::COLOR_N: + { + meshDefinition.mColors.emplace_back(MeshDefinition::Accessor{}); + accessorDest = &meshDefinition.mColors.back(); + break; + } + case gltf2::Attribute::JOINTS_N: + { + meshDefinition.mJoints.emplace_back(MeshDefinition::Accessor{}); + accessorDest = &meshDefinition.mJoints.back(); + break; + } + case gltf2::Attribute::WEIGHTS_N: + { + meshDefinition.mWeights.emplace_back(MeshDefinition::Accessor{}); + accessorDest = &meshDefinition.mWeights.back(); + break; + } + case gltf2::Attribute::INVALID: + { + accessorDest = nullptr; + break; + } + } + return accessorDest; +} + +void SetFlagsFromComponentType(const gltf2::Accessor& accessor, + gltf2::Attribute::HashType attributeHash, + MeshDefinition& meshDefinition, + bool isQuantized) +{ + switch(gltf2::Attribute::TypeFromHash(attributeHash)) + { + case gltf2::Attribute::POSITION: + { + if(isQuantized) + { + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_POSITION; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_POSITION; + } + DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_POSITION))) || accessor.mComponentType == gltf2::Component::FLOAT); + break; + } + case gltf2::Attribute::NORMAL: + { + if(isQuantized) + { + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL; + } + + DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_NORMAL))) || accessor.mComponentType == gltf2::Component::FLOAT); + break; + } + case gltf2::Attribute::TANGENT: + { + if(isQuantized) + { + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT; + } + + DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TANGENT))) || accessor.mComponentType == gltf2::Component::FLOAT); + break; + } + case gltf2::Attribute::TEXCOORD_N: + { + if(isQuantized) + { + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TEXCOORD; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_TEXCOORD; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TEXCOORD; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_TEXCOORD; + } + DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_TEXCOORD))) || accessor.mComponentType == gltf2::Component::FLOAT); + break; + } + case gltf2::Attribute::COLOR_N: + { + break; + } + case gltf2::Attribute::JOINTS_N: + { + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS; + DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) || + MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) || + accessor.mComponentType == gltf2::Component::FLOAT); + break; + } + case gltf2::Attribute::WEIGHTS_N: + { + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_WEIGHT; + meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_WEIGHT; + DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_WEIGHT) || + MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_WEIGHT) || + accessor.mComponentType == gltf2::Component::FLOAT); + + break; + } + case gltf2::Attribute::INVALID: + { + break; + } + } } void ConvertMeshes(const gltf2::Document& document, ConversionContext& context) @@ -796,108 +941,40 @@ void ConvertMeshes(const gltf2::Document& document, ConversionContext& context) auto& attribs = primitive.mAttributes; meshDefinition.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[primitive.mMode]; - auto positionIter = attribs.find(gltf2::Attribute::POSITION); - + auto positionIter = attribs.find(gltf2::Attribute::ToHash(gltf2::Attribute::POSITION, false, 0)); if(positionIter == attribs.end()) { DALI_LOG_ERROR("Primitive mesh dosn't have POSITION atrributes!"); continue; } - auto& accPositions = *positionIter->second; - meshDefinition.mPositions = ConvertMeshPrimitiveAccessor(accPositions); - meshDefinition.mPositions.mNormalized = accPositions.mNormalized; - - if(isQuantized) - { - meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION; - meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_POSITION; - meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION; - meshDefinition.mFlags |= (accPositions.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_POSITION; - } - - DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_POSITION))) || accPositions.mComponentType == gltf2::Component::FLOAT); + auto& positionsAccessor = *positionIter->second; // glTF2 support vector4 tangent for mesh. // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview meshDefinition.mTangentType = Property::VECTOR4; - const bool needNormalsTangents = accPositions.mType == gltf2::AccessorType::VEC3; - for(auto& attributeMapping : ATTRIBUTE_MAPPINGS) + bool needNormals = (positionsAccessor.mType == gltf2::AccessorType::VEC3); + bool needTangents = (positionsAccessor.mType == gltf2::AccessorType::VEC3); + + for(const auto& [attributeHash, accessor] : attribs) { - auto iFind = attribs.find(attributeMapping.mType); - if(iFind != attribs.end()) + MeshDefinition::Accessor* accessorDest = GetAccessorFromAttribute(attributeHash, meshDefinition, needNormals, needTangents); + if(accessorDest == nullptr) { - auto& accessor = meshDefinition.*(attributeMapping.mAccessor); - accessor = ConvertMeshPrimitiveAccessor(*iFind->second); - - if(iFind->first == gltf2::Attribute::NORMAL) - { - meshDefinition.mNormals.mNormalized = iFind->second->mNormalized; - - if(isQuantized) - { - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL; - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL; - } - - DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_NORMAL))) || iFind->second->mComponentType == gltf2::Component::FLOAT); - } - if(iFind->first == gltf2::Attribute::TANGENT) - { - meshDefinition.mTangents.mNormalized = iFind->second->mNormalized; - - if(isQuantized) - { - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT; - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT; - } - - DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TANGENT))) || iFind->second->mComponentType == gltf2::Component::FLOAT); - } - if(iFind->first == gltf2::Attribute::TEXCOORD_0 || iFind->first == gltf2::Attribute::TEXCOORD_1) - { - meshDefinition.mTexCoords.mNormalized = iFind->second->mNormalized; - - if(isQuantized) - { - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TEXCOORD; - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_TEXCOORD; - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TEXCOORD; - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_TEXCOORD; - } - - DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_TEXCOORD))) || iFind->second->mComponentType == gltf2::Component::FLOAT); - } - if(iFind->first == gltf2::Attribute::JOINTS_0) - { - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS; - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS; - DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) || iFind->second->mComponentType == gltf2::Component::FLOAT); - } - if(iFind->first == gltf2::Attribute::WEIGHTS_0) - { - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_WEIGHT; - meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_WEIGHT; - DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_WEIGHT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_WEIGHT) || iFind->second->mComponentType == gltf2::Component::FLOAT); - } + continue; } - else if(needNormalsTangents) - { - switch(attributeMapping.mType) - { - case gltf2::Attribute::NORMAL: - meshDefinition.RequestNormals(); - break; - - case gltf2::Attribute::TANGENT: - meshDefinition.RequestTangents(); - break; + *accessorDest = ConvertMeshPrimitiveAccessor(*accessor); + SetFlagsFromComponentType(*accessor, attributeHash, meshDefinition, isQuantized); + } - default: - break; - } - } + if(needNormals) + { + meshDefinition.RequestNormals(); + } + if(needTangents) + { + meshDefinition.RequestTangents(); } if(primitive.mIndices) diff --git a/dali-scene3d/public-api/loader/mesh-definition.cpp b/dali-scene3d/public-api/loader/mesh-definition.cpp index 264f2fa..34f36f7 100644 --- a/dali-scene3d/public-api/loader/mesh-definition.cpp +++ b/dali-scene3d/public-api/loader/mesh-definition.cpp @@ -211,7 +211,7 @@ bool ReadAccessor(const MeshDefinition::Accessor& accessor, std::istream& source } template -void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath) +void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath, const std::string& name) { constexpr auto sizeofBlobUnit = sizeof(T) * 4; @@ -241,11 +241,27 @@ void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Acces ++floats; } } - raw.mAttribs.push_back({"aJoints", Property::VECTOR4, static_cast(outBufferSize / sizeof(Vector4)), std::move(buffer)}); + raw.mAttribs.push_back({name, Property::VECTOR4, static_cast(outBufferSize / sizeof(Vector4)), std::move(buffer)}); +} + +void ReadTypedJointAccessor(MeshDefinition::RawData& raw, uint32_t flags, MeshDefinition::Accessor& accessor, std::iostream& stream, std::string& path, const std::string& name) +{ + if(MaskMatch(flags, MeshDefinition::U16_JOINT_IDS)) + { + ReadJointAccessor(raw, accessor, stream, path, name); + } + else if(MaskMatch(flags, MeshDefinition::U8_JOINT_IDS)) + { + ReadJointAccessor(raw, accessor, stream, path, name); + } + else + { + ReadJointAccessor(raw, accessor, stream, path, name); + } } template -void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath) +void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath, const std::string& name) { constexpr auto sizeofBlobUnit = sizeof(T) * 4; @@ -276,7 +292,23 @@ void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Acce ++floats; } } - raw.mAttribs.push_back({"aWeights", Property::VECTOR4, static_cast(outBufferSize / sizeof(Vector4)), std::move(buffer)}); + raw.mAttribs.push_back({name, Property::VECTOR4, static_cast(outBufferSize / sizeof(Vector4)), std::move(buffer)}); +} + +void ReadTypedWeightAccessor(MeshDefinition::RawData& raw, uint32_t flags, MeshDefinition::Accessor& accessor, std::iostream& stream, std::string& path, std::string name) +{ + if(MaskMatch(flags, MeshDefinition::U16_WEIGHT)) + { + ReadWeightAccessor(raw, accessor, stream, path, name); + } + else if(MaskMatch(flags, MeshDefinition::U8_WEIGHT)) + { + ReadWeightAccessor(raw, accessor, stream, path, name); + } + else + { + ReadWeightAccessor(raw, accessor, stream, path, name); + } } template> @@ -827,19 +859,23 @@ MeshDefinition::SparseBlob::SparseBlob(Blob&& indices, Blob&& values, uint32_t c MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob& blob, const MeshDefinition::SparseBlob& sparse, - Index bufferIndex) + Index bufferIndex, + bool normalized) : mBlob{blob}, mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr}, - mBufferIdx(bufferIndex) + mBufferIdx(bufferIndex), + mNormalized(normalized) { } MeshDefinition::Accessor::Accessor(MeshDefinition::Blob&& blob, MeshDefinition::SparseBlob&& sparse, - Index bufferIndex) + Index bufferIndex, + bool normalized) : mBlob{std::move(blob)}, mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{std::move(sparse)} : nullptr}, - mBufferIdx(bufferIndex) + mBufferIdx(bufferIndex), + mNormalized(normalized) { } @@ -929,7 +965,7 @@ bool MeshDefinition::IsQuad() const bool MeshDefinition::IsSkinned() const { - return mJoints0.IsDefined() && mWeights0.IsDefined(); + return !mJoints.empty() && !mWeights.empty(); } bool MeshDefinition::HasBlendShapes() const @@ -1160,31 +1196,30 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& } } - const auto hasUvs = mTexCoords.IsDefined(); - if(hasUvs) + if(!mTexCoords.empty() && mTexCoords[0].IsDefined()) { - const auto bufferSize = mTexCoords.mBlob.GetBufferSize(); - + auto& texCoords = mTexCoords[0]; + const auto bufferSize = texCoords.mBlob.GetBufferSize(); uint32_t uvCount; if(MaskMatch(mFlags, S8_TEXCOORD) || MaskMatch(mFlags, U8_TEXCOORD)) { - DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % (sizeof(uint8_t) * 2) == 0) || - mTexCoords.mBlob.mStride >= (sizeof(uint8_t) * 2)) && + DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % (sizeof(uint8_t) * 2) == 0) || + texCoords.mBlob.mStride >= (sizeof(uint8_t) * 2)) && "TexCoords buffer length not a multiple of element size"); uvCount = static_cast(bufferSize / (sizeof(uint8_t) * 2)); } else if(MaskMatch(mFlags, S16_TEXCOORD) || MaskMatch(mFlags, U16_TEXCOORD)) { - DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % (sizeof(uint16_t) * 2) == 0) || - mTexCoords.mBlob.mStride >= (sizeof(uint16_t) * 2)) && + DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % (sizeof(uint16_t) * 2) == 0) || + texCoords.mBlob.mStride >= (sizeof(uint16_t) * 2)) && "TexCoords buffer length not a multiple of element size"); uvCount = static_cast(bufferSize / (sizeof(uint16_t) * 2)); } else { - DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) || - mTexCoords.mBlob.mStride >= sizeof(Vector2)) && + DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % sizeof(Vector2) == 0) || + texCoords.mBlob.mStride >= sizeof(Vector2)) && "TexCoords buffer length not a multiple of element size"); uvCount = static_cast(bufferSize / sizeof(Vector2)); } @@ -1192,13 +1227,13 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& std::vector buffer(bufferSize); std::string path; - auto& stream = GetAvailableData(fileStream, meshPath, buffers[mTexCoords.mBufferIdx], path); - if(!ReadAccessor(mTexCoords, stream, buffer.data())) + auto& stream = GetAvailableData(fileStream, meshPath, buffers[texCoords.mBufferIdx], path); + if(!ReadAccessor(texCoords, stream, buffer.data())) { ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << path << "'."; } - GetDequantizedData(buffer, 2u, uvCount, mFlags & TEXCOORDS_MASK, mTexCoords.mNormalized); + GetDequantizedData(buffer, 2u, uvCount, mFlags & TEXCOORDS_MASK, texCoords.mNormalized); if(MaskMatch(mFlags, FLIP_UVS_VERTICAL)) { @@ -1211,13 +1246,12 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& } } - if(mTexCoords.mNormalized) + if(texCoords.mNormalized) { - GetDequantizedMinMax(mTexCoords.mBlob.mMin, mTexCoords.mBlob.mMax, mFlags & TEXCOORDS_MASK); + GetDequantizedMinMax(texCoords.mBlob.mMin, texCoords.mBlob.mMax, mFlags & TEXCOORDS_MASK); } - mTexCoords.mBlob.ApplyMinMax(static_cast(uvCount), reinterpret_cast(buffer.data())); - + texCoords.mBlob.ApplyMinMax(static_cast(uvCount), reinterpret_cast(buffer.data())); raw.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast(uvCount), std::move(buffer)}); } @@ -1297,6 +1331,7 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& GenerateTangents, }, }}; + const bool hasUvs = !mTexCoords.empty() && mTexCoords[0].IsDefined(); const bool generateSuccessed = GenerateTangentsFunction[MaskMatch(mFlags, U32_INDICES)][mTangentType == Property::VECTOR3][hasUvs](raw); if(!generateSuccessed) { @@ -1304,25 +1339,26 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& } } - if(mColors.IsDefined()) + // Only support 1 vertex color + if(!mColors.empty() && mColors[0].IsDefined()) { - uint32_t propertySize = mColors.mBlob.mElementSizeHint; + uint32_t propertySize = mColors[0].mBlob.mElementSizeHint; Property::Type propertyType = (propertySize == sizeof(Vector4)) ? Property::VECTOR4 : ((propertySize == sizeof(Vector3)) ? Property::VECTOR3 : Property::NONE); if(propertyType != Property::NONE) { - DALI_ASSERT_ALWAYS(((mColors.mBlob.mLength % propertySize == 0) || - mColors.mBlob.mStride >= propertySize) && + DALI_ASSERT_ALWAYS(((mColors[0].mBlob.mLength % propertySize == 0) || + mColors[0].mBlob.mStride >= propertySize) && "Colors buffer length not a multiple of element size"); - const auto bufferSize = mColors.mBlob.GetBufferSize(); + const auto bufferSize = mColors[0].mBlob.GetBufferSize(); std::vector buffer(bufferSize); std::string path; - auto& stream = GetAvailableData(fileStream, meshPath, buffers[mColors.mBufferIdx], path); - if(!ReadAccessor(mColors, stream, buffer.data())) + auto& stream = GetAvailableData(fileStream, meshPath, buffers[mColors[0].mBufferIdx], path); + if(!ReadAccessor(mColors[0], stream, buffer.data())) { ExceptionFlinger(ASSERT_LOCATION) << "Failed to read colors from '" << path << "'."; } - mColors.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast(buffer.data())); + mColors[0].mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast(buffer.data())); raw.mAttribs.push_back({"aVertexColor", propertyType, static_cast(bufferSize / propertySize), std::move(buffer)}); } @@ -1342,34 +1378,25 @@ MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& if(IsSkinned()) { - std::string pathJoint; - auto& streamJoint = GetAvailableData(fileStream, meshPath, buffers[mJoints0.mBufferIdx], pathJoint); - if(MaskMatch(mFlags, U16_JOINT_IDS)) - { - ReadJointAccessor(raw, mJoints0, streamJoint, pathJoint); - } - else if(MaskMatch(mFlags, U8_JOINT_IDS)) - { - ReadJointAccessor(raw, mJoints0, streamJoint, pathJoint); - } - else - { - ReadJointAccessor(raw, mJoints0, streamJoint, pathJoint); - } - - std::string pathWeight; - auto& streamWeight = GetAvailableData(fileStream, meshPath, buffers[mWeights0.mBufferIdx], pathWeight); - if(MaskMatch(mFlags, U16_WEIGHT)) - { - ReadWeightAccessor(raw, mWeights0, streamWeight, pathWeight); - } - else if(MaskMatch(mFlags, U8_WEIGHT)) - { - ReadWeightAccessor(raw, mWeights0, streamWeight, pathWeight); - } - else - { - ReadWeightAccessor(raw, mWeights0, streamWeight, pathWeight); + int setIndex = 0; + for(auto& accessor : mJoints) + { + std::string pathJoint; + auto& streamJoint = GetAvailableData(fileStream, meshPath, buffers[accessor.mBufferIdx], pathJoint); + std::ostringstream jointName; + jointName << "aJoints" << setIndex; + ++setIndex; + ReadTypedJointAccessor(raw, mFlags, accessor, streamJoint, pathJoint, jointName.str()); + } + setIndex = 0; + for(auto& accessor : mWeights) + { + std::string pathWeight; + auto& streamWeight = GetAvailableData(fileStream, meshPath, buffers[accessor.mBufferIdx], pathWeight); + std::ostringstream weightName; + weightName << "aWeights" << setIndex; + ++setIndex; + ReadTypedWeightAccessor(raw, mFlags, accessor, streamWeight, pathWeight, weightName.str()); } } diff --git a/dali-scene3d/public-api/loader/mesh-definition.h b/dali-scene3d/public-api/loader/mesh-definition.h index d1016b5..1f3bca5 100644 --- a/dali-scene3d/public-api/loader/mesh-definition.h +++ b/dali-scene3d/public-api/loader/mesh-definition.h @@ -198,10 +198,13 @@ struct DALI_SCENE3D_API MeshDefinition Accessor(const MeshDefinition::Blob& blob, const MeshDefinition::SparseBlob& sparse, - Index bufferIndex = INVALID_INDEX); + Index bufferIndex = INVALID_INDEX, + bool normalized = false); + Accessor(MeshDefinition::Blob&& blob, MeshDefinition::SparseBlob&& sparse, - Index bufferIndex = INVALID_INDEX); + Index bufferIndex = INVALID_INDEX, + bool normalized = false); bool IsDefined() const { @@ -311,12 +314,12 @@ public: // DATA std::string mUri; // When the mesh data is loaded from embedded resources, this URI is used as a data stream. Accessor mIndices; Accessor mPositions; - Accessor mNormals; // data can be generated based on positions - Accessor mTexCoords; - Accessor mColors; + Accessor mNormals; // data can be generated based on positions Accessor mTangents; // data can be generated based on normals and texCoords (the latter isn't mandatory; the results will be better if available) - Accessor mJoints0; - Accessor mWeights0; + std::vector mTexCoords; + std::vector mColors; + std::vector mJoints; + std::vector mWeights; Property::Type mTangentType{Property::VECTOR3}; Blob mBlendShapeHeader; diff --git a/dali-scene3d/public-api/loader/shader-definition.cpp b/dali-scene3d/public-api/loader/shader-definition.cpp index 49ff885..e9975f4 100644 --- a/dali-scene3d/public-api/loader/shader-definition.cpp +++ b/dali-scene3d/public-api/loader/shader-definition.cpp @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include +#include // INTERNAL INCLUDES #include @@ -44,7 +45,7 @@ ShaderDefinition::ShaderDefinition(const ShaderDefinition& other) { } -void ShaderDefinition::ApplyDefine(std::string& shaderCode, const std::string& definevar) +void ApplyDefine(std::string& shaderCode, const std::string& definevar) { const std::string IF_1 = "#if 1"; @@ -79,6 +80,26 @@ void ShaderDefinition::ApplyDefine(std::string& shaderCode, const std::string& d } } +void RedefineMacro(std::string& shaderCode, const std::string& macro, const std::string& value) +{ + std::string definition = "#define " + macro; + std::size_t found = shaderCode.find(definition); + if(found != std::string::npos) + { + std::size_t insertionPoint = found + definition.length(); + + // Automatically insert line-continuation character into value + std::regex re("\n"); + std::sregex_token_iterator first{value.begin(), value.end(), re, -1}, last; + for(auto i = first; i != last; ++i) + { + std::string line = std::string("\\\n") + (*i).str(); + shaderCode.insert(insertionPoint, line); + insertionPoint += line.length(); + } + } +} + ShaderDefinition::RawData ShaderDefinition::LoadRaw(const std::string& shadersPath) const { @@ -117,6 +138,12 @@ ShaderDefinition::LoadRaw(const std::string& shadersPath) const ApplyDefine(raw.mFragmentShaderSource, definevar); ApplyDefine(raw.mShadowVertexShaderSource, definevar); } + for(const auto& macroDef : mMacros) + { + RedefineMacro(raw.mVertexShaderSource, macroDef.macro, macroDef.definition); + RedefineMacro(raw.mFragmentShaderSource, macroDef.macro, macroDef.definition); + RedefineMacro(raw.mShadowVertexShaderSource, macroDef.macro, macroDef.definition); + } } return raw; diff --git a/dali-scene3d/public-api/loader/shader-definition.h b/dali-scene3d/public-api/loader/shader-definition.h index 0fe83d3..f39ac5f 100644 --- a/dali-scene3d/public-api/loader/shader-definition.h +++ b/dali-scene3d/public-api/loader/shader-definition.h @@ -24,6 +24,7 @@ // INTERNAL INCLUDES #include +#include namespace Dali::Scene3D::Loader { @@ -44,17 +45,12 @@ struct DALI_SCENE3D_API ShaderDefinition std::string mShadowFragmentShaderSource; }; - /* - * @brief Apply the defines values to shader. - */ - static void ApplyDefine(std::string& shaderCode, const std::string& definevar); - ShaderDefinition() = default; ShaderDefinition(const ShaderDefinition& other); ShaderDefinition& operator=(const ShaderDefinition& other); - ShaderDefinition(ShaderDefinition&&) = default; + ShaderDefinition(ShaderDefinition&&) = default; ShaderDefinition& operator=(ShaderDefinition&&) = default; /* @@ -76,12 +72,13 @@ public: // DATA std::shared_ptr mRawData; RendererState::Type mRendererState = RendererState::NONE; - std::string mVertexShaderPath; - std::string mFragmentShaderPath; - std::vector mDefines; - std::vector mHints; - Property::Map mUniforms; - bool mUseBuiltInShader{false}; + std::string mVertexShaderPath; + std::string mFragmentShaderPath; + std::vector mDefines; + std::vector mMacros; + std::vector mHints; + Property::Map mUniforms; + bool mUseBuiltInShader{false}; }; } // namespace Dali::Scene3D::Loader diff --git a/dali-scene3d/public-api/loader/shader-manager.cpp b/dali-scene3d/public-api/loader/shader-manager.cpp index c3ef1ce..edb7b64 100644 --- a/dali-scene3d/public-api/loader/shader-manager.cpp +++ b/dali-scene3d/public-api/loader/shader-manager.cpp @@ -38,6 +38,9 @@ namespace static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10; static constexpr uint32_t INDEX_FOR_SHADOW_CONSTRAINT_TAG = 100; +static const char* ADD_EXTRA_SKINNING_ATTRIBUTES{"ADD_EXTRA_SKINNING_ATTRIBUTES"}; +static const char* ADD_EXTRA_WEIGHTS{"ADD_EXTRA_WEIGHTS"}; + ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef) { ShaderOption option; @@ -109,6 +112,27 @@ ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinit if(meshDef.IsSkinned()) { option.AddOption(ShaderOption::Type::SKINNING); + + // Add options for ADD_EXTRA_SKINNING_ATTRIBUTES and ADD_EXTRA_WEIGHTS: + size_t numberOfSets = meshDef.mJoints.size(); + if(numberOfSets > 1) + { + std::ostringstream attributes; + std::ostringstream weights; + for(size_t i = 1; i < numberOfSets; ++i) + { + attributes << "in vec4 aJoints" << i << ";\n"; + attributes << "in vec4 aWeights" << i << ";\n"; + + weights << "bone +=\n" + << "uBone[int(aJoints" << i << ".x)] * aWeights" << i << ".x +\n" + << "uBone[int(aJoints" << i << ".y)] * aWeights" << i << ".y +\n" + << "uBone[int(aJoints" << i << ".z)] * aWeights" << i << ".z +\n" + << "uBone[int(aJoints" << i << ".w)] * aWeights" << i << ".w;\n"; + } + option.AddMacroDefinition(ADD_EXTRA_SKINNING_ATTRIBUTES, attributes.str()); + option.AddMacroDefinition(ADD_EXTRA_WEIGHTS, weights.str()); + } } if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL)) @@ -116,7 +140,7 @@ ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinit option.AddOption(ShaderOption::Type::FLIP_UVS_VERTICAL); } - if(meshDef.mColors.IsDefined()) + if(!meshDef.mColors.empty() && meshDef.mColors[0].IsDefined()) { option.AddOption(ShaderOption::Type::COLOR_ATTRIBUTE); } @@ -199,6 +223,7 @@ Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption) shaderDef.mUseBuiltInShader = true; shaderOption.GetDefines(shaderDef.mDefines); + shaderDef.mMacros = shaderOption.GetMacroDefinitions(); shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY; shaderMap[hash] = mImpl->mShaders.size(); @@ -396,14 +421,12 @@ void ShaderManager::SetShadowConstraintToShader(Dali::Shader shader) std::string shadowViewProjectionPropertyName(Scene3D::Internal::Light::GetShadowViewProjectionMatrixUniformName()); auto shadowViewProjectionPropertyIndex = shader.RegisterProperty(shadowViewProjectionPropertyName, Matrix::IDENTITY); Dali::CameraActor shadowLightCamera = Dali::Scene3D::Internal::GetImplementation(mImpl->mShadowLight).GetCamera(); - auto tempViewProjectionMatrixIndex = shadowLightCamera.GetPropertyIndex("tempViewProjectionMatrix"); + auto tempViewProjectionMatrixIndex = shadowLightCamera.GetPropertyIndex("tempViewProjectionMatrix"); if(tempViewProjectionMatrixIndex != Dali::Property::INVALID_INDEX) { tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY); } - Dali::Constraint shadowViewProjectionConstraint = Dali::Constraint::New(shader, shadowViewProjectionPropertyIndex, [](Matrix& output, const PropertyInputContainer& inputs) - { - output = inputs[0]->GetMatrix(); }); + Dali::Constraint shadowViewProjectionConstraint = Dali::Constraint::New(shader, shadowViewProjectionPropertyIndex, [](Matrix& output, const PropertyInputContainer& inputs) { output = inputs[0]->GetMatrix(); }); shadowViewProjectionConstraint.AddSource(Source{shadowLightCamera, tempViewProjectionMatrixIndex}); shadowViewProjectionConstraint.ApplyPost(); shadowViewProjectionConstraint.SetTag(INDEX_FOR_SHADOW_CONSTRAINT_TAG); diff --git a/dali-scene3d/public-api/loader/shader-option.cpp b/dali-scene3d/public-api/loader/shader-option.cpp index 85489ab..d09195d 100644 --- a/dali-scene3d/public-api/loader/shader-option.cpp +++ b/dali-scene3d/public-api/loader/shader-option.cpp @@ -19,6 +19,7 @@ #include // EXTERNAL INCLUDES +#include #include namespace Dali::Scene3D::Loader @@ -48,8 +49,39 @@ static constexpr std::string_view OPTION_KEYWORD[] = "MORPH_VERSION_2_0", }; static constexpr uint32_t NUMBER_OF_OPTIONS = sizeof(OPTION_KEYWORD) / sizeof(OPTION_KEYWORD[0]); + +inline void HashString(std::uint64_t& hash, const char* string) +{ + char c; + while((c = *string++)) + { + hash = hash * 33 + c; + } +} } // namespace +ShaderOption::ShaderOption(const ShaderOption& rhs) +{ + mOptionHash = rhs.mOptionHash; + for(auto& macroDef : rhs.mMacros) + { + mMacros.emplace_back(macroDef); + } +} + +ShaderOption& ShaderOption::operator=(const ShaderOption& rhs) +{ + if(this != &rhs) + { + mOptionHash = rhs.mOptionHash; + for(auto& macroDef : rhs.mMacros) + { + mMacros.emplace_back(macroDef); + } + } + return *this; +} + void ShaderOption::SetTransparency() { mOptionHash |= (1 << NUMBER_OF_OPTIONS); @@ -60,9 +92,38 @@ void ShaderOption::AddOption(Type shaderOptionType) mOptionHash |= (1 << static_cast(shaderOptionType)); } +void ShaderOption::AddMacroDefinition(std::string macro, std::string definition) +{ + auto iter = std::find_if(mMacros.begin(), mMacros.end(), [macro](ShaderOption::MacroDefinition& md) { return md.macro == macro; }); + if(iter != mMacros.end()) + { + iter->definition = definition; + } + else + { + mMacros.emplace_back(MacroDefinition{macro, definition}); + } +} + +const std::vector& ShaderOption::GetMacroDefinitions() const +{ + return mMacros; +} + uint64_t ShaderOption::GetOptionHash() const { - return mOptionHash; + uint64_t optionHash = mOptionHash; + if(!mMacros.empty()) + { + uint64_t hash = 5381; + for(auto& macroDef : mMacros) + { + HashString(hash, macroDef.macro.c_str()); + HashString(hash, macroDef.definition.c_str()); + } + optionHash |= (hash << 32 & 0xFFFFFFFF00000000); + } + return optionHash; } void ShaderOption::GetDefines(std::vector& defines) const diff --git a/dali-scene3d/public-api/loader/shader-option.h b/dali-scene3d/public-api/loader/shader-option.h index e9d95c2..18fad44 100644 --- a/dali-scene3d/public-api/loader/shader-option.h +++ b/dali-scene3d/public-api/loader/shader-option.h @@ -20,6 +20,7 @@ // EXTERNAL INCLUDER #include #include +#include #include // INTERNAL INCLUDES @@ -27,7 +28,6 @@ namespace Dali::Scene3D::Loader { - class DALI_SCENE3D_API ShaderOption { public: @@ -54,6 +54,16 @@ public: MORPH_VERSION_2_0 }; + struct MacroDefinition + { + std::string macro; + std::string definition; + }; + + ShaderOption() = default; + ShaderOption(const ShaderOption& rhs); + ShaderOption& operator=(const ShaderOption& rhs); + public: /** * @brief Sets transparency option. @@ -69,6 +79,11 @@ public: void AddOption(Type shaderOptionType); /** + * Enables empty preprocessor definitions to be defined to a value + */ + void AddMacroDefinition(std::string macro, std::string definition); + + /** * @brief Retrieves current shader option hash * * @return Hash value of currently added options. @@ -90,8 +105,15 @@ public: */ static std::string_view GetDefineKeyword(Type shaderOptionType); + /** + * Get any macro definitions + */ + const std::vector& GetMacroDefinitions() const; + private: uint64_t mOptionHash{0u}; + + std::vector mMacros; }; } // namespace Dali::Scene3D::Loader -- 2.7.4