/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
*/
-// INTERNAL
-#include "dali-scene3d/public-api/loader/node-definition.h"
-#include "dali-scene3d/public-api/loader/renderer-state.h"
-#include "dali-scene3d/public-api/loader/utils.h"
+// CLASS HEADER
+#include <dali-scene3d/public-api/loader/node-definition.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/light/light-impl.h>
+#include <dali-scene3d/internal/model-components/material-impl.h>
+#include <dali-scene3d/internal/model-components/model-node-impl.h>
+#include <dali-scene3d/internal/model-components/model-primitive-impl.h>
+#include <dali-scene3d/public-api/loader/renderer-state.h>
+#include <dali-scene3d/public-api/loader/utils.h>
namespace Dali
{
namespace
{
-constexpr std::string_view IBL_INTENSITY_STRING("uIblIntensity");
-constexpr std::string_view IBL_Y_DIRECTION("uYDirection");
+static constexpr std::string_view IBL_INTENSITY_STRING("uIblIntensity");
+static constexpr std::string_view IBL_Y_DIRECTION("uYDirection");
+static constexpr std::string_view IBL_MAXLOD("uMaxLOD");
+
+static constexpr uint32_t MAX_NUMBER_OF_MATERIAL_TEXTURE = 7;
+static constexpr uint32_t SEMANTICS[MAX_NUMBER_OF_MATERIAL_TEXTURE] =
+ {
+ Scene3D::Loader::MaterialDefinition::ALBEDO,
+ Scene3D::Loader::MaterialDefinition::METALLIC | Scene3D::Loader::MaterialDefinition::ROUGHNESS,
+ Scene3D::Loader::MaterialDefinition::NORMAL,
+ Scene3D::Loader::MaterialDefinition::OCCLUSION,
+ Scene3D::Loader::MaterialDefinition::EMISSIVE,
+ Scene3D::Loader::MaterialDefinition::SPECULAR,
+ Scene3D::Loader::MaterialDefinition::SPECULAR_COLOR,
+};
+
+static constexpr Scene3D::Material::TextureType TEXTURE_TYPES[MAX_NUMBER_OF_MATERIAL_TEXTURE] =
+ {
+ Scene3D::Material::TextureType::BASE_COLOR,
+ Scene3D::Material::TextureType::METALLIC_ROUGHNESS,
+ Scene3D::Material::TextureType::NORMAL,
+ Scene3D::Material::TextureType::OCCLUSION,
+ Scene3D::Material::TextureType::EMISSIVE,
+ Scene3D::Material::TextureType::SPECULAR,
+ Scene3D::Material::TextureType::SPECULAR_COLOR,
+};
+
+Vector4 GetTextureFactor(Scene3D::Loader::MaterialDefinition& materialDefinition, uint32_t semantic)
+{
+ Vector4 factor = Vector4::ONE;
+ switch(semantic)
+ {
+ case Scene3D::Loader::MaterialDefinition::ALBEDO:
+ factor = materialDefinition.mBaseColorFactor;
+ break;
+ case Scene3D::Loader::MaterialDefinition::METALLIC | Scene3D::Loader::MaterialDefinition::ROUGHNESS:
+ factor = Vector4(materialDefinition.mMetallic, materialDefinition.mRoughness, 0.0f, 0.0f);
+ break;
+ case Scene3D::Loader::MaterialDefinition::NORMAL:
+ factor.x = materialDefinition.mNormalScale;
+ break;
+ case Scene3D::Loader::MaterialDefinition::OCCLUSION:
+ factor.x = materialDefinition.mOcclusionStrength;
+ break;
+ case Scene3D::Loader::MaterialDefinition::EMISSIVE:
+ factor = materialDefinition.mEmissiveFactor;
+ break;
+ case Scene3D::Loader::MaterialDefinition::SPECULAR:
+ factor.x = materialDefinition.mSpecularFactor;
+ break;
+ case Scene3D::Loader::MaterialDefinition::SPECULAR_COLOR:
+ factor = materialDefinition.mSpecularColorFactor;
+ break;
+ default:
+ break;
+ }
+ return factor;
+}
+
} // namespace
namespace Scene3D
reflector.Reflect(ResourceType::Shader, mShaderIdx);
}
-void NodeDefinition::Renderable::OnCreate(const NodeDefinition& node, CreateParams& params, Actor& actor) const
+void NodeDefinition::Renderable::OnCreate(const NodeDefinition& nodeDefinition, CreateParams& params, ModelNode& node) const
{
DALI_ASSERT_DEBUG(mShaderIdx != INVALID_INDEX);
auto& resources = params.mResources;
RendererState::Apply(resources.mShaders[mShaderIdx].first.mRendererState, renderer);
- actor.AddRenderer(renderer);
+ node.AddRenderer(renderer);
}
-const std::string NodeDefinition::ORIGINAL_MATRIX_PROPERTY_NAME = "originalMatrix";
+const char* NodeDefinition::ORIGINAL_MATRIX_PROPERTY_NAME = "originalMatrix";
-Actor NodeDefinition::CreateActor(CreateParams& params) const
+ModelNode NodeDefinition::CreateModelNode(CreateParams& params)
{
- Actor actor = Actor::New();
- SetActorCentered(actor);
+ ModelNode node = ModelNode::New();
+ mNodeId = node.GetProperty<int32_t>(Dali::Actor::Property::ID);
+
+ SetActorCentered(node);
+
+ node.SetProperty(Actor::Property::NAME, mName);
+ node.SetProperty(Actor::Property::POSITION, mPosition);
+ node.SetProperty(Actor::Property::ORIENTATION, mOrientation);
+ node.SetProperty(Actor::Property::SCALE, mScale);
+ node.SetProperty(Actor::Property::SIZE, mSize);
+ node.SetProperty(Actor::Property::VISIBLE, mIsVisible);
- actor.SetProperty(Actor::Property::NAME, mName);
- actor.SetProperty(Actor::Property::POSITION, mPosition);
- actor.SetProperty(Actor::Property::ORIENTATION, mOrientation);
- actor.SetProperty(Actor::Property::SCALE, mScale);
- actor.SetProperty(Actor::Property::SIZE, mSize);
- actor.SetProperty(Actor::Property::VISIBLE, mIsVisible);
+ node.RegisterProperty(ORIGINAL_MATRIX_PROPERTY_NAME, GetLocalSpace(), Property::AccessMode::READ_ONLY);
- actor.RegisterProperty(ORIGINAL_MATRIX_PROPERTY_NAME, GetLocalSpace(), Property::AccessMode::READ_ONLY);
+ node.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
- if(mRenderable)
+ for(auto& renderable : mRenderables)
{
- mRenderable->OnCreate(*this, params, actor);
+ renderable->OnCreate(*this, params, node);
}
for(auto& e : mExtras)
{
- actor.RegisterProperty(e.mKey, e.mValue);
+ node.RegisterProperty(e.mKey, e.mValue);
}
for(auto& c : mConstraints)
{
- params.mConstrainables.push_back(ConstraintRequest{&c, actor});
+ params.mConstrainables.push_back(ConstraintRequest{&c, node});
}
- return actor;
+ return node;
}
Matrix NodeDefinition::GetLocalSpace() const
return IBL_Y_DIRECTION;
}
+std::string_view NodeDefinition::GetIblMaxLodUniformName()
+{
+ return IBL_MAXLOD;
+}
+
bool NodeDefinition::GetExtents(const ResourceBundle& resources, Vector3& min, Vector3& max) const
{
- if(mRenderable)
+ if(mRenderables.empty())
{
- if(!mRenderable->GetExtents(resources, min, max))
+ return false;
+ }
+
+ bool useModelExtents = false;
+ for(auto& renderable : mRenderables)
+ {
+ Vector3 renderableMin(Vector3::ONE * MAXFLOAT), renderableMax(-Vector3::ONE * MAXFLOAT);
+ if(!renderable->GetExtents(resources, renderableMin, renderableMax))
{
- // If the renderable node don't have mesh accessor, use size to compute extents.
- min = -mSize / 2.0f;
- max = mSize / 2.0f;
+ useModelExtents = false;
+ break;
}
- return true;
+ useModelExtents = true;
+ min.x = std::min(min.x, renderableMin.x);
+ min.y = std::min(min.y, renderableMin.y);
+ min.z = std::min(min.z, renderableMin.z);
+ max.x = std::max(max.x, renderableMax.x);
+ max.y = std::max(max.y, renderableMax.y);
+ max.z = std::max(max.z, renderableMax.z);
}
- return false;
+ if(!useModelExtents)
+ {
+ // If the renderable node don't have mesh accessor, use size to compute extents.
+ min = -mSize / 2.0f;
+ max = mSize / 2.0f;
+ }
+ return true;
}
-bool ModelNode::GetExtents(const ResourceBundle& resources, Vector3& min, Vector3& max) const
+bool ModelRenderable::GetExtents(const ResourceBundle& resources, Vector3& min, Vector3& max) const
{
auto& mesh = resources.mMeshes[mMeshIdx];
uint32_t minSize = mesh.first.mPositions.mBlob.mMin.size();
return false;
}
-void ModelNode::RegisterResources(IResourceReceiver& receiver) const
+void ModelRenderable::RegisterResources(IResourceReceiver& receiver) const
{
Renderable::RegisterResources(receiver);
receiver.Register(ResourceType::Mesh, mMeshIdx);
receiver.Register(ResourceType::Material, mMaterialIdx);
}
-void ModelNode::ReflectResources(IResourceReflector& reflector)
+void ModelRenderable::ReflectResources(IResourceReflector& reflector)
{
Renderable::ReflectResources(reflector);
reflector.Reflect(ResourceType::Mesh, mMeshIdx);
reflector.Reflect(ResourceType::Material, mMaterialIdx);
}
-void ModelNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const
+// How many shader managers are there?!
+void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinition::CreateParams& params, ModelNode& node) const
{
DALI_ASSERT_DEBUG(mMeshIdx != INVALID_INDEX);
- Renderable::OnCreate(node, params, actor);
+ ShaderOption::HashType shaderOptionHash{0u};
+ if(mShaderIdx == INVALID_INDEX)
+ {
+ ShaderOption option = params.mShaderManager->ProduceShaderOption(params.mResources.mMaterials[mMaterialIdx].first,
+ params.mResources.mMeshes[mMeshIdx].first);
+ shaderOptionHash = option.GetOptionHash();
+ Shader shader = params.mShaderManager->ProduceShader(option);
+
+ static Geometry defaultGeometry = Geometry::New();
+ Renderer renderer = Renderer::New(defaultGeometry, shader);
+
+ RendererState::Apply(params.mShaderManager->GetRendererState(params.mResources.mMaterials[mMaterialIdx].first), renderer);
+ Internal::GetImplementation(node).UpdateShader(params.mShaderManager);
+ node.AddRenderer(renderer);
+ }
+ else
+ {
+ Renderable::OnCreate(nodeDefinition, params, node);
+ }
auto& resources = params.mResources;
auto& mesh = resources.mMeshes[mMeshIdx];
- auto renderer = actor.GetRendererAt(0);
+ auto renderer = node.GetRendererAt(node.GetRendererCount() - 1u);
Geometry geometry = mesh.second.geometry;
renderer.SetGeometry(geometry);
- auto shader = renderer.GetShader();
-
- if(mesh.first.IsSkinned())
- {
- params.mSkinnables.push_back(SkinningShaderConfigurationRequest{mesh.first.mSkeletonIdx, shader});
- }
-
- if(mesh.first.HasBlendShapes())
- {
- params.mBlendshapeRequests.push_back(BlendshapeShaderConfigurationRequest{node.mName, mMeshIdx, shader});
- }
-
TextureSet textures = resources.mMaterials[mMaterialIdx].second;
-
// Set the blend shape texture.
if(mesh.second.blendShapeGeometry)
{
textures = newTextureSet;
}
-
renderer.SetTextures(textures);
- actor.SetProperty(Actor::Property::COLOR, mColor);
-
- actor.RegisterProperty("uHasVertexColor", static_cast<float>(mesh.first.mColors.IsDefined()));
-
- auto& matDef = resources.mMaterials[mMaterialIdx].first;
- actor.RegisterProperty("uColorFactor", matDef.mBaseColorFactor);
- actor.RegisterProperty("uMetallicFactor", matDef.mMetallic);
- actor.RegisterProperty("uRoughnessFactor", matDef.mRoughness);
- actor.RegisterProperty("uNormalScale", matDef.mNormalScale);
- if(matDef.mFlags & MaterialDefinition::OCCLUSION)
{
- actor.RegisterProperty("uOcclusionStrength", matDef.mOcclusionStrength);
+ mesh.first.mModelPrimitive = ModelPrimitive::New();
+ auto& primitive = GetImplementation(mesh.first.mModelPrimitive);
+ primitive.SetRenderer(renderer);
+
+ Index envIndex = resources.mMaterials[mMaterialIdx].first.mEnvironmentIdx;
+ uint32_t specularMipmap = resources.mEnvironmentMaps[envIndex].second.mSpecularMipmapLevels;
+ primitive.SetImageBasedLightTexture(resources.mEnvironmentMaps[envIndex].second.mDiffuse,
+ resources.mEnvironmentMaps[envIndex].second.mSpecular,
+ resources.mEnvironmentMaps[envIndex].first.mIblIntensity,
+ specularMipmap);
+
+ bool hasPositions = false;
+ bool hasNormals = false;
+ bool hasTangents = false;
+ mesh.first.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
+ primitive.SetBlendShapeOptions(hasPositions, hasNormals, hasTangents, mesh.first.mBlendShapeVersion);
+ primitive.SetBlendShapeGeometry(mesh.second.blendShapeGeometry);
+ primitive.SetSkinned(mesh.first.IsSkinned(), mesh.first.GetNumberOfJointSets());
+ primitive.SetVertexColor(mesh.first.HasVertexColor());
}
- if(matDef.mFlags & MaterialDefinition::EMISSIVE)
+
+ auto shader = renderer.GetShader();
+ if(mesh.first.IsSkinned())
{
- actor.RegisterProperty("uEmissiveFactor", matDef.mEmissiveFactor);
+ params.mSkinnables.push_back(SkinningShaderConfigurationRequest{mesh.first.mSkeletonIdx, shader, mesh.first.mModelPrimitive});
}
- Index envIdx = matDef.mEnvironmentIdx;
- actor.RegisterProperty(IBL_INTENSITY_STRING.data(), resources.mEnvironmentMaps[envIdx].first.mIblIntensity);
- actor.RegisterProperty(IBL_Y_DIRECTION.data(), resources.mEnvironmentMaps[envIdx].first.mYDirection);
+ if(mesh.first.HasBlendShapes())
+ {
+ params.mBlendshapeRequests.push_back(BlendshapeShaderConfigurationRequest{nodeDefinition.mName, mMeshIdx, shader, mesh.first.mModelPrimitive});
+ }
- float opaque = 0.0f;
- float mask = 0.0f;
- float alphaCutoff = matDef.GetAlphaCutoff();
- if(!MaskMatch(matDef.mFlags, MaterialDefinition::TRANSPARENCY))
+ auto& matDef = resources.mMaterials[mMaterialIdx].first;
+ renderer.RegisterProperty("uColorFactor", matDef.mBaseColorFactor);
+ renderer.RegisterProperty("uMetallicFactor", matDef.mMetallic);
+ renderer.RegisterProperty("uRoughnessFactor", matDef.mRoughness);
+ renderer.RegisterProperty("uDielectricSpecular", matDef.mDielectricSpecular);
+ renderer.RegisterProperty("uSpecularFactor", matDef.mSpecularFactor);
+ renderer.RegisterProperty("uSpecularColorFactor", matDef.mSpecularColorFactor);
+ renderer.RegisterProperty("uNormalScale", matDef.mNormalScale);
+ renderer.RegisterProperty("uEmissiveFactor", matDef.mEmissiveFactor);
+ if(matDef.mFlags & MaterialDefinition::OCCLUSION)
{
- opaque = 1.0f;
+ renderer.RegisterProperty("uOcclusionStrength", matDef.mOcclusionStrength);
}
- else
+
+ float opaque = matDef.mIsOpaque ? 1.0f : 0.0f;
+ float mask = matDef.mIsMask ? 1.0f : 0.0f;
+ float alphaCutoff = matDef.GetAlphaCutoff();
+
+ renderer.RegisterProperty("uOpaque", opaque);
+ renderer.RegisterProperty("uMask", mask);
+ renderer.RegisterProperty("uAlphaThreshold", alphaCutoff);
+
+ Index envIndex = matDef.mEnvironmentIdx;
+ uint32_t specularMipmap = resources.mEnvironmentMaps[envIndex].second.mSpecularMipmapLevels;
+ renderer.RegisterProperty(IBL_MAXLOD.data(), static_cast<float>(specularMipmap));
+ renderer.RegisterProperty(IBL_INTENSITY_STRING.data(), resources.mEnvironmentMaps[envIndex].first.mIblIntensity);
+ renderer.RegisterProperty(IBL_Y_DIRECTION.data(), resources.mEnvironmentMaps[envIndex].first.mYDirection);
+
+ node.SetProperty(Actor::Property::COLOR, mColor);
+
+ // If user uses customshader, the properties of the shader could not be changed by Material.
+ if(mShaderIdx == INVALID_INDEX)
{
- if(alphaCutoff > 0.f)
+ matDef.mMaterial = Material::New();
+ auto material = matDef.mMaterial;
+ uint32_t textureIndexOffset = (mesh.second.blendShapeGeometry) ? 1 : 0;
+ uint32_t textureIndex = 0;
+ for(uint32_t i = 0; i < MAX_NUMBER_OF_MATERIAL_TEXTURE; ++i)
{
- mask = 1.0f;
+ Internal::Material::TextureInformation textureInformation;
+ if(matDef.CheckTextures(SEMANTICS[i]))
+ {
+ textureInformation.mTexture = textures.GetTexture(textureIndex + textureIndexOffset);
+ textureInformation.mSampler = textures.GetSampler(textureIndex + textureIndexOffset);
+ textureInformation.mUrl = matDef.mTextureStages[textureIndex].mTexture.mDirectoryPath + matDef.mTextureStages[textureIndex].mTexture.mImageUri;
+ textureIndex++;
+ }
+ textureInformation.mFactor = GetTextureFactor(matDef, SEMANTICS[i]);
+ GetImplementation(material).SetTextureInformation(TEXTURE_TYPES[i], std::move(textureInformation));
}
+ material.SetProperty(Scene3D::Material::Property::ALPHA_MODE, matDef.mAlphaModeType);
+ material.SetProperty(Scene3D::Material::Property::ALPHA_CUTOFF, matDef.GetAlphaCutoff());
+ material.SetProperty(Scene3D::Material::Property::DOUBLE_SIDED, matDef.mDoubleSided);
+ material.SetProperty(Scene3D::Material::Property::IOR, matDef.mIor);
+
+ // This _should_ keep the same shader as generated at the top of the method.
+ GetImplementation(mesh.first.mModelPrimitive).SetMaterial(material, false);
+ GetImplementation(material).ResetFlag();
}
- actor.RegisterProperty("uOpaque", opaque);
- actor.RegisterProperty("uMask", mask);
- actor.RegisterProperty("uAlphaThreshold", alphaCutoff);
+
+ Internal::GetImplementation(node).AddModelPrimitive(mesh.first.mModelPrimitive, shaderOptionHash);
}
-void ArcNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const
+void ArcRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinition::CreateParams& params, ModelNode& node) const
{
- ModelNode::OnCreate(node, params, actor);
+ ModelRenderable::OnCreate(nodeDefinition, params, node);
- actor.RegisterProperty("antiAliasing", mAntiAliasing ? 1 : 0);
- actor.RegisterProperty("arcCaps", mArcCaps);
- actor.RegisterProperty("radius", mRadius);
+ node.RegisterProperty("antiAliasing", mAntiAliasing ? 1 : 0);
+ node.RegisterProperty("arcCaps", mArcCaps);
+ node.RegisterProperty("radius", mRadius);
const float startAngleRadians = mStartAngleDegrees * Math::PI_OVER_180;
Vector2 startPolar{std::cos(startAngleRadians), std::sin(startAngleRadians)};
- actor.RegisterProperty("startAngle", startPolar);
+ node.RegisterProperty("startAngle", startPolar);
const float endAngleRadians = mEndAngleDegrees * Math::PI_OVER_180;
Vector2 endPolar{std::cos(endAngleRadians), std::sin(endAngleRadians)};
- actor.RegisterProperty("endAngle", endPolar);
+ node.RegisterProperty("endAngle", endPolar);
}
-void ArcNode::GetEndVectorWithDiffAngle(float startAngle, float diffAngle, Vector2& endVector)
+void ArcRenderable::GetEndVectorWithDiffAngle(float startAngle, float diffAngle, Vector2& endVector)
{
float endAngle = 0.f;
if(diffAngle <= 0.001f)
{
- //0.001 is used to ensure is empty arc when startAngle = endAngle + 360 * N
+ // 0.001 is used to ensure is empty arc when startAngle = endAngle + 360 * N
endAngle = startAngle + 0.001f;
}
else if(diffAngle >= 360.f)