Let we parse extra / extensions information from gltf2 mesh.
It will be used when we apply blendshape informations by string.
Since we are store the blendshape name, now we can get the index of
blendshape by name per each ModelNode.
Change-Id: I4e2030901b87c76b5fb205208c13184ae6ebd7b0
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
--- /dev/null
+{\r
+ "accessors": [\r
+ {\r
+ "bufferView": 0,\r
+ "componentType": 5126,\r
+ "count": 24,\r
+ "type": "VEC3"\r
+ },\r
+ {\r
+ "bufferView": 1,\r
+ "componentType": 5126,\r
+ "count": 24,\r
+ "type": "VEC4"\r
+ },\r
+ {\r
+ "bufferView": 2,\r
+ "componentType": 5126,\r
+ "count": 24,\r
+ "type": "VEC3",\r
+ "max": [\r
+ 0.0100000035,\r
+ 0.0100000035,\r
+ 0.01\r
+ ],\r
+ "min": [\r
+ -0.0100000044,\r
+ -0.0100000054,\r
+ -0.01\r
+ ]\r
+ },\r
+ {\r
+ "bufferView": 3,\r
+ "componentType": 5126,\r
+ "count": 24,\r
+ "type": "VEC3",\r
+ "name": "thin"\r
+ },\r
+ {\r
+ "bufferView": 4,\r
+ "componentType": 5126,\r
+ "count": 24,\r
+ "type": "VEC3",\r
+ "max": [\r
+ 0.0,\r
+ 0.01893253,\r
+ 0.0\r
+ ],\r
+ "min": [\r
+ 0.0,\r
+ 0.0,\r
+ 0.0\r
+ ],\r
+ "name": "thin"\r
+ },\r
+ {\r
+ "bufferView": 5,\r
+ "componentType": 5126,\r
+ "count": 24,\r
+ "type": "VEC3",\r
+ "name": "thin"\r
+ },\r
+ {\r
+ "bufferView": 6,\r
+ "componentType": 5126,\r
+ "count": 24,\r
+ "type": "VEC3",\r
+ "name": "angle"\r
+ },\r
+ {\r
+ "bufferView": 7,\r
+ "componentType": 5126,\r
+ "count": 24,\r
+ "type": "VEC3",\r
+ "max": [\r
+ 0.0,\r
+ 0.0198908355,\r
+ 0.0\r
+ ],\r
+ "min": [\r
+ 0.0,\r
+ 0.0,\r
+ 0.0\r
+ ],\r
+ "name": "angle"\r
+ },\r
+ {\r
+ "bufferView": 8,\r
+ "componentType": 5126,\r
+ "count": 24,\r
+ "type": "VEC3",\r
+ "name": "angle"\r
+ },\r
+ {\r
+ "bufferView": 9,\r
+ "componentType": 5123,\r
+ "count": 36,\r
+ "type": "SCALAR"\r
+ },\r
+ {\r
+ "bufferView": 10,\r
+ "componentType": 5126,\r
+ "count": 127,\r
+ "type": "SCALAR",\r
+ "max": [\r
+ 4.19999743\r
+ ],\r
+ "min": [\r
+ 0.03\r
+ ]\r
+ },\r
+ {\r
+ "bufferView": 11,\r
+ "componentType": 5126,\r
+ "count": 254,\r
+ "type": "SCALAR"\r
+ }\r
+ ],\r
+ "animations": [\r
+ {\r
+ "channels": [\r
+ {\r
+ "sampler": 0,\r
+ "target": {\r
+ "node": 0,\r
+ "path": "weights"\r
+ }\r
+ }\r
+ ],\r
+ "samplers": [\r
+ {\r
+ "input": 10,\r
+ "interpolation": "LINEAR",\r
+ "output": 11\r
+ }\r
+ ],\r
+ "name": "Square"\r
+ }\r
+ ],\r
+ "asset": {\r
+ "generator": "glTF Tools for Unity",\r
+ "version": "2.0"\r
+ },\r
+ "bufferViews": [\r
+ {\r
+ "buffer": 0,\r
+ "byteLength": 288\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 288,\r
+ "byteLength": 384\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 672,\r
+ "byteLength": 288\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 960,\r
+ "byteLength": 288\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 1248,\r
+ "byteLength": 288\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 1536,\r
+ "byteLength": 288\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 1824,\r
+ "byteLength": 288\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 2112,\r
+ "byteLength": 288\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 2400,\r
+ "byteLength": 288\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 2688,\r
+ "byteLength": 72\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 2760,\r
+ "byteLength": 508\r
+ },\r
+ {\r
+ "buffer": 0,\r
+ "byteOffset": 3268,\r
+ "byteLength": 1016\r
+ }\r
+ ],\r
+ "buffers": [\r
+ {\r
+ "uri": "AnimatedMorphCube.bin",\r
+ "byteLength": 4284\r
+ }\r
+ ],\r
+ "meshes": [\r
+ {\r
+ "extras": {\r
+ "targetNames": [\r
+ "Target_0",\r
+ "Target_1"\r
+ ]\r
+ },\r
+ "primitives": [\r
+ {\r
+ "attributes": {\r
+ "NORMAL": 0,\r
+ "TANGENT": 1,\r
+ "POSITION": 2\r
+ },\r
+ "indices": 9,\r
+ "material": 0,\r
+ "targets": [\r
+ {\r
+ "NORMAL": 3,\r
+ "POSITION": 4,\r
+ "TANGENT": 5\r
+ },\r
+ {\r
+ "NORMAL": 6,\r
+ "POSITION": 7,\r
+ "TANGENT": 8\r
+ }\r
+ ]\r
+ }\r
+ ],\r
+ "weights": [\r
+ 0.0,\r
+ 0.0\r
+ ],\r
+ "name": "Cube"\r
+ }\r
+ ],\r
+ "materials": [\r
+ {\r
+ "pbrMetallicRoughness": {\r
+ "baseColorFactor": [\r
+ 0.6038274,\r
+ 0.6038274,\r
+ 0.6038274,\r
+ 1.0\r
+ ],\r
+ "metallicFactor": 0.0,\r
+ "roughnessFactor": 0.5\r
+ },\r
+ "name": "Material"\r
+ }\r
+ ],\r
+ "nodes": [\r
+ {\r
+ "mesh": 0,\r
+ "rotation": [\r
+ 0.0,\r
+ 0.7071067,\r
+ -0.7071068,\r
+ 0.0\r
+ ],\r
+ "scale": [\r
+ 100.0,\r
+ 100.0,\r
+ 100.0\r
+ ],\r
+ "name": "AnimatedMorphCube"\r
+ }\r
+ ],\r
+ "scene": 0,\r
+ "scenes": [\r
+ {\r
+ "nodes": [\r
+ 0\r
+ ]\r
+ }\r
+ ]\r
+}
\ No newline at end of file
],\r
"mode": 4\r
}\r
- ]\r
+ ],\r
+ "extensions": {\r
+ "SXR_targets_names": {\r
+ "Target_0": 0\r
+ },\r
+ "avatar_shape_names": {\r
+ "Target_0": 0\r
+ }\r
+ }\r
}\r
],\r
"nodes": [\r
#include <dali-toolkit-test-suite-utils.h>
#include <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/common/map-wrapper.h>
#include <stdlib.h>
#include <iostream>
*/
const char* TEST_GLTF_FILE_NAME = TEST_RESOURCE_DIR "/AnimatedCube.gltf";
const char* TEST_GLTF_ANIMATION_TEST_FILE_NAME = TEST_RESOURCE_DIR "/animationTest.gltf";
+const char* TEST_GLTF_EXTRAS_FILE_NAME = TEST_RESOURCE_DIR "/AnimatedMorphCubeAnimateNonZeroFrame.gltf";
const char* TEST_GLTF_MULTIPLE_PRIMITIVE_FILE_NAME = TEST_RESOURCE_DIR "/simpleMultiplePrimitiveTest.gltf";
const char* TEST_DLI_FILE_NAME = TEST_RESOURCE_DIR "/arc.dli";
const char* TEST_DLI_EXERCISE_FILE_NAME = TEST_RESOURCE_DIR "/exercise.dli";
CameraActor appliedCamera;
DALI_TEST_EQUALS(model.ApplyCamera(0u, appliedCamera), false, TEST_LOCATION); // Cannot apply into empty camera.
- auto CompareCameraProperties = [](CameraActor lhs, CameraActor rhs, const char* location)
- {
+ auto CompareCameraProperties = [](CameraActor lhs, CameraActor rhs, const char* location) {
DALI_TEST_EQUALS(lhs.GetProperty<int>(Dali::CameraActor::Property::PROJECTION_MODE), rhs.GetProperty<int>(Dali::CameraActor::Property::PROJECTION_MODE), TEST_LOCATION);
DALI_TEST_EQUALS(lhs.GetProperty<float>(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE), rhs.GetProperty<float>(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE), TEST_LOCATION);
END_TEST;
}
+
+int UtcDaliModelRetrieveBlendShapeNames(void)
+{
+ tet_infoline(" UtcDaliModelRetrieveBlendShapeByName.");
+
+ ToolkitTestApplication application;
+
+ Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_EXTRAS_FILE_NAME);
+ model.SetProperty(Dali::Actor::Property::SIZE, Vector3(300, 300, 300));
+ application.GetScene().Add(model);
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS(model.GetChildCount(), 1u, TEST_LOCATION);
+
+ // Get target ModelNode that has extras
+ Scene3D::ModelNode expectNode = model.FindChildModelNodeByName("AnimatedMorphCube");
+
+ // Pair of expected blend shape index from expectNode.
+ std::map<std::string, Scene3D::Loader::BlendShapes::Index> expectBlendShapeNames = {
+ {"Target_0", 0u},
+ {"Target_1", 1u},
+ };
+
+ std::vector<std::string> blendShapeNameList;
+ model.RetrieveBlendShapeNames(blendShapeNameList);
+
+ DALI_TEST_EQUALS(blendShapeNameList.size(), expectBlendShapeNames.size(), TEST_LOCATION);
+ for(auto i = 0u; i < blendShapeNameList.size(); ++i)
+ {
+ const auto& name = blendShapeNameList[i];
+ tet_printf("Check retrieved blendshape name : %s\n", name.c_str());
+
+ const auto& iter = expectBlendShapeNames.find(name);
+ DALI_TEST_CHECK(iter != expectBlendShapeNames.end());
+
+ std::vector<Scene3D::ModelNode> nodeList;
+ model.RetrieveModelNodesByBlendShapeName(name, nodeList);
+ DALI_TEST_EQUALS(nodeList.size(), 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(nodeList[0], expectNode, TEST_LOCATION);
+ DALI_TEST_EQUALS(nodeList[0].GetBlendShapeIndexByName(name), iter->second, TEST_LOCATION);
+ }
+
+ END_TEST;
+}
Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
{
std::vector<std::string> errors;
- auto onError = [&errors](const std::string& msg)
- { errors.push_back(msg); };
+ auto onError = [&errors](const std::string& msg) { errors.push_back(msg); };
if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
{
Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
{
return;
}
-
GetImplementation(node).AddLight(light, lightIndex);
uint32_t childrenCount = node.GetChildCount();
}
}
+void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node)
+{
+ if(!node)
+ {
+ return;
+ }
+ const auto childCount = node.GetChildCount();
+ for(auto i = 0u; i < childCount; ++i)
+ {
+ UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i)));
+ }
+
+ std::vector<std::string> blendShapeNames;
+ node.RetrieveBlendShapeNames(blendShapeNames);
+ for(const auto& iter : blendShapeNames)
+ {
+ // Append or create new list.
+ resultMap[iter].push_back(node);
+ }
+}
+
} // anonymous namespace
Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
return Scene3D::ModelNode::DownCast(childActor);
}
+void Model::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
+{
+ blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeModelNodeMap.size());
+ for(const auto& iter : mBlendShapeModelNodeMap)
+ {
+ blendShapeNames.push_back(iter.first);
+ }
+}
+
+void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<Scene3D::ModelNode>& modelNodes) const
+{
+ auto iter = mBlendShapeModelNodeMap.find(std::string(blendShapeName));
+ if(iter != mBlendShapeModelNodeMap.end())
+ {
+ const auto& modelNodeList = iter->second;
+ modelNodes.reserve(modelNodes.size() + modelNodeList.size());
+ for(const auto& nodeIter : modelNodeList)
+ {
+ modelNodes.push_back(nodeIter);
+ }
+ }
+}
+
///////////////////////////////////////////////////////////
//
// Private methods
resources.GenerateResources();
for(auto iRoot : scene.GetRoots())
{
- if(auto actor = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
+ if(auto modelNode = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
{
- scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
- ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests));
+ scene.ConfigureSkinningShaders(resources, modelNode, std::move(nodeParams.mSkinnables));
+ ConfigureBlendShapeShaders(resources, scene, modelNode, std::move(nodeParams.mBlendshapeRequests));
- scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+ scene.ApplyConstraints(modelNode, std::move(nodeParams.mConstrainables));
- mModelRoot.Add(actor);
+ mModelRoot.Add(modelNode);
}
AddModelTreeToAABB(AABB, scene, resourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
}
+ UpdateBlendShapeNodeMap();
+
mNaturalSize = AABB.CalculateSize();
mModelPivot = AABB.CalculatePivot();
mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
mAnimations.clear();
if(!mModelLoadTask->GetAnimations().empty())
{
- auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property)
- {
+ auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
{
return mModelRoot.FindChildByName(property.mNodeName);
}
}
+void Model::UpdateBlendShapeNodeMap()
+{
+ // Remove privous node map
+ mBlendShapeModelNodeMap.clear();
+
+ UpdateBlendShapeNodeMapRecursively(mBlendShapeModelNodeMap, mModelRoot);
+}
+
} // namespace Internal
} // namespace Scene3D
} // namespace Dali
// EXTERNAL INCLUDES
#include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali/devel-api/common/map-wrapper.h>
#include <dali/public-api/actors/camera-actor.h>
#include <dali/public-api/actors/layer.h>
#include <dali/public-api/animation/animation.h>
class Model : public Dali::Toolkit::Internal::Control, public LightObserver
{
public:
- using AnimationData = std::pair<std::string, Dali::Animation>;
- using CameraData = Loader::CameraParameters;
+ using AnimationData = std::pair<std::string, Dali::Animation>;
+ using CameraData = Loader::CameraParameters;
+ using BlendShapeModelNodeMap = std::map<std::string, std::vector<Scene3D::ModelNode>>;
/**
* @copydoc Model::New()
*/
Scene3D::ModelNode FindChildModelNodeByName(std::string_view nodeName);
+ /**
+ * @copydoc Model::RetrieveBlendShapeNames()
+ */
+ void RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const;
+
+ /**
+ * @copydoc Model::RetrieveModelNodesByBlendShapeName()
+ */
+ void RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<Scene3D::ModelNode>& modelNodes) const;
+
protected:
/**
* @brief Constructs a new Model.
*/
void ResetCameraParameters();
+ /**
+ * @brief Collect ModelNode list by blendshape name
+ */
+ void UpdateBlendShapeNodeMap();
+
private:
std::string mModelUrl;
std::string mResourceDirectoryUrl;
// Light
std::vector<Scene3D::Light> mLights;
+ // List of ModelNode for name of blend shape.
+ BlendShapeModelNodeMap mBlendShapeModelNodeMap;
+
// Asynchronous loading variable
ModelLoadTaskPtr mModelLoadTask;
EnvironmentMapLoadTaskPtr mIblDiffuseLoadTask;
//TODO: extensions
};
+ struct Extras
+ {
+ std::vector<std::string_view> mTargetNames;
+
+ //TODO: extras
+ };
+
+ struct Extensions
+ {
+ std::vector<std::string_view> mSXRTargetsNames;
+ std::vector<std::string_view> mAvatarShapeNames;
+
+ //TODO: extensions
+ };
+
std::vector<Primitive> mPrimitives;
std::vector<float> mWeights;
- //TODO: extras
- //TODO: extensions
+ Extras mExtras;
+ Extensions mExtensions;
};
struct Node;
return MESH_PRIMITIVE_READER;
}
+const json::Reader<gltf2::Mesh::Extras>& GetMeshExtrasReader()
+{
+ static const auto MESH_EXTRAS_READER = std::move(json::Reader<gltf2::Mesh::Extras>()
+ .Register(*json::MakeProperty("targetNames", json::Read::Array<std::string_view, json::Read::StringView>, &gltf2::Mesh::Extras::mTargetNames)));
+ return MESH_EXTRAS_READER;
+}
+
+std::vector<std::string_view> ReadMeshExtensionsTargetsName(const json_value_s& j)
+{
+ auto& jsonObject = json::Cast<json_object_s>(j);
+ std::vector<std::string_view> result;
+
+ auto element = jsonObject.start;
+ while(element)
+ {
+ auto jsonString = *element->name;
+ uint32_t index = json::Read::Number<uint32_t>(*element->value);
+
+ if(result.size() <= index)
+ {
+ result.resize(index + 1u);
+ }
+
+ result[index] = json::Read::StringView(jsonString);
+
+ element = element->next;
+ }
+ return result;
+}
+
+const json::Reader<gltf2::Mesh::Extensions>& GetMeshExtensionsReader()
+{
+ static const auto MESH_EXTENSIONS_READER = std::move(json::Reader<gltf2::Mesh::Extensions>()
+ .Register(*json::MakeProperty("SXR_targets_names", ReadMeshExtensionsTargetsName, &gltf2::Mesh::Extensions::mSXRTargetsNames))
+ .Register(*json::MakeProperty("avatar_shape_names", ReadMeshExtensionsTargetsName, &gltf2::Mesh::Extensions::mAvatarShapeNames)));
+ return MESH_EXTENSIONS_READER;
+}
+
const json::Reader<gltf2::Mesh>& GetMeshReader()
{
static const auto MESH_READER = std::move(json::Reader<gltf2::Mesh>()
.Register(*json::MakeProperty("primitives",
json::Read::Array<gltf2::Mesh::Primitive, json::ObjectReader<gltf2::Mesh::Primitive>::Read>,
&gltf2::Mesh::mPrimitives))
- .Register(*json::MakeProperty("weights", json::Read::Array<float, json::Read::Number>, &gltf2::Mesh::mWeights)));
+ .Register(*json::MakeProperty("weights", json::Read::Array<float, json::Read::Number>, &gltf2::Mesh::mWeights))
+ .Register(*json::MakeProperty("extras", json::ObjectReader<gltf2::Mesh::Extras>::Read, &gltf2::Mesh::mExtras))
+ .Register(*json::MakeProperty("extensions", json::ObjectReader<gltf2::Mesh::Extensions>::Read, &gltf2::Mesh::mExtensions)));
return MESH_READER;
}
void ConvertMaterial(const gltf2::Material& material, const std::unordered_map<std::string, ImageMetadata>& imageMetaData, decltype(ResourceBundle::mMaterials)& outMaterials, ConversionContext& context)
{
- auto getTextureMetaData = [](const std::unordered_map<std::string, ImageMetadata>& metaData, const gltf2::TextureInfo& info)
- {
+ auto getTextureMetaData = [](const std::unordered_map<std::string, ImageMetadata>& metaData, const gltf2::TextureInfo& info) {
if(!info.mTexture->mSource->mUri.empty())
{
if(auto search = metaData.find(info.mTexture->mSource->mUri.data()); search != metaData.end())
{
meshDefinition.mBlendShapes.reserve(primitive.mTargets.size());
meshDefinition.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
+ uint32_t blendShapeIndex = 0u;
for(const auto& target : primitive.mTargets)
{
MeshDefinition::BlendShape blendShape;
blendShape.weight = mesh.mWeights[meshDefinition.mBlendShapes.size()];
}
+ // Get blendshape name from extras / SXR_targets_names / avatar_shape_names.
+ if(blendShapeIndex < mesh.mExtras.mTargetNames.size())
+ {
+ blendShape.name = mesh.mExtras.mTargetNames[blendShapeIndex];
+ }
+ else if(blendShapeIndex < mesh.mExtensions.mSXRTargetsNames.size())
+ {
+ blendShape.name = mesh.mExtensions.mSXRTargetsNames[blendShapeIndex];
+ }
+ else if(blendShapeIndex < mesh.mExtensions.mAvatarShapeNames.size())
+ {
+ blendShape.name = mesh.mExtensions.mAvatarShapeNames[blendShapeIndex];
+ }
+
meshDefinition.mBlendShapes.push_back(std::move(blendShape));
+ ++blendShapeIndex;
}
}
auto& resources = output.mResources;
const auto index = scene.GetNodeCount();
- auto weakNode = scene.AddNode([&]()
- {
+ auto weakNode = scene.AddNode([&]() {
std::unique_ptr<NodeDefinition> nodeDefinition{new NodeDefinition()};
nodeDefinition->mParentIdx = parentIndex;
json::SetObjectReader(GetMaterialExtensionsReader());
json::SetObjectReader(GetMaterialReader());
json::SetObjectReader(GetMeshPrimitiveReader());
+ json::SetObjectReader(GetMeshExtrasReader());
+ json::SetObjectReader(GetMeshExtensionsReader());
json::SetObjectReader(GetMeshReader());
json::SetObjectReader(GetSkinReader());
json::SetObjectReader(GetCameraPerspectiveReader());
return static_cast<E>(number);
}
+ static std::string_view StringView(const json_string_s& js)
+ {
+ return std::string_view(js.string, js.string_size);
+ }
+
static std::string_view StringView(const json_value_s& j)
{
auto& js = Cast<json_string_s>(j);
- return std::string_view(js.string, js.string_size);
+ return StringView(js);
}
static std::string String(const json_value_s& j)
#include <dali/public-api/object/type-registry.h>
// INTERNAL INCLUDES
-#include <dali-scene3d/internal/model-components/model-primitive-impl.h>
#include <dali-scene3d/internal/light/light-impl.h>
+#include <dali-scene3d/internal/model-components/model-primitive-impl.h>
namespace Dali
{
return Scene3D::ModelNode::DownCast(childActor);
}
+void ModelNode::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
+{
+ blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeIndexMap.size());
+ for(const auto& iter : mBlendShapeIndexMap)
+ {
+ blendShapeNames.push_back(iter.first);
+ }
+}
+
+Loader::BlendShapes::Index ModelNode::GetBlendShapeIndexByName(std::string_view blendShapeName) const
+{
+ auto iter = mBlendShapeIndexMap.find(std::string(blendShapeName));
+ if(iter != mBlendShapeIndexMap.end())
+ {
+ return iter->second;
+ }
+ return Loader::BlendShapes::INVALID_INDEX;
+}
+
void ModelNode::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
{
mDiffuseTexture = diffuseTexture;
void ModelNode::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data, Scene3D::ModelPrimitive primitive)
{
+ // Update mBlendShapeIndexMap
+ mBlendShapeIndexMap.clear();
+ const auto blendShapeCount = data.names.size();
+ for(Loader::BlendShapes::Index index = 0u; index < blendShapeCount; ++index)
+ {
+ auto& name = data.names[index];
+ if(!name.empty())
+ {
+ mBlendShapeIndexMap[name] = index;
+ }
+ }
+
GetImplementation(primitive).SetBlendShapeData(data);
}
Matrix inverseMatrix = boneData.inverseMatrix;
// Constrain bone matrix to joint transform.
- boneData.constraint = Constraint::New<Matrix>(renderer, propBoneXform, [inverseMatrix](Matrix& output, const PropertyInputContainer& inputs)
- { Matrix::Multiply(output, inverseMatrix, inputs[0]->GetMatrix()); });
+ boneData.constraint = Constraint::New<Matrix>(renderer, propBoneXform, [inverseMatrix](Matrix& output, const PropertyInputContainer& inputs) { Matrix::Multiply(output, inverseMatrix, inputs[0]->GetMatrix()); });
Actor joint = Self();
boneData.constraint.AddSource(Source{joint, Actor::Property::WORLD_MATRIX});
*/
// EXTERNAL INCLUDES
+#include <dali/devel-api/common/map-wrapper.h>
#include <dali/public-api/actors/custom-actor-impl.h>
#include <dali/public-api/common/dali-common.h>
#include <memory> // for std::unique_ptr
+#include <string>
// INTERNAL INCLUDES
#include <dali-scene3d/internal/model-components/model-primitive-modify-observer.h>
public:
using ModelPrimitiveContainer = std::vector<Scene3D::ModelPrimitive>;
using BoneDataContainer = std::vector<Dali::Scene3D::Loader::Skinning::BoneData>;
+ using BlendShapeIndexMap = std::map<std::string, Loader::BlendShapes::Index>;
// Creation & Destruction
/**
Scene3D::ModelNode FindChildModelNodeByName(std::string_view nodeName);
/**
+ * @copydoc Dali::Scene3D::ModelNode::RetrieveBlendShapeNames()
+ */
+ void RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const;
+
+ /**
+ * @copydoc Dali::Scene3D::ModelNode::GetBlendShapeIndexByName()
+ */
+ Loader::BlendShapes::Index GetBlendShapeIndexByName(std::string_view blendShapeName) const;
+
+ /**
* @brief Sets the diffuse and specular image-based lighting textures for a ModelPrimitive.
*
* @param[in] diffuseTexture The diffuse texture.
/// @cond internal
// Not copyable or movable
- DALI_INTERNAL ModelNode(const ModelNode&) = delete; ///< Deleted copy constructor.
- DALI_INTERNAL ModelNode(ModelNode&&) = delete; ///< Deleted move constructor.
+ DALI_INTERNAL ModelNode(const ModelNode&) = delete; ///< Deleted copy constructor.
+ DALI_INTERNAL ModelNode(ModelNode&&) = delete; ///< Deleted move constructor.
DALI_INTERNAL ModelNode& operator=(const ModelNode&) = delete; ///< Deleted copy assignment operator.
- DALI_INTERNAL ModelNode& operator=(ModelNode&&) = delete; ///< Deleted move assignment operator.
+ DALI_INTERNAL ModelNode& operator=(ModelNode&&) = delete; ///< Deleted move assignment operator.
private:
ModelPrimitiveContainer mModelPrimitiveContainer; ///< List of model primitives
BoneDataContainer mBoneDataContainer;
+ BlendShapeIndexMap mBlendShapeIndexMap; ///< Index of blend shape by name
Dali::Texture mSpecularTexture;
Dali::Texture mDiffuseTexture;
float mIblScaleFactor{1.0f};
return GetImpl(*this).FindChildModelNodeByName(nodeName);
}
+void Model::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
+{
+ GetImpl(*this).RetrieveBlendShapeNames(blendShapeNames);
+}
+
+void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<ModelNode>& modelNodes) const
+{
+ GetImpl(*this).RetrieveModelNodesByBlendShapeName(blendShapeName, modelNodes);
+}
+
} // namespace Scene3D
} // namespace Dali
/**
* @brief Returns a child ModelNode object with a name that matches nodeName.
*
+ * @SINCE_2_2.34
* @param[in] nodeName The name of the child ModelNode object you want to find.
* @return Returns a child ModelNode object with a name that matches nodeName. If there is no corresponding child ModelNode object, it returns an empty ModelNode object.
*/
ModelNode FindChildModelNodeByName(std::string_view nodeName);
+ /**
+ * @brief Retrieve the list of blendshape name that current Model hold.
+ * The name will be appended end of input list.
+ *
+ * @SINCE_2_2.34
+ * @param[in, out] blendShapeNames The name of blendShape list collected.
+ * @note This method should be called after Model load finished.
+ */
+ void RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const;
+
+ /**
+ * @brief Retrieve the list of ModelNode that contains given blend shape name.
+ * The ModelNode will be appended end of input list.
+ *
+ * @SINCE_2_2.34
+ * @param[in] blendShapeName The name of blendShape that want to collect.
+ * @param[in, out] modelNodes The ModelNode list collected.
+ * @note This method should be called after Model load finished.
+ */
+ void RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<ModelNode>& modelNodes) const;
+
public: // Not intended for application developers
/// @cond internal
/**
#include <dali/public-api/common/vector-wrapper.h>
#include <dali/public-api/object/weak-handle.h>
#include <dali/public-api/rendering/shader.h>
+#include <limits> ///< for std::numeric_limits
#include <string>
// INTERNAL INCLUDES
struct DALI_SCENE3D_API BlendShapes
{
+ using Index = uint32_t;
+ static constexpr Index INVALID_INDEX = std::numeric_limits<Index>::max();
+
enum class Version
{
VERSION_1_0,
struct BlendShapeData
{
- std::vector<float> weights;
- std::vector<float> unnormalizeFactors;
- Version version{Scene3D::Loader::BlendShapes::Version::INVALID};
- uint32_t bufferOffset{0};
- int32_t components{0x0};
- Dali::WeakHandle<Actor> mActor;
+ std::vector<std::string> names;
+ std::vector<float> weights;
+ std::vector<float> unnormalizeFactors;
+ Version version{Scene3D::Loader::BlendShapes::Version::INVALID};
+ uint32_t bufferOffset{0};
+ int32_t components{0x0};
+ Dali::WeakHandle<Actor> mActor;
};
// shader properties - animatable (uniforms)
data.components = 0x0;
for(auto&& blendShape : mesh.first.mBlendShapes)
{
+ data.names.push_back(blendShape.name);
data.weights.push_back(blendShape.weight);
data.components |= (blendShape.deltas.IsDefined() * BlendShapes::Component::POSITIONS) |
(blendShape.normals.IsDefined() * BlendShapes::Component::NORMALS) | (blendShape.tangents.IsDefined() * BlendShapes::Component::TANGENTS);
return Internal::GetImplementation(*this).FindChildModelNodeByName(nodeName);
}
+void ModelNode::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
+{
+ return Internal::GetImplementation(*this).RetrieveBlendShapeNames(blendShapeNames);
+}
+
+Loader::BlendShapes::Index ModelNode::GetBlendShapeIndexByName(std::string_view blendShapeName) const
+{
+ return Internal::GetImplementation(*this).GetBlendShapeIndexByName(blendShapeName);
+}
+
} // namespace Scene3D
} // namespace Dali
// INTERNAL INCLUDES
#include <dali-scene3d/public-api/api.h>
+#include <dali-scene3d/public-api/loader/blend-shape-details.h> ///< For Loader::BlendShapes::Index
#include <dali-scene3d/public-api/model-components/model-primitive.h>
namespace Dali
static ModelNode DownCast(BaseHandle handle);
public: // Public Method
-
/**
* @brief Gets the number of ModelPrimitives this node has.
*
/**
* @brief Returns a child ModelNode object with a name that matches nodeName.
*
+ * @SINCE_2_2.99
* @param[in] nodeName The name of the child ModelNode object you want to find.
* @return Returns a child ModelNode object with a name that matches nodeName. If there is no corresponding child ModelNode object, it returns an empty ModelNode object.
*/
ModelNode FindChildModelNodeByName(std::string_view nodeName);
+ /**
+ * @brief Retrieve the list of blendshape name that current ModelNode hold.
+ * The name will be appended end of input list.
+ *
+ * @SINCE_2_2.99
+ * @param[in, out] blendShapeNames The name of blendShape list collected.
+ */
+ void RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const;
+
+ /**
+ * @brief Get the index of blend shape by given name.
+ *
+ * @SINCE_2_2.99
+ * @param[in] blendShapeName The name of blendshape that is not empty.
+ * @return Index of blendshape, or return invalid if there is no blendshape with given name.
+ */
+ Loader::BlendShapes::Index GetBlendShapeIndexByName(std::string_view blendShapeName) const;
+
public: // Not intended for application developers
/// @cond internal
/**