2 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-scene3d/internal/loader/gltf2-util.h>
22 #include <dali/devel-api/threading/mutex.h>
23 #include <dali/integration-api/debug.h>
25 using namespace Dali::Scene3D::Loader;
27 namespace Dali::Scene3D::Loader::Internal
31 static constexpr std::string_view MRENDERER_MODEL_IDENTIFICATION = "M-Renderer";
32 static constexpr std::string_view POSITION_PROPERTY = "position";
33 static constexpr std::string_view ORIENTATION_PROPERTY = "orientation";
34 static constexpr std::string_view SCALE_PROPERTY = "scale";
35 static constexpr std::string_view BLEND_SHAPE_WEIGHTS_UNIFORM = "uBlendShapeWeight";
36 static constexpr std::string_view ROOT_NODE_NAME = "RootNode";
37 static const Vector3 SCALE_TO_ADJUST(100.0f, 100.0f, 100.0f);
39 static const Geometry::Type GLTF2_TO_DALI_PRIMITIVES[]{
45 Geometry::TRIANGLE_STRIP,
46 Geometry::TRIANGLE_FAN}; //...because Dali swaps the last two.
48 static struct AttributeMapping
50 gltf2::Attribute::Type mType;
51 MeshDefinition::Accessor MeshDefinition::*mAccessor;
52 uint16_t mElementSizeRequired;
53 } ATTRIBUTE_MAPPINGS[]{
54 {gltf2::Attribute::NORMAL, &MeshDefinition::mNormals, sizeof(Vector3)},
55 {gltf2::Attribute::TANGENT, &MeshDefinition::mTangents, sizeof(Vector3)},
56 {gltf2::Attribute::TEXCOORD_0, &MeshDefinition::mTexCoords, sizeof(Vector2)},
57 {gltf2::Attribute::COLOR_0, &MeshDefinition::mColors, sizeof(Vector4)},
58 {gltf2::Attribute::JOINTS_0, &MeshDefinition::mJoints0, sizeof(Vector4)},
59 {gltf2::Attribute::WEIGHTS_0, &MeshDefinition::mWeights0, sizeof(Vector4)},
62 std::vector<gltf2::Animation> ReadAnimationArray(const json_value_s& j)
64 auto results = json::Read::Array<gltf2::Animation, json::ObjectReader<gltf2::Animation>::Read>(j);
66 for(auto& animation : results)
68 for(auto& channel : animation.mChannels)
70 channel.mSampler.UpdateVector(animation.mSamplers);
77 void ApplyAccessorMinMax(const gltf2::Accessor& accessor, float* values)
79 DALI_ASSERT_ALWAYS(accessor.mMax.empty() || gltf2::AccessorType::ElementCount(accessor.mType) == accessor.mMax.size());
80 DALI_ASSERT_ALWAYS(accessor.mMin.empty() || gltf2::AccessorType::ElementCount(accessor.mType) == accessor.mMin.size());
81 MeshDefinition::Blob::ApplyMinMax(accessor.mMin, accessor.mMax, accessor.mCount, values);
84 const json::Reader<gltf2::Buffer>& GetBufferReader()
86 static const auto BUFFER_READER = std::move(json::Reader<gltf2::Buffer>()
87 .Register(*json::MakeProperty("byteLength", json::Read::Number<uint32_t>, &gltf2::Buffer::mByteLength))
88 .Register(*json::MakeProperty("uri", json::Read::StringView, &gltf2::Buffer::mUri)));
92 const json::Reader<gltf2::BufferView>& GetBufferViewReader()
94 static const auto BUFFER_VIEW_READER = std::move(json::Reader<gltf2::BufferView>()
95 .Register(*json::MakeProperty("buffer", gltf2::RefReader<gltf2::Document>::Read<gltf2::Buffer, &gltf2::Document::mBuffers>, &gltf2::BufferView::mBuffer))
96 .Register(*json::MakeProperty("byteOffset", json::Read::Number<uint32_t>, &gltf2::BufferView::mByteOffset))
97 .Register(*json::MakeProperty("byteLength", json::Read::Number<uint32_t>, &gltf2::BufferView::mByteLength))
98 .Register(*json::MakeProperty("byteStride", json::Read::Number<uint32_t>, &gltf2::BufferView::mByteStride))
99 .Register(*json::MakeProperty("target", json::Read::Number<uint32_t>, &gltf2::BufferView::mTarget)));
100 return BUFFER_VIEW_READER;
103 const json::Reader<gltf2::BufferViewClient>& GetBufferViewClientReader()
105 static const auto BUFFER_VIEW_CLIENT_READER = std::move(json::Reader<gltf2::BufferViewClient>()
106 .Register(*json::MakeProperty("bufferView", gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>, &gltf2::BufferViewClient::mBufferView))
107 .Register(*json::MakeProperty("byteOffset", json::Read::Number<uint32_t>, &gltf2::BufferViewClient::mByteOffset)));
108 return BUFFER_VIEW_CLIENT_READER;
111 const json::Reader<gltf2::ComponentTypedBufferViewClient>& GetComponentTypedBufferViewClientReader()
113 static const auto COMPONENT_TYPED_BUFFER_VIEW_CLIENT_READER = std::move(json::Reader<gltf2::ComponentTypedBufferViewClient>()
114 .Register(*new json::Property<gltf2::ComponentTypedBufferViewClient, gltf2::Ref<gltf2::BufferView>>("bufferView", gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>, &gltf2::ComponentTypedBufferViewClient::mBufferView))
115 .Register(*new json::Property<gltf2::ComponentTypedBufferViewClient, uint32_t>("byteOffset", json::Read::Number<uint32_t>, &gltf2::ComponentTypedBufferViewClient::mByteOffset))
116 .Register(*json::MakeProperty("componentType", json::Read::Enum<gltf2::Component::Type>, &gltf2::ComponentTypedBufferViewClient::mComponentType)));
117 return COMPONENT_TYPED_BUFFER_VIEW_CLIENT_READER;
120 const json::Reader<gltf2::Accessor::Sparse>& GetAccessorSparseReader()
122 static const auto ACCESSOR_SPARSE_READER = std::move(json::Reader<gltf2::Accessor::Sparse>()
123 .Register(*json::MakeProperty("count", json::Read::Number<uint32_t>, &gltf2::Accessor::Sparse::mCount))
124 .Register(*json::MakeProperty("indices", json::ObjectReader<gltf2::ComponentTypedBufferViewClient>::Read, &gltf2::Accessor::Sparse::mIndices))
125 .Register(*json::MakeProperty("values", json::ObjectReader<gltf2::BufferViewClient>::Read, &gltf2::Accessor::Sparse::mValues)));
126 return ACCESSOR_SPARSE_READER;
129 const json::Reader<gltf2::Accessor>& GetAccessorReader()
131 static const auto ACCESSOR_READER = std::move(json::Reader<gltf2::Accessor>()
132 .Register(*new json::Property<gltf2::Accessor, gltf2::Ref<gltf2::BufferView>>("bufferView",
133 gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>,
134 &gltf2::Accessor::mBufferView))
135 .Register(*new json::Property<gltf2::Accessor, uint32_t>("byteOffset",
136 json::Read::Number<uint32_t>,
137 &gltf2::Accessor::mByteOffset))
138 .Register(*new json::Property<gltf2::Accessor, gltf2::Component::Type>("componentType",
139 json::Read::Enum<gltf2::Component::Type>,
140 &gltf2::Accessor::mComponentType))
141 .Register(*new json::Property<gltf2::Accessor, std::string_view>("name", json::Read::StringView, &gltf2::Accessor::mName))
142 .Register(*json::MakeProperty("count", json::Read::Number<uint32_t>, &gltf2::Accessor::mCount))
143 .Register(*json::MakeProperty("normalized", json::Read::Boolean, &gltf2::Accessor::mNormalized))
144 .Register(*json::MakeProperty("type", gltf2::ReadStringEnum<gltf2::AccessorType>, &gltf2::Accessor::mType))
145 .Register(*json::MakeProperty("min", json::Read::Array<float, json::Read::Number>, &gltf2::Accessor::mMin))
146 .Register(*json::MakeProperty("max", json::Read::Array<float, json::Read::Number>, &gltf2::Accessor::mMax))
147 .Register(*new json::Property<gltf2::Accessor, gltf2::Accessor::Sparse>("sparse", json::ObjectReader<gltf2::Accessor::Sparse>::Read, &gltf2::Accessor::SetSparse)));
148 return ACCESSOR_READER;
151 const json::Reader<gltf2::Image>& GetImageReader()
153 static const auto IMAGE_READER = std::move(json::Reader<gltf2::Image>()
154 .Register(*new json::Property<gltf2::Image, std::string_view>("name", json::Read::StringView, &gltf2::Material::mName))
155 .Register(*json::MakeProperty("uri", json::Read::StringView, &gltf2::Image::mUri))
156 .Register(*json::MakeProperty("mimeType", json::Read::StringView, &gltf2::Image::mMimeType))
157 .Register(*json::MakeProperty("bufferView", gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>, &gltf2::Image::mBufferView)));
161 const json::Reader<gltf2::Sampler>& GetSamplerReader()
163 static const auto SAMPLER_READER = std::move(json::Reader<gltf2::Sampler>()
164 .Register(*json::MakeProperty("minFilter", json::Read::Enum<gltf2::Filter::Type>, &gltf2::Sampler::mMinFilter))
165 .Register(*json::MakeProperty("magFilter", json::Read::Enum<gltf2::Filter::Type>, &gltf2::Sampler::mMagFilter))
166 .Register(*json::MakeProperty("wrapS", json::Read::Enum<gltf2::Wrap::Type>, &gltf2::Sampler::mWrapS))
167 .Register(*json::MakeProperty("wrapT", json::Read::Enum<gltf2::Wrap::Type>, &gltf2::Sampler::mWrapT)));
168 return SAMPLER_READER;
171 const json::Reader<gltf2::Texture>& GetTextureReader()
173 static const auto TEXURE_READER = std::move(json::Reader<gltf2::Texture>()
174 .Register(*json::MakeProperty("source", gltf2::RefReader<gltf2::Document>::Read<gltf2::Image, &gltf2::Document::mImages>, &gltf2::Texture::mSource))
175 .Register(*json::MakeProperty("sampler", gltf2::RefReader<gltf2::Document>::Read<gltf2::Sampler, &gltf2::Document::mSamplers>, &gltf2::Texture::mSampler)));
176 return TEXURE_READER;
179 const json::Reader<gltf2::TextureInfo>& GetTextureInfoReader()
181 static const auto TEXURE_INFO_READER = std::move(json::Reader<gltf2::TextureInfo>()
182 .Register(*json::MakeProperty("index", gltf2::RefReader<gltf2::Document>::Read<gltf2::Texture, &gltf2::Document::mTextures>, &gltf2::TextureInfo::mTexture))
183 .Register(*json::MakeProperty("texCoord", json::Read::Number<uint32_t>, &gltf2::TextureInfo::mTexCoord))
184 .Register(*json::MakeProperty("scale", json::Read::Number<float>, &gltf2::TextureInfo::mScale))
185 .Register(*json::MakeProperty("strength", json::Read::Number<float>, &gltf2::TextureInfo::mStrength)));
186 return TEXURE_INFO_READER;
189 const json::Reader<gltf2::Material::Pbr>& GetMaterialPbrReader()
191 static const auto MATERIAL_PBR_READER = std::move(json::Reader<gltf2::Material::Pbr>()
192 .Register(*json::MakeProperty("baseColorFactor", gltf2::ReadDaliVector<Vector4>, &gltf2::Material::Pbr::mBaseColorFactor))
193 .Register(*json::MakeProperty("baseColorTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::Pbr::mBaseColorTexture))
194 .Register(*json::MakeProperty("metallicFactor", json::Read::Number<float>, &gltf2::Material::Pbr::mMetallicFactor))
195 .Register(*json::MakeProperty("roughnessFactor", json::Read::Number<float>, &gltf2::Material::Pbr::mRoughnessFactor))
196 .Register(*json::MakeProperty("metallicRoughnessTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::Pbr::mMetallicRoughnessTexture)));
197 return MATERIAL_PBR_READER;
200 const json::Reader<gltf2::MaterialSpecular>& GetMaterialSpecularReader()
202 static const auto MATERIAL_SPECULAR_READER = std::move(json::Reader<gltf2::MaterialSpecular>()
203 .Register(*json::MakeProperty("specularFactor", json::Read::Number<float>, &gltf2::MaterialSpecular::mSpecularFactor))
204 .Register(*json::MakeProperty("specularTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::MaterialSpecular::mSpecularTexture))
205 .Register(*json::MakeProperty("specularColorFactor", gltf2::ReadDaliVector<Vector3>, &gltf2::MaterialSpecular::mSpecularColorFactor))
206 .Register(*json::MakeProperty("specularColorTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::MaterialSpecular::mSpecularColorTexture)));
207 return MATERIAL_SPECULAR_READER;
210 const json::Reader<gltf2::MaterialIor>& GetMaterialIorReader()
212 static const auto MATERIAL_IOR_READER = std::move(json::Reader<gltf2::MaterialIor>()
213 .Register(*json::MakeProperty("ior", json::Read::Number<float>, &gltf2::MaterialIor::mIor)));
214 return MATERIAL_IOR_READER;
217 const json::Reader<gltf2::MaterialExtensions>& GetMaterialExtensionsReader()
219 static const auto MATERIAL_EXTENSION_READER = std::move(json::Reader<gltf2::MaterialExtensions>()
220 .Register(*json::MakeProperty("KHR_materials_ior", json::ObjectReader<gltf2::MaterialIor>::Read, &gltf2::MaterialExtensions::mMaterialIor))
221 .Register(*json::MakeProperty("KHR_materials_specular", json::ObjectReader<gltf2::MaterialSpecular>::Read, &gltf2::MaterialExtensions::mMaterialSpecular)));
222 return MATERIAL_EXTENSION_READER;
225 const json::Reader<gltf2::Material>& GetMaterialReader()
227 static const auto MATERIAL_READER = std::move(json::Reader<gltf2::Material>()
228 .Register(*new json::Property<gltf2::Material, std::string_view>("name", json::Read::StringView, &gltf2::Material::mName))
229 .Register(*json::MakeProperty("pbrMetallicRoughness", json::ObjectReader<gltf2::Material::Pbr>::Read, &gltf2::Material::mPbrMetallicRoughness))
230 .Register(*json::MakeProperty("normalTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::mNormalTexture))
231 .Register(*json::MakeProperty("occlusionTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::mOcclusionTexture))
232 .Register(*json::MakeProperty("emissiveTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::mEmissiveTexture))
233 .Register(*json::MakeProperty("emissiveFactor", gltf2::ReadDaliVector<Vector3>, &gltf2::Material::mEmissiveFactor))
234 .Register(*json::MakeProperty("alphaMode", gltf2::ReadStringEnum<gltf2::AlphaMode>, &gltf2::Material::mAlphaMode))
235 .Register(*json::MakeProperty("alphaCutoff", json::Read::Number<float>, &gltf2::Material::mAlphaCutoff))
236 .Register(*json::MakeProperty("doubleSided", json::Read::Boolean, &gltf2::Material::mDoubleSided))
237 .Register(*json::MakeProperty("extensions", json::ObjectReader<gltf2::MaterialExtensions>::Read, &gltf2::Material::mMaterialExtensions)));
238 return MATERIAL_READER;
241 std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes(const json_value_s& j)
243 auto& jsonObject = json::Cast<json_object_s>(j);
244 std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> result;
246 auto element = jsonObject.start;
249 auto jsonString = *element->name;
250 result[gltf2::Attribute::FromString(jsonString.string, jsonString.string_size)] = gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
251 element = element->next;
256 std::vector<std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>>> ReadMeshPrimitiveTargets(const json_value_s& j)
258 auto& jsonObject = json::Cast<json_array_s>(j);
259 std::vector<std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>>> result;
261 result.reserve(jsonObject.length);
263 auto element = jsonObject.start;
266 result.push_back(std::move(ReadMeshPrimitiveAttributes(*element->value)));
267 element = element->next;
273 const json::Reader<gltf2::Mesh::Primitive>& GetMeshPrimitiveReader()
275 static const auto MESH_PRIMITIVE_READER = std::move(json::Reader<gltf2::Mesh::Primitive>()
276 .Register(*json::MakeProperty("attributes", ReadMeshPrimitiveAttributes, &gltf2::Mesh::Primitive::mAttributes))
277 .Register(*json::MakeProperty("indices", gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>, &gltf2::Mesh::Primitive::mIndices))
278 .Register(*json::MakeProperty("material", gltf2::RefReader<gltf2::Document>::Read<gltf2::Material, &gltf2::Document::mMaterials>, &gltf2::Mesh::Primitive::mMaterial))
279 .Register(*json::MakeProperty("mode", json::Read::Enum<gltf2::Mesh::Primitive::Mode>, &gltf2::Mesh::Primitive::mMode))
280 .Register(*json::MakeProperty("targets", ReadMeshPrimitiveTargets, &gltf2::Mesh::Primitive::mTargets)));
281 return MESH_PRIMITIVE_READER;
284 const json::Reader<gltf2::Mesh>& GetMeshReader()
286 static const auto MESH_READER = std::move(json::Reader<gltf2::Mesh>()
287 .Register(*new json::Property<gltf2::Mesh, std::string_view>("name", json::Read::StringView, &gltf2::Mesh::mName))
288 .Register(*json::MakeProperty("primitives",
289 json::Read::Array<gltf2::Mesh::Primitive, json::ObjectReader<gltf2::Mesh::Primitive>::Read>,
290 &gltf2::Mesh::mPrimitives))
291 .Register(*json::MakeProperty("weights", json::Read::Array<float, json::Read::Number>, &gltf2::Mesh::mWeights)));
295 const json::Reader<gltf2::Skin>& GetSkinReader()
297 static const auto SKIN_READER = std::move(json::Reader<gltf2::Skin>()
298 .Register(*new json::Property<gltf2::Skin, std::string_view>("name", json::Read::StringView, &gltf2::Skin::mName))
299 .Register(*json::MakeProperty("inverseBindMatrices",
300 gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>,
301 &gltf2::Skin::mInverseBindMatrices))
302 .Register(*json::MakeProperty("skeleton",
303 gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>,
304 &gltf2::Skin::mSkeleton))
305 .Register(*json::MakeProperty("joints",
306 json::Read::Array<gltf2::Ref<gltf2::Node>, gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>>,
307 &gltf2::Skin::mJoints)));
311 const json::Reader<gltf2::Camera::Perspective>& GetCameraPerspectiveReader()
313 static const auto CAMERA_PERSPECTIVE_READER = std::move(json::Reader<gltf2::Camera::Perspective>()
314 .Register(*json::MakeProperty("aspectRatio", json::Read::Number<float>, &gltf2::Camera::Perspective::mAspectRatio))
315 .Register(*json::MakeProperty("yfov", json::Read::Number<float>, &gltf2::Camera::Perspective::mYFov))
316 .Register(*json::MakeProperty("zfar", json::Read::Number<float>, &gltf2::Camera::Perspective::mZFar))
317 .Register(*json::MakeProperty("znear", json::Read::Number<float>, &gltf2::Camera::Perspective::mZNear))); // TODO: infinite perspective projection, where znear is omitted
318 return CAMERA_PERSPECTIVE_READER;
321 const json::Reader<gltf2::Camera::Orthographic>& GetCameraOrthographicReader()
323 static const auto CAMERA_ORTHOGRAPHIC_READER = std::move(json::Reader<gltf2::Camera::Orthographic>()
324 .Register(*json::MakeProperty("xmag", json::Read::Number<float>, &gltf2::Camera::Orthographic::mXMag))
325 .Register(*json::MakeProperty("ymag", json::Read::Number<float>, &gltf2::Camera::Orthographic::mYMag))
326 .Register(*json::MakeProperty("zfar", json::Read::Number<float>, &gltf2::Camera::Orthographic::mZFar))
327 .Register(*json::MakeProperty("znear", json::Read::Number<float>, &gltf2::Camera::Orthographic::mZNear)));
328 return CAMERA_ORTHOGRAPHIC_READER;
331 const json::Reader<gltf2::Camera>& GetCameraReader()
333 static const auto CAMERA_READER = std::move(json::Reader<gltf2::Camera>()
334 .Register(*new json::Property<gltf2::Camera, std::string_view>("name", json::Read::StringView, &gltf2::Camera::mName))
335 .Register(*json::MakeProperty("type", json::Read::StringView, &gltf2::Camera::mType))
336 .Register(*json::MakeProperty("perspective", json::ObjectReader<gltf2::Camera::Perspective>::Read, &gltf2::Camera::mPerspective))
337 .Register(*json::MakeProperty("orthographic", json::ObjectReader<gltf2::Camera::Orthographic>::Read, &gltf2::Camera::mOrthographic)));
338 return CAMERA_READER;
341 const json::Reader<gltf2::Node>& GetNodeReader()
343 static const auto NODE_READER = std::move(json::Reader<gltf2::Node>()
344 .Register(*new json::Property<gltf2::Node, std::string_view>("name", json::Read::StringView, &gltf2::Node::mName))
345 .Register(*json::MakeProperty("translation", gltf2::ReadDaliVector<Vector3>, &gltf2::Node::mTranslation))
346 .Register(*json::MakeProperty("rotation", gltf2::ReadQuaternion, &gltf2::Node::mRotation))
347 .Register(*json::MakeProperty("scale", gltf2::ReadDaliVector<Vector3>, &gltf2::Node::mScale))
348 .Register(*new json::Property<gltf2::Node, Matrix>("matrix", gltf2::ReadDaliVector<Matrix>, &gltf2::Node::SetMatrix))
349 .Register(*json::MakeProperty("camera", gltf2::RefReader<gltf2::Document>::Read<gltf2::Camera, &gltf2::Document::mCameras>, &gltf2::Node::mCamera))
350 .Register(*json::MakeProperty("children", json::Read::Array<gltf2::Ref<gltf2::Node>, gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>>, &gltf2::Node::mChildren))
351 .Register(*json::MakeProperty("mesh", gltf2::RefReader<gltf2::Document>::Read<gltf2::Mesh, &gltf2::Document::mMeshes>, &gltf2::Node::mMesh))
352 .Register(*json::MakeProperty("skin", gltf2::RefReader<gltf2::Document>::Read<gltf2::Skin, &gltf2::Document::mSkins>, &gltf2::Node::mSkin)));
356 const json::Reader<gltf2::Animation::Sampler>& GetAnimationSamplerReader()
358 static const auto ANIMATION_SAMPLER_READER = std::move(json::Reader<gltf2::Animation::Sampler>()
359 .Register(*json::MakeProperty("input", gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>, &gltf2::Animation::Sampler::mInput))
360 .Register(*json::MakeProperty("output", gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>, &gltf2::Animation::Sampler::mOutput))
361 .Register(*json::MakeProperty("interpolation", gltf2::ReadStringEnum<gltf2::Animation::Sampler::Interpolation>, &gltf2::Animation::Sampler::mInterpolation)));
362 return ANIMATION_SAMPLER_READER;
365 const json::Reader<gltf2::Animation::Channel::Target>& GetAnimationChannelTargetReader()
367 static const auto ANIMATION_TARGET_READER = std::move(json::Reader<gltf2::Animation::Channel::Target>()
368 .Register(*json::MakeProperty("node", gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>, &gltf2::Animation::Channel::Target::mNode))
369 .Register(*json::MakeProperty("path", gltf2::ReadStringEnum<gltf2::Animation::Channel::Target>, &gltf2::Animation::Channel::Target::mPath)));
370 return ANIMATION_TARGET_READER;
373 const json::Reader<gltf2::Animation::Channel>& GetAnimationChannelReader()
375 static const auto ANIMATION_CHANNEL_READER = std::move(json::Reader<gltf2::Animation::Channel>()
376 .Register(*json::MakeProperty("target", json::ObjectReader<gltf2::Animation::Channel::Target>::Read, &gltf2::Animation::Channel::mTarget))
377 .Register(*json::MakeProperty("sampler", gltf2::RefReader<gltf2::Animation>::Read<gltf2::Animation::Sampler, &gltf2::Animation::mSamplers>, &gltf2::Animation::Channel::mSampler)));
378 return ANIMATION_CHANNEL_READER;
381 const json::Reader<gltf2::Animation>& GetAnimationReader()
383 static const auto ANIMATION_READER = std::move(json::Reader<gltf2::Animation>()
384 .Register(*new json::Property<gltf2::Animation, std::string_view>("name", json::Read::StringView, &gltf2::Animation::mName))
385 .Register(*json::MakeProperty("samplers",
386 json::Read::Array<gltf2::Animation::Sampler, json::ObjectReader<gltf2::Animation::Sampler>::Read>,
387 &gltf2::Animation::mSamplers))
388 .Register(*json::MakeProperty("channels",
389 json::Read::Array<gltf2::Animation::Channel, json::ObjectReader<gltf2::Animation::Channel>::Read>,
390 &gltf2::Animation::mChannels)));
391 return ANIMATION_READER;
394 const json::Reader<gltf2::Scene>& GetSceneReader()
396 static const auto SCENE_READER = std::move(json::Reader<gltf2::Scene>()
397 .Register(*new json::Property<gltf2::Scene, std::string_view>("name", json::Read::StringView, &gltf2::Scene::mName))
398 .Register(*json::MakeProperty("nodes",
399 json::Read::Array<gltf2::Ref<gltf2::Node>, gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>>,
400 &gltf2::Scene::mNodes)));
404 const json::Reader<gltf2::Document>& GetDocumentReader()
406 static const auto DOCUMENT_READER = std::move(json::Reader<gltf2::Document>()
407 .Register(*json::MakeProperty("buffers",
408 json::Read::Array<gltf2::Buffer, json::ObjectReader<gltf2::Buffer>::Read>,
409 &gltf2::Document::mBuffers))
410 .Register(*json::MakeProperty("bufferViews",
411 json::Read::Array<gltf2::BufferView, json::ObjectReader<gltf2::BufferView>::Read>,
412 &gltf2::Document::mBufferViews))
413 .Register(*json::MakeProperty("accessors",
414 json::Read::Array<gltf2::Accessor, json::ObjectReader<gltf2::Accessor>::Read>,
415 &gltf2::Document::mAccessors))
416 .Register(*json::MakeProperty("images",
417 json::Read::Array<gltf2::Image, json::ObjectReader<gltf2::Image>::Read>,
418 &gltf2::Document::mImages))
419 .Register(*json::MakeProperty("samplers",
420 json::Read::Array<gltf2::Sampler, json::ObjectReader<gltf2::Sampler>::Read>,
421 &gltf2::Document::mSamplers))
422 .Register(*json::MakeProperty("textures",
423 json::Read::Array<gltf2::Texture, json::ObjectReader<gltf2::Texture>::Read>,
424 &gltf2::Document::mTextures))
425 .Register(*json::MakeProperty("materials",
426 json::Read::Array<gltf2::Material, json::ObjectReader<gltf2::Material>::Read>,
427 &gltf2::Document::mMaterials))
428 .Register(*json::MakeProperty("meshes",
429 json::Read::Array<gltf2::Mesh, json::ObjectReader<gltf2::Mesh>::Read>,
430 &gltf2::Document::mMeshes))
431 .Register(*json::MakeProperty("skins",
432 json::Read::Array<gltf2::Skin, json::ObjectReader<gltf2::Skin>::Read>,
433 &gltf2::Document::mSkins))
434 .Register(*json::MakeProperty("cameras",
435 json::Read::Array<gltf2::Camera, json::ObjectReader<gltf2::Camera>::Read>,
436 &gltf2::Document::mCameras))
437 .Register(*json::MakeProperty("nodes",
438 json::Read::Array<gltf2::Node, json::ObjectReader<gltf2::Node>::Read>,
439 &gltf2::Document::mNodes))
440 .Register(*json::MakeProperty("animations",
442 &gltf2::Document::mAnimations))
443 .Register(*json::MakeProperty("scenes",
444 json::Read::Array<gltf2::Scene, json::ObjectReader<gltf2::Scene>::Read>,
445 &gltf2::Document::mScenes))
446 .Register(*json::MakeProperty("scene", gltf2::RefReader<gltf2::Document>::Read<gltf2::Scene, &gltf2::Document::mScenes>, &gltf2::Document::mScene)));
447 return DOCUMENT_READER;
450 void ConvertBuffer(const gltf2::Buffer& buffer, decltype(ResourceBundle::mBuffers)& outBuffers, const std::string& resourcePath)
452 BufferDefinition bufferDefinition;
454 bufferDefinition.mResourcePath = resourcePath;
455 bufferDefinition.mUri = buffer.mUri;
456 bufferDefinition.mByteLength = buffer.mByteLength;
458 outBuffers.emplace_back(std::move(bufferDefinition));
461 void ConvertBuffers(const gltf2::Document& document, ConversionContext& context)
463 auto& outBuffers = context.mOutput.mResources.mBuffers;
464 outBuffers.reserve(document.mBuffers.size());
466 for(auto& buffer : document.mBuffers)
468 if(buffer.mUri.empty())
472 ConvertBuffer(buffer, outBuffers, context.mPath);
476 SamplerFlags::Type ConvertWrapMode(gltf2::Wrap::Type wrapMode)
480 case gltf2::Wrap::REPEAT:
481 return SamplerFlags::WRAP_REPEAT;
482 case gltf2::Wrap::CLAMP_TO_EDGE:
483 return SamplerFlags::WRAP_CLAMP;
484 case gltf2::Wrap::MIRRORED_REPEAT:
485 return SamplerFlags::WRAP_MIRROR;
487 throw std::runtime_error("Invalid wrap type.");
491 SamplerFlags::Type ConvertSampler(const gltf2::Ref<gltf2::Sampler>& sampler)
495 return ((sampler->mMinFilter < gltf2::Filter::NEAREST_MIPMAP_NEAREST) ? (sampler->mMinFilter - gltf2::Filter::NEAREST) : ((sampler->mMinFilter - gltf2::Filter::NEAREST_MIPMAP_NEAREST) + 2)) |
496 ((sampler->mMagFilter - gltf2::Filter::NEAREST) << SamplerFlags::FILTER_MAG_SHIFT) |
497 (ConvertWrapMode(sampler->mWrapS) << SamplerFlags::WRAP_S_SHIFT) |
498 (ConvertWrapMode(sampler->mWrapT) << SamplerFlags::WRAP_T_SHIFT);
502 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#texturesampler
503 // "The index of the sampler used by this texture. When undefined, a sampler with repeat wrapping and auto filtering should be used."
504 // "What is an auto filtering", I hear you ask. Since there's nothing else to determine mipmapping from - including glTF image
505 // properties, if not in some extension -, we will simply assume linear filtering.
506 return SamplerFlags::FILTER_LINEAR | (SamplerFlags::FILTER_LINEAR << SamplerFlags::FILTER_MAG_SHIFT) |
507 (SamplerFlags::WRAP_REPEAT << SamplerFlags::WRAP_S_SHIFT) | (SamplerFlags::WRAP_REPEAT << SamplerFlags::WRAP_T_SHIFT);
511 TextureDefinition ConvertTextureInfo(const gltf2::TextureInfo& textureInfo, ConversionContext& context, const ImageMetadata& metaData = ImageMetadata())
513 TextureDefinition textureDefinition;
514 std::string uri = std::string(textureInfo.mTexture->mSource->mUri);
517 uint32_t bufferIndex = textureInfo.mTexture->mSource->mBufferView->mBuffer.GetIndex();
518 if(bufferIndex != INVALID_INDEX && context.mOutput.mResources.mBuffers[bufferIndex].IsAvailable())
520 auto& stream = context.mOutput.mResources.mBuffers[bufferIndex].GetBufferStream();
522 stream.seekg(textureInfo.mTexture->mSource->mBufferView->mByteOffset, stream.beg);
523 std::vector<uint8_t> dataBuffer;
524 dataBuffer.resize(textureInfo.mTexture->mSource->mBufferView->mByteLength);
525 stream.read(reinterpret_cast<char*>(dataBuffer.data()), static_cast<std::streamsize>(static_cast<size_t>(textureInfo.mTexture->mSource->mBufferView->mByteLength)));
526 return TextureDefinition{std::move(dataBuffer), ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode};
528 return TextureDefinition();
532 return TextureDefinition{uri, ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode};
536 void AddTextureStage(uint32_t semantic, MaterialDefinition& materialDefinition, gltf2::TextureInfo textureInfo, const Dali::Scene3D::Loader::ImageMetadata& metaData, ConversionContext& context)
538 materialDefinition.mTextureStages.push_back({semantic, ConvertTextureInfo(textureInfo, context, metaData)});
539 materialDefinition.mFlags |= semantic;
542 void ConvertMaterial(const gltf2::Material& material, const std::unordered_map<std::string, ImageMetadata>& imageMetaData, decltype(ResourceBundle::mMaterials)& outMaterials, ConversionContext& context)
544 auto getTextureMetaData = [](const std::unordered_map<std::string, ImageMetadata>& metaData, const gltf2::TextureInfo& info)
546 if(!info.mTexture->mSource->mUri.empty())
548 if(auto search = metaData.find(info.mTexture->mSource->mUri.data()); search != metaData.end())
550 return search->second;
553 return ImageMetadata();
556 MaterialDefinition materialDefinition;
558 auto& pbr = material.mPbrMetallicRoughness;
559 if(material.mAlphaMode == gltf2::AlphaMode::BLEND)
561 materialDefinition.mAlphaModeType = Scene3D::Material::AlphaModeType::BLEND;
562 materialDefinition.mIsOpaque = false;
563 materialDefinition.mFlags |= MaterialDefinition::TRANSPARENCY;
565 else if(material.mAlphaMode == gltf2::AlphaMode::MASK)
567 materialDefinition.mAlphaModeType = Scene3D::Material::AlphaModeType::MASK;
568 materialDefinition.mIsMask = true;
569 materialDefinition.SetAlphaCutoff(std::min(1.f, std::max(0.f, material.mAlphaCutoff)));
572 materialDefinition.mBaseColorFactor = pbr.mBaseColorFactor;
574 materialDefinition.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!material.mNormalTexture + !!material.mOcclusionTexture + !!material.mEmissiveTexture);
575 if(pbr.mBaseColorTexture)
577 AddTextureStage(MaterialDefinition::ALBEDO, materialDefinition, pbr.mBaseColorTexture, getTextureMetaData(imageMetaData, pbr.mBaseColorTexture), context);
581 materialDefinition.mNeedAlbedoTexture = false;
584 materialDefinition.mMetallic = pbr.mMetallicFactor;
585 materialDefinition.mRoughness = pbr.mRoughnessFactor;
587 if(pbr.mMetallicRoughnessTexture)
589 AddTextureStage(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
591 pbr.mMetallicRoughnessTexture,
592 getTextureMetaData(imageMetaData, pbr.mMetallicRoughnessTexture),
597 materialDefinition.mNeedMetallicRoughnessTexture = false;
600 materialDefinition.mNormalScale = material.mNormalTexture.mScale;
601 if(material.mNormalTexture)
603 AddTextureStage(MaterialDefinition::NORMAL, materialDefinition, material.mNormalTexture, getTextureMetaData(imageMetaData, material.mNormalTexture), context);
607 materialDefinition.mNeedNormalTexture = false;
610 if(material.mOcclusionTexture)
612 AddTextureStage(MaterialDefinition::OCCLUSION, materialDefinition, material.mOcclusionTexture, getTextureMetaData(imageMetaData, material.mOcclusionTexture), context);
613 materialDefinition.mOcclusionStrength = material.mOcclusionTexture.mStrength;
616 materialDefinition.mEmissiveFactor = material.mEmissiveFactor;
617 if(material.mEmissiveTexture)
619 AddTextureStage(MaterialDefinition::EMISSIVE, materialDefinition, material.mEmissiveTexture, getTextureMetaData(imageMetaData, material.mEmissiveTexture), context);
622 if(!Dali::Equals(material.mMaterialExtensions.mMaterialIor.mIor, gltf2::UNDEFINED_FLOAT_VALUE))
624 materialDefinition.mIor = material.mMaterialExtensions.mMaterialIor.mIor;
625 materialDefinition.mDielectricSpecular = powf((materialDefinition.mIor - 1.0f) / (materialDefinition.mIor + 1.0f), 2.0f);
627 materialDefinition.mSpecularFactor = material.mMaterialExtensions.mMaterialSpecular.mSpecularFactor;
628 materialDefinition.mSpecularColorFactor = material.mMaterialExtensions.mMaterialSpecular.mSpecularColorFactor;
630 if(material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture)
632 AddTextureStage(MaterialDefinition::SPECULAR, materialDefinition, material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture), context);
635 if(material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture)
637 AddTextureStage(MaterialDefinition::SPECULAR_COLOR, materialDefinition, material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture), context);
640 materialDefinition.mDoubleSided = material.mDoubleSided;
642 outMaterials.emplace_back(std::move(materialDefinition), TextureSet());
645 void ConvertMaterials(const gltf2::Document& document, ConversionContext& context)
647 auto& imageMetaData = context.mOutput.mSceneMetadata.mImageMetadata;
649 auto& outMaterials = context.mOutput.mResources.mMaterials;
650 outMaterials.reserve(document.mMaterials.size());
652 for(auto& material : document.mMaterials)
654 ConvertMaterial(material, imageMetaData, outMaterials, context);
658 MeshDefinition::Accessor ConvertMeshPrimitiveAccessor(const gltf2::Accessor& accessor)
660 DALI_ASSERT_ALWAYS((accessor.mBufferView &&
661 (accessor.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max())) ||
662 (accessor.mSparse && !accessor.mBufferView));
664 DALI_ASSERT_ALWAYS(!accessor.mSparse ||
665 ((accessor.mSparse->mIndices.mBufferView && (accessor.mSparse->mIndices.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max())) &&
666 (accessor.mSparse->mValues.mBufferView && (accessor.mSparse->mValues.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max()))));
668 MeshDefinition::SparseBlob sparseBlob;
671 const gltf2::Accessor::Sparse& sparse = *accessor.mSparse;
672 const gltf2::ComponentTypedBufferViewClient& indices = sparse.mIndices;
673 const gltf2::BufferViewClient& values = sparse.mValues;
675 MeshDefinition::Blob indicesBlob(
676 indices.mBufferView->mByteOffset + indices.mByteOffset,
677 sparse.mCount * indices.GetBytesPerComponent(),
678 static_cast<uint16_t>(indices.mBufferView->mByteStride),
679 static_cast<uint16_t>(indices.GetBytesPerComponent()),
682 MeshDefinition::Blob valuesBlob(
683 values.mBufferView->mByteOffset + values.mByteOffset,
684 sparse.mCount * accessor.GetElementSizeBytes(),
685 static_cast<uint16_t>(values.mBufferView->mByteStride),
686 static_cast<uint16_t>(accessor.GetElementSizeBytes()),
690 sparseBlob = std::move(MeshDefinition::SparseBlob(std::move(indicesBlob), std::move(valuesBlob), accessor.mSparse->mCount));
693 uint32_t bufferViewOffset = 0u;
694 uint32_t bufferViewStride = 0u;
695 if(accessor.mBufferView)
697 bufferViewOffset = accessor.mBufferView->mByteOffset;
698 bufferViewStride = accessor.mBufferView->mByteStride;
701 return MeshDefinition::Accessor{
702 std::move(MeshDefinition::Blob{bufferViewOffset + accessor.mByteOffset,
703 accessor.GetBytesLength(),
704 static_cast<uint16_t>(bufferViewStride),
705 static_cast<uint16_t>(accessor.GetElementSizeBytes()),
708 std::move(sparseBlob),
709 accessor.mBufferView ? accessor.mBufferView->mBuffer.GetIndex() : 0};
712 void ConvertMeshes(const gltf2::Document& document, ConversionContext& context)
714 uint32_t meshCount = 0;
715 context.mMeshIds.reserve(document.mMeshes.size());
716 for(auto& mesh : document.mMeshes)
718 context.mMeshIds.push_back(meshCount);
719 meshCount += mesh.mPrimitives.size();
722 auto& outMeshes = context.mOutput.mResources.mMeshes;
723 outMeshes.reserve(meshCount);
724 for(auto& mesh : document.mMeshes)
726 for(auto& primitive : mesh.mPrimitives)
728 MeshDefinition meshDefinition;
730 auto& attribs = primitive.mAttributes;
731 meshDefinition.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[primitive.mMode];
733 auto positionIter = attribs.find(gltf2::Attribute::POSITION);
735 if(positionIter == attribs.end())
737 DALI_LOG_ERROR("Primitive mesh dosn't have POSITION atrributes!");
741 auto& accPositions = *positionIter->second;
742 meshDefinition.mPositions = ConvertMeshPrimitiveAccessor(accPositions);
743 // glTF2 support vector4 tangent for mesh.
744 // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview
745 meshDefinition.mTangentType = Property::VECTOR4;
747 const bool needNormalsTangents = accPositions.mType == gltf2::AccessorType::VEC3;
748 for(auto& attributeMapping : ATTRIBUTE_MAPPINGS)
750 auto iFind = attribs.find(attributeMapping.mType);
751 if(iFind != attribs.end())
753 auto& accessor = meshDefinition.*(attributeMapping.mAccessor);
754 accessor = ConvertMeshPrimitiveAccessor(*iFind->second);
756 if(iFind->first == gltf2::Attribute::JOINTS_0)
758 meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
759 meshDefinition.mFlags |= (iFind->second->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS;
760 DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) || iFind->second->mComponentType == gltf2::Component::FLOAT);
763 else if(needNormalsTangents)
765 switch(attributeMapping.mType)
767 case gltf2::Attribute::NORMAL:
768 meshDefinition.RequestNormals();
771 case gltf2::Attribute::TANGENT:
772 meshDefinition.RequestTangents();
781 if(primitive.mIndices)
783 meshDefinition.mIndices = ConvertMeshPrimitiveAccessor(*primitive.mIndices);
784 meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gltf2::Component::UNSIGNED_INT) * MeshDefinition::U32_INDICES;
785 meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_INDICES;
786 DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U32_INDICES) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_INDICES) || primitive.mIndices->mComponentType == gltf2::Component::UNSIGNED_SHORT);
789 if(!primitive.mTargets.empty())
791 meshDefinition.mBlendShapes.reserve(primitive.mTargets.size());
792 meshDefinition.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
793 for(const auto& target : primitive.mTargets)
795 MeshDefinition::BlendShape blendShape;
797 auto endIt = target.end();
798 auto it = target.find(gltf2::Attribute::POSITION);
801 blendShape.deltas = ConvertMeshPrimitiveAccessor(*it->second);
803 it = target.find(gltf2::Attribute::NORMAL);
806 blendShape.normals = ConvertMeshPrimitiveAccessor(*it->second);
808 it = target.find(gltf2::Attribute::TANGENT);
811 blendShape.tangents = ConvertMeshPrimitiveAccessor(*it->second);
814 if(!mesh.mWeights.empty())
816 blendShape.weight = mesh.mWeights[meshDefinition.mBlendShapes.size()];
819 meshDefinition.mBlendShapes.push_back(std::move(blendShape));
823 outMeshes.push_back({std::move(meshDefinition), MeshGeometry{}});
828 ModelRenderable* MakeModelRenderable(const gltf2::Mesh::Primitive& primitive, ConversionContext& context)
830 auto modelRenderable = new ModelRenderable();
832 modelRenderable->mShaderIdx = 0; // TODO: further thought
834 auto materialIdx = primitive.mMaterial.GetIndex();
835 if(INVALID_INDEX == materialIdx)
837 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#default-material
838 if(INVALID_INDEX == context.mDefaultMaterial)
840 auto& outMaterials = context.mOutput.mResources.mMaterials;
841 context.mDefaultMaterial = outMaterials.size();
843 ConvertMaterial(gltf2::Material{}, context.mOutput.mSceneMetadata.mImageMetadata, outMaterials, context);
846 materialIdx = context.mDefaultMaterial;
849 modelRenderable->mMaterialIdx = materialIdx;
851 return modelRenderable;
854 void ConvertCamera(const gltf2::Camera& camera, CameraParameters& cameraParameters)
856 cameraParameters.isPerspective = camera.mType.compare("perspective") == 0;
857 if(cameraParameters.isPerspective)
859 auto& perspective = camera.mPerspective;
860 if(!Dali::Equals(perspective.mYFov, gltf2::UNDEFINED_FLOAT_VALUE))
862 cameraParameters.yFovDegree = Degree(Radian(perspective.mYFov));
866 cameraParameters.yFovDegree = Degree(gltf2::UNDEFINED_FLOAT_VALUE);
868 cameraParameters.zNear = perspective.mZNear;
869 cameraParameters.zFar = perspective.mZFar;
870 // TODO: yes, we seem to ignore aspectRatio in CameraParameters.
874 auto& ortho = camera.mOrthographic;
875 if(!Dali::Equals(ortho.mYMag, gltf2::UNDEFINED_FLOAT_VALUE) && !Dali::Equals(ortho.mXMag, gltf2::UNDEFINED_FLOAT_VALUE))
877 cameraParameters.orthographicSize = ortho.mYMag * .5f;
878 cameraParameters.aspectRatio = ortho.mXMag / ortho.mYMag;
882 cameraParameters.orthographicSize = gltf2::UNDEFINED_FLOAT_VALUE;
883 cameraParameters.aspectRatio = gltf2::UNDEFINED_FLOAT_VALUE;
885 cameraParameters.zNear = ortho.mZNear;
886 cameraParameters.zFar = ortho.mZFar;
890 void ConvertNode(gltf2::Node const& node, const Index gltfIndex, Index parentIndex, ConversionContext& context, bool isMRendererModel)
892 auto& output = context.mOutput;
893 auto& scene = output.mScene;
894 auto& resources = output.mResources;
896 const auto index = scene.GetNodeCount();
897 auto weakNode = scene.AddNode([&]()
899 std::unique_ptr<NodeDefinition> nodeDefinition{new NodeDefinition()};
901 nodeDefinition->mParentIdx = parentIndex;
902 nodeDefinition->mName = node.mName;
903 if(nodeDefinition->mName.empty())
905 // TODO: Production quality generation of unique names.
906 nodeDefinition->mName = std::to_string(reinterpret_cast<uintptr_t>(nodeDefinition.get()));
909 if(!node.mSkin) // Nodes with skinned meshes are not supposed to have local transforms.
911 nodeDefinition->mPosition = node.mTranslation;
912 nodeDefinition->mOrientation = node.mRotation;
913 nodeDefinition->mScale = node.mScale;
915 if(isMRendererModel && node.mName == ROOT_NODE_NAME && node.mScale == SCALE_TO_ADJUST)
917 nodeDefinition->mScale *= 0.01f;
921 return nodeDefinition; }());
924 ExceptionFlinger(ASSERT_LOCATION) << "Node name '" << node.mName << "' is not unique; scene is invalid.";
927 context.mNodeIndices.RegisterMapping(gltfIndex, index);
929 Index skeletonIdx = node.mSkin ? node.mSkin.GetIndex() : INVALID_INDEX;
932 auto& mesh = *node.mMesh;
933 uint32_t primitiveCount = mesh.mPrimitives.size();
934 auto meshIndex = context.mMeshIds[node.mMesh.GetIndex()];
935 weakNode->mRenderables.reserve(primitiveCount);
936 for(uint32_t i = 0; i < primitiveCount; ++i)
938 std::unique_ptr<NodeDefinition::Renderable> renderable;
939 auto modelRenderable = MakeModelRenderable(mesh.mPrimitives[i], context);
940 modelRenderable->mMeshIdx = meshIndex + i;
942 DALI_ASSERT_DEBUG(resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == INVALID_INDEX ||
943 resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == skeletonIdx);
944 resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx = skeletonIdx;
946 renderable.reset(modelRenderable);
947 weakNode->mRenderables.push_back(std::move(renderable));
953 CameraParameters cameraParameters;
954 ConvertCamera(*node.mCamera, cameraParameters);
956 cameraParameters.matrix.SetTransformComponents(node.mScale, node.mRotation, node.mTranslation);
957 output.mCameraParameters.push_back(cameraParameters);
960 for(auto& child : node.mChildren)
962 ConvertNode(*child, child.GetIndex(), index, context, isMRendererModel);
966 void ConvertSceneNodes(const gltf2::Scene& scene, ConversionContext& context, bool isMRendererModel)
968 auto& outScene = context.mOutput.mScene;
969 Index rootIndex = outScene.GetNodeCount();
970 switch(scene.mNodes.size())
976 ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, context, isMRendererModel);
977 outScene.AddRootNode(rootIndex);
982 std::unique_ptr<NodeDefinition> sceneRoot{new NodeDefinition()};
983 sceneRoot->mName = "GLTF_LOADER_SCENE_ROOT_" + std::to_string(outScene.GetRoots().size());
985 outScene.AddNode(std::move(sceneRoot));
986 outScene.AddRootNode(rootIndex);
988 for(auto& node : scene.mNodes)
990 ConvertNode(*node, node.GetIndex(), rootIndex, context, isMRendererModel);
997 void ConvertNodes(const gltf2::Document& document, ConversionContext& context, bool isMRendererModel)
999 if(!document.mScenes.empty())
1001 uint32_t rootSceneIndex = 0u;
1004 rootSceneIndex = document.mScene.GetIndex();
1006 ConvertSceneNodes(document.mScenes[rootSceneIndex], context, isMRendererModel);
1008 for(uint32_t i = 0; i < rootSceneIndex; ++i)
1010 ConvertSceneNodes(document.mScenes[i], context, isMRendererModel);
1013 for(uint32_t i = rootSceneIndex + 1; i < document.mScenes.size(); ++i)
1015 ConvertSceneNodes(document.mScenes[i], context, isMRendererModel);
1020 template<typename T>
1021 void LoadDataFromAccessor(ConversionContext& context, uint32_t bufferIndex, Vector<T>& dataBuffer, uint32_t offset, uint32_t size)
1023 if(bufferIndex >= context.mOutput.mResources.mBuffers.size())
1025 DALI_LOG_ERROR("Invailid buffer index\n");
1029 auto& buffer = context.mOutput.mResources.mBuffers[bufferIndex];
1030 if(!buffer.IsAvailable())
1032 DALI_LOG_ERROR("Failed to load from buffer stream.\n");
1034 auto& stream = buffer.GetBufferStream();
1036 stream.seekg(offset, stream.beg);
1037 stream.read(reinterpret_cast<char*>(dataBuffer.Begin()), static_cast<std::streamsize>(static_cast<size_t>(size)));
1040 template<typename T>
1041 float LoadDataFromAccessors(ConversionContext& context, const gltf2::Accessor& input, const gltf2::Accessor& output, Vector<float>& inputDataBuffer, Vector<T>& outputDataBuffer)
1043 inputDataBuffer.Resize(input.mCount);
1044 outputDataBuffer.Resize(output.mCount);
1046 const uint32_t inputDataBufferSize = input.GetBytesLength();
1047 const uint32_t outputDataBufferSize = output.GetBytesLength();
1049 LoadDataFromAccessor<float>(context, output.mBufferView->mBuffer.GetIndex(), inputDataBuffer, input.mBufferView->mByteOffset + input.mByteOffset, inputDataBufferSize);
1050 LoadDataFromAccessor<T>(context, output.mBufferView->mBuffer.GetIndex(), outputDataBuffer, output.mBufferView->mByteOffset + output.mByteOffset, outputDataBufferSize);
1051 ApplyAccessorMinMax(input, reinterpret_cast<float*>(inputDataBuffer.begin()));
1052 ApplyAccessorMinMax(output, reinterpret_cast<float*>(outputDataBuffer.begin()));
1054 return inputDataBuffer[input.mCount - 1u];
1057 template<typename T>
1058 float LoadKeyFrames(ConversionContext& context, const gltf2::Animation::Channel& channel, KeyFrames& keyFrames, gltf2::Animation::Channel::Target::Type type)
1060 const gltf2::Accessor& input = *channel.mSampler->mInput;
1061 const gltf2::Accessor& output = *channel.mSampler->mOutput;
1063 Vector<float> inputDataBuffer;
1064 Vector<T> outputDataBuffer;
1066 const float duration = std::max(LoadDataFromAccessors<T>(context, input, output, inputDataBuffer, outputDataBuffer), AnimationDefinition::MIN_DURATION_SECONDS);
1068 // Set first frame value as first keyframe (gltf animation spec)
1069 if(input.mCount > 0 && !Dali::EqualsZero(inputDataBuffer[0]))
1071 keyFrames.Add(0.0f, outputDataBuffer[0]);
1074 for(uint32_t i = 0; i < input.mCount; ++i)
1076 keyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i]);
1082 float LoadBlendShapeKeyFrames(ConversionContext& context, const gltf2::Animation::Channel& channel, Index nodeIndex, uint32_t& propertyIndex, std::vector<Dali::Scene3D::Loader::AnimatedProperty>& properties)
1084 const gltf2::Accessor& input = *channel.mSampler->mInput;
1085 const gltf2::Accessor& output = *channel.mSampler->mOutput;
1087 Vector<float> inputDataBuffer;
1088 Vector<float> outputDataBuffer;
1090 const float duration = std::max(LoadDataFromAccessors<float>(context, input, output, inputDataBuffer, outputDataBuffer), AnimationDefinition::MIN_DURATION_SECONDS);
1092 char weightNameBuffer[32];
1093 auto prefixSize = snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s[", BLEND_SHAPE_WEIGHTS_UNIFORM.data());
1094 char* const pWeightName = weightNameBuffer + prefixSize;
1095 const auto remainingSize = sizeof(weightNameBuffer) - prefixSize;
1096 for(uint32_t weightIndex = 0u, endWeightIndex = channel.mSampler->mOutput->mCount / channel.mSampler->mInput->mCount; weightIndex < endWeightIndex; ++weightIndex)
1098 AnimatedProperty& animatedProperty = properties[propertyIndex++];
1100 animatedProperty.mNodeIndex = nodeIndex;
1101 snprintf(pWeightName, remainingSize, "%d]", weightIndex);
1102 animatedProperty.mPropertyName = std::string(weightNameBuffer);
1104 animatedProperty.mKeyFrames = KeyFrames::New();
1106 // Set first frame value as first keyframe (gltf animation spec)
1107 if(input.mCount > 0 && !Dali::EqualsZero(inputDataBuffer[0]))
1109 animatedProperty.mKeyFrames.Add(0.0f, outputDataBuffer[weightIndex]);
1112 for(uint32_t i = 0; i < input.mCount; ++i)
1114 animatedProperty.mKeyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i * endWeightIndex + weightIndex]);
1117 animatedProperty.mTimePeriod = {0.f, duration};
1123 template<typename T>
1124 float LoadAnimation(AnimationDefinition& animationDefinition, Index nodeIndex, Index propertyIndex, const std::string& propertyName, const gltf2::Animation::Channel& channel, ConversionContext& context)
1126 AnimatedProperty& animatedProperty = animationDefinition.mProperties[propertyIndex];
1128 animatedProperty.mNodeIndex = nodeIndex;
1129 animatedProperty.mPropertyName = propertyName;
1131 animatedProperty.mKeyFrames = KeyFrames::New();
1132 float duration = LoadKeyFrames<T>(context, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
1133 animatedProperty.mTimePeriod = {0.f, duration};
1138 void ConvertAnimations(const gltf2::Document& document, ConversionContext& context)
1140 auto& output = context.mOutput;
1142 output.mAnimationDefinitions.reserve(output.mAnimationDefinitions.size() + document.mAnimations.size());
1144 for(const auto& animation : document.mAnimations)
1146 AnimationDefinition animationDefinition;
1148 if(!animation.mName.empty())
1150 animationDefinition.mName = animation.mName;
1153 uint32_t numberOfProperties = 0u;
1154 for(const auto& channel : animation.mChannels)
1156 if(channel.mTarget.mPath == gltf2::Animation::Channel::Target::WEIGHTS)
1158 numberOfProperties += channel.mSampler->mOutput->mCount / channel.mSampler->mInput->mCount;
1162 numberOfProperties++;
1165 animationDefinition.mProperties.resize(numberOfProperties);
1167 Index propertyIndex = 0u;
1168 for(const auto& channel : animation.mChannels)
1170 Index nodeIndex = context.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex());
1171 float duration = 0.f;
1173 switch(channel.mTarget.mPath)
1175 case gltf2::Animation::Channel::Target::TRANSLATION:
1177 duration = LoadAnimation<Vector3>(animationDefinition, nodeIndex, propertyIndex, POSITION_PROPERTY.data(), channel, context);
1180 case gltf2::Animation::Channel::Target::ROTATION:
1182 duration = LoadAnimation<Quaternion>(animationDefinition, nodeIndex, propertyIndex, ORIENTATION_PROPERTY.data(), channel, context);
1185 case gltf2::Animation::Channel::Target::SCALE:
1187 duration = LoadAnimation<Vector3>(animationDefinition, nodeIndex, propertyIndex, SCALE_PROPERTY.data(), channel, context);
1190 case gltf2::Animation::Channel::Target::WEIGHTS:
1192 duration = LoadBlendShapeKeyFrames(context, channel, nodeIndex, propertyIndex, animationDefinition.mProperties);
1198 // nothing to animate.
1203 animationDefinition.mDuration = std::max(duration, animationDefinition.mDuration);
1208 output.mAnimationDefinitions.push_back(std::move(animationDefinition));
1212 void ProcessSkins(const gltf2::Document& document, ConversionContext& context)
1214 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skininversebindmatrices
1215 // If an inverseBindMatrices accessor was provided, we'll load the joint data from the buffer,
1216 // otherwise we'll set identity matrices for inverse bind pose.
1217 struct IInverseBindMatrixProvider
1219 virtual ~IInverseBindMatrixProvider()
1222 virtual void Provide(Matrix& inverseBindMatrix) = 0;
1225 struct InverseBindMatrixAccessor : public IInverseBindMatrixProvider
1227 std::istream& mStream;
1228 const uint32_t mElementSizeBytes;
1230 InverseBindMatrixAccessor(const gltf2::Accessor& accessor, ConversionContext& context)
1231 : mStream(context.mOutput.mResources.mBuffers[accessor.mBufferView->mBuffer.GetIndex()].GetBufferStream()),
1232 mElementSizeBytes(accessor.GetElementSizeBytes())
1234 DALI_ASSERT_DEBUG(accessor.mType == gltf2::AccessorType::MAT4 && accessor.mComponentType == gltf2::Component::FLOAT);
1236 if(!mStream.rdbuf()->in_avail())
1238 DALI_LOG_ERROR("Failed to load from stream\n");
1241 mStream.seekg(accessor.mBufferView->mByteOffset + accessor.mByteOffset, mStream.beg);
1244 virtual void Provide(Matrix& inverseBindMatrix) override
1246 DALI_ASSERT_ALWAYS(mStream.read(reinterpret_cast<char*>(inverseBindMatrix.AsFloat()), static_cast<std::streamsize>(static_cast<size_t>(mElementSizeBytes))));
1250 struct DefaultInverseBindMatrixProvider : public IInverseBindMatrixProvider
1252 virtual void Provide(Matrix& inverseBindMatrix) override
1254 inverseBindMatrix = Matrix::IDENTITY;
1258 auto& resources = context.mOutput.mResources;
1259 resources.mSkeletons.reserve(document.mSkins.size());
1261 for(auto& skin : document.mSkins)
1263 std::unique_ptr<IInverseBindMatrixProvider> inverseBindMatrixProvider;
1264 if(skin.mInverseBindMatrices)
1266 inverseBindMatrixProvider.reset(new InverseBindMatrixAccessor(*skin.mInverseBindMatrices, context));
1270 inverseBindMatrixProvider.reset(new DefaultInverseBindMatrixProvider());
1273 SkeletonDefinition skeleton;
1274 if(skin.mSkeleton.GetIndex() != INVALID_INDEX)
1276 skeleton.mRootNodeIdx = context.mNodeIndices.GetRuntimeId(skin.mSkeleton.GetIndex());
1279 skeleton.mJoints.resize(skin.mJoints.size());
1280 auto iJoint = skeleton.mJoints.begin();
1281 for(auto& joint : skin.mJoints)
1283 iJoint->mNodeIdx = context.mNodeIndices.GetRuntimeId(joint.GetIndex());
1285 inverseBindMatrixProvider->Provide(iJoint->mInverseBindMatrix);
1290 resources.mSkeletons.push_back(std::move(skeleton));
1294 void ProduceShaders(ShaderDefinitionFactory& shaderFactory, Dali::Scene3D::Loader::SceneDefinition& scene)
1296 uint32_t nodeCount = scene.GetNodeCount();
1297 for(uint32_t i = 0; i < nodeCount; ++i)
1299 auto nodeDefinition = scene.GetNode(i);
1300 for(auto& renderable : nodeDefinition->mRenderables)
1302 if(shaderFactory.ProduceShader(*renderable) == INVALID_INDEX)
1304 DALI_LOG_ERROR("Fail to produce shader\n");
1310 void SetObjectReaders()
1312 json::SetObjectReader(GetBufferReader());
1313 json::SetObjectReader(GetBufferViewReader());
1314 json::SetObjectReader(GetBufferViewClientReader());
1315 json::SetObjectReader(GetComponentTypedBufferViewClientReader());
1316 json::SetObjectReader(GetAccessorSparseReader());
1317 json::SetObjectReader(GetAccessorReader());
1318 json::SetObjectReader(GetImageReader());
1319 json::SetObjectReader(GetSamplerReader());
1320 json::SetObjectReader(GetTextureReader());
1321 json::SetObjectReader(GetTextureInfoReader());
1322 json::SetObjectReader(GetMaterialPbrReader());
1323 json::SetObjectReader(GetMaterialSpecularReader());
1324 json::SetObjectReader(GetMaterialIorReader());
1325 json::SetObjectReader(GetMaterialExtensionsReader());
1326 json::SetObjectReader(GetMaterialReader());
1327 json::SetObjectReader(GetMeshPrimitiveReader());
1328 json::SetObjectReader(GetMeshReader());
1329 json::SetObjectReader(GetSkinReader());
1330 json::SetObjectReader(GetCameraPerspectiveReader());
1331 json::SetObjectReader(GetCameraOrthographicReader());
1332 json::SetObjectReader(GetCameraReader());
1333 json::SetObjectReader(GetNodeReader());
1334 json::SetObjectReader(GetAnimationSamplerReader());
1335 json::SetObjectReader(GetAnimationChannelTargetReader());
1336 json::SetObjectReader(GetAnimationChannelReader());
1337 json::SetObjectReader(GetAnimationReader());
1338 json::SetObjectReader(GetSceneReader());
1341 void SetDefaultEnvironmentMap(const gltf2::Document& document, ConversionContext& context)
1343 EnvironmentDefinition environmentDefinition;
1344 environmentDefinition.mUseBrdfTexture = true;
1345 environmentDefinition.mIblIntensity = Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
1346 context.mOutput.mResources.mEnvironmentMaps.push_back({std::move(environmentDefinition), EnvironmentDefinition::Textures()});
1349 void InitializeGltfLoader()
1351 static Dali::Mutex initializeMutex;
1352 // Set ObjectReader only once (for all gltf loading).
1353 static bool setObjectReadersRequired = true;
1355 Mutex::ScopedLock lock(initializeMutex);
1356 if(setObjectReadersRequired)
1358 // NOTE: only referencing own, anonymous namespace, const objects; the pointers will never need to change.
1360 setObjectReadersRequired = false;
1365 const std::string_view GetRendererModelIdentification()
1367 return MRENDERER_MODEL_IDENTIFICATION;
1370 void ReadDocument(const json_object_s& jsonObject, gltf2::Document& document)
1372 GetDocumentReader().Read(jsonObject, document);
1375 void ReadDocumentFromParsedData(const json_object_s& jsonObject, gltf2::Document& document)
1377 static Dali::Mutex readMutex;
1378 Mutex::ScopedLock lock(readMutex);
1379 gt::SetRefReaderObject(document);
1380 Gltf2Util::ReadDocument(jsonObject, document);
1383 bool GenerateDocument(json::unique_ptr& root, gt::Document& document, bool& isMRendererModel)
1385 auto& rootObject = js::Cast<json_object_s>(*root);
1386 auto jsonAsset = js::FindObjectChild("asset", rootObject);
1388 auto jsAssetVersion = js::FindObjectChild("version", js::Cast<json_object_s>(*jsonAsset));
1391 document.mAsset.mVersion = js::Read::StringView(*jsAssetVersion);
1394 auto jsAssetGenerator = js::FindObjectChild("generator", js::Cast<json_object_s>(*jsonAsset));
1395 if(jsAssetGenerator)
1397 document.mAsset.mGenerator = js::Read::StringView(*jsAssetGenerator);
1398 isMRendererModel = (document.mAsset.mGenerator.find(Gltf2Util::GetRendererModelIdentification().data()) != std::string_view::npos);
1401 Gltf2Util::InitializeGltfLoader();
1402 Gltf2Util::ReadDocumentFromParsedData(rootObject, document);
1407 void ConvertGltfToContext(gt::Document& document, Gltf2Util::ConversionContext& context, bool isMRendererModel)
1409 Dali::Scene3D::Loader::ShaderDefinitionFactory shaderFactory;
1410 shaderFactory.SetResources(context.mOutput.mResources);
1412 Gltf2Util::ConvertBuffers(document, context);
1413 Gltf2Util::ConvertMaterials(document, context);
1414 Gltf2Util::ConvertMeshes(document, context);
1415 Gltf2Util::ConvertNodes(document, context, isMRendererModel);
1416 Gltf2Util::ConvertAnimations(document, context);
1417 Gltf2Util::ProcessSkins(document, context);
1418 Gltf2Util::ProduceShaders(shaderFactory, context.mOutput.mScene);
1419 context.mOutput.mScene.EnsureUniqueSkinningShaderInstances(context.mOutput.mResources);
1421 // Set Default Environment map
1422 Gltf2Util::SetDefaultEnvironmentMap(document, context);
1425 } // namespace Gltf2Util
1427 } // namespace Dali::Scene3D::Loader::Internal