Added vertex color test to model primitive 45/301045/1
authorDavid Steele <david.steele@samsung.com>
Mon, 6 Nov 2023 13:43:13 +0000 (13:43 +0000)
committerDavid Steele <david.steele@samsung.com>
Tue, 7 Nov 2023 13:51:23 +0000 (13:51 +0000)
Modifying model loading to reduce shader churn
Changed ShaderManager to return shader option
Added debug across shader generation

Change-Id: Icbe72d36bc92e8e2d7735a1c13a0be73eab79312
Signed-off-by: David Steele <david.steele@samsung.com>
dali-scene3d/internal/model-components/model-node-impl.cpp
dali-scene3d/internal/model-components/model-node-impl.h
dali-scene3d/internal/model-components/model-primitive-impl.cpp
dali-scene3d/internal/model-components/model-primitive-impl.h
dali-scene3d/public-api/loader/mesh-definition.cpp
dali-scene3d/public-api/loader/mesh-definition.h
dali-scene3d/public-api/loader/node-definition.cpp
dali-scene3d/public-api/loader/shader-manager.cpp
dali-scene3d/public-api/loader/shader-manager.h
dali-scene3d/public-api/loader/shader-option.h
dali-scene3d/public-api/model-components/model-node.cpp

index 8370795..6cbc92b 100644 (file)
@@ -173,7 +173,7 @@ uint32_t ModelNode::GetModelPrimitiveCount() const
   return static_cast<uint32_t>(mModelPrimitiveContainer.size());
 }
 
-void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
+void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive, Loader::ShaderOption::HashType hash)
 {
   for(auto&& primitive : mModelPrimitiveContainer)
   {
@@ -197,7 +197,7 @@ void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
     GetImplementation(modelPrimitive).SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
   }
 
-  GetImplementation(modelPrimitive).UpdateShader(mShaderManager);
+  GetImplementation(modelPrimitive).UpdateShader(mShaderManager, hash);
 
   Dali::Renderer renderer = GetImplementation(modelPrimitive).GetRenderer();
   if(renderer)
@@ -241,7 +241,7 @@ void ModelNode::RemoveModelPrimitive(uint32_t index)
     return;
   }
 
-  GetImplementation(mModelPrimitiveContainer[index]).UpdateShader(nullptr);
+  GetImplementation(mModelPrimitiveContainer[index]).UpdateShader(nullptr, 0u);
 
   Actor self = Self();
   GetImplementation(mModelPrimitiveContainer[index]).RemovePrimitiveObserver(this);
@@ -326,7 +326,7 @@ void ModelNode::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
     mShaderManager = shaderManager;
     for(auto&& primitive : mModelPrimitiveContainer)
     {
-      GetImplementation(primitive).UpdateShader(mShaderManager);
+      GetImplementation(primitive).UpdateShader(mShaderManager, 0u);
     }
   }
 }
index ed17a45..7399406 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-scene3d/public-api/light/light.h>
 #include <dali-scene3d/public-api/loader/mesh-definition.h>
 #include <dali-scene3d/public-api/loader/shader-manager.h>
+#include <dali-scene3d/public-api/loader/shader-option.h>
 #include <dali-scene3d/public-api/loader/skinning-details.h>
 #include <dali-scene3d/public-api/model-components/model-node.h>
 #include <dali-scene3d/public-api/model-components/model-primitive.h>
@@ -198,7 +199,7 @@ public: // Public Method
   /**
    * @copydoc Dali::Scene3D::ModelNode::AddModelPrimitive()
    */
-  void AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive);
+  void AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive, Loader::ShaderOption::HashType hash);
 
   /**
    * @copydoc Dali::Scene3D::ModelNode::RemoveModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
@@ -306,7 +307,7 @@ private:
   Scene3D::Loader::ShaderManagerPtr mShaderManager;
   ModelPrimitiveContainer           mModelPrimitiveContainer; ///< List of model primitives
   BoneDataContainer                 mBoneDataContainer;
-  BlendShapeIndexMap                mBlendShapeIndexMap;      ///< Index of blend shape by name
+  BlendShapeIndexMap                mBlendShapeIndexMap; ///< Index of blend shape by name
   Dali::Texture                     mShadowMapTexture;
   Dali::Texture                     mSpecularTexture;
   Dali::Texture                     mDiffuseTexture;
index 0a079ff..e58327c 100644 (file)
 #include <dali/public-api/object/property-array.h>
 #include <dali/public-api/object/property-map.h>
 
+#if defined(DEBUG_ENABLED)
+#include <sys/types.h>
+#include <unistd.h>
 #include <filesystem>
 namespace fs = std::filesystem;
+#endif
 
 namespace Dali
 {
@@ -48,6 +52,15 @@ namespace
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_SCENE3D_MODEL_PRIMITIVE");
 
+std::string tmpFilename(std::string prefix, std::string suffix)
+{
+  static int id = 0;
+  id++;
+  std::ostringstream oss;
+  oss << prefix << getpid() << "_" << std::setfill('0') << std::setw(4) << id << suffix;
+  return oss.str();
+}
+
 #define DALI_LOG_WRITE_FILE(filename, stream) \
   {                                           \
     fs::path tmp = fs::temp_directory_path(); \
@@ -230,14 +243,14 @@ void ModelPrimitive::SetImageBasedLightScaleFactor(float iblScaleFactor)
   }
 }
 
-void ModelPrimitive::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
+void ModelPrimitive::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager, Loader::ShaderOption::HashType hash)
 {
   if(mShaderManager != shaderManager)
   {
     mShaderManager = (shaderManager) ? shaderManager : new Scene3D::Loader::ShaderManager();
     if(mMaterial && GetImplementation(mMaterial).IsResourceReady())
     {
-      ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag::SHADER);
+      ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag::SHADER, hash);
     }
   }
 }
@@ -267,6 +280,11 @@ void ModelPrimitive::SetSkinned(bool isSkinned, uint32_t numberOfJointSets)
   mNumberOfJointSets = numberOfJointSets;
 }
 
+void ModelPrimitive::SetVertexColor(bool hasVertexColor)
+{
+  mHasVertexColor = hasVertexColor;
+}
+
 // From MaterialModifyObserver
 
 void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, MaterialModifyObserver::ModifyFlag flag)
@@ -274,7 +292,7 @@ void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, Materi
   ApplyMaterialToRenderer(flag);
 }
 
-void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
+void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag, Loader::ShaderOption::HashType oldHash)
 {
   if(!mMaterial)
   {
@@ -292,6 +310,10 @@ void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag
       shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::SKINNING);
       shaderOption.AddJointMacros(mNumberOfJointSets);
     }
+    if(mHasVertexColor)
+    {
+      shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::COLOR_ATTRIBUTE);
+    }
     if(mHasPositions || mHasNormals || mHasTangents)
     {
       if(mHasPositions)
@@ -315,19 +337,20 @@ void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag
     Shader newShader = mShaderManager->ProduceShader(shaderOption);
     if(mShader != newShader)
     {
-      DALI_LOG_INFO(gLogFilter, Debug::General, "Warning!  Model primitive shader changed\n");
+      DALI_LOG_INFO(gLogFilter, Debug::General, "Warning!  Model primitive shader changed: OldHash:%x NewHash:%x\n", oldHash, shaderOption.GetOptionHash());
+
 #if defined(DEBUG_ENABLED)
       if(mShader)
       {
         Property::Map oldMap = GetMap(mShader);
-        DALI_LOG_WRITE_FILE("oldShader.txt", "Vertex Shader:\n"
-                                               << oldMap["vertex"] << "\n\nFragmentShader: " << oldMap["fragment"] << "\n");
+        DALI_LOG_WRITE_FILE(tmpFilename("oldShader", ".txt"), "Vertex Shader:\n"
+                            << oldMap["vertex"] << "\n\nFragmentShader: " << oldMap["fragment"] << "\n");
       }
       if(newShader)
       {
         Property::Map newMap = GetMap(newShader);
-        DALI_LOG_WRITE_FILE("newShader.txt", "Vertex Shader:\n"
-                                               << newMap["vertex"] << "\n\nFragmentShader: " << newMap["fragment"] << "\n");
+        DALI_LOG_WRITE_FILE(tmpFilename("newShader", ".txt"), "Vertex Shader:\n"
+                            << newMap["vertex"] << "\n\nFragmentShader: " << newMap["fragment"] << "\n");
       }
 #endif
     }
index 1e6a04f..5913424 100644 (file)
@@ -151,8 +151,9 @@ public:
    * @brief Updates shaders by using current material
    *
    * @param[in] shaderManager Shader manager to create shader.
+   * @param[in] hash of old shader option
    */
-  void UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager);
+  void UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager, Loader::ShaderOption::HashType hash);
 
   /**
    * @brief Sets the blend shape data for this model primitive.
@@ -186,6 +187,13 @@ public:
    */
   void SetSkinned(bool isSkinned, uint32_t numberOfJointSets);
 
+  /**
+   * @brief Set whether this model primitve has vertex color attributes
+   *
+   * @param[in] hasVertexColor Whether or not this model primitive has vertex color attributes
+   */
+  void SetVertexColor(bool hasVertexColor);
+
 private: // From MaterialModifyObserver
   /**
    * @copydoc Dali::Scene3D::Internal::Material::MaterialModifyObserver::OnMaterialModified()
@@ -196,7 +204,8 @@ private:
   /**
    * @brief Apply materials data into renderer.
    */
-  void ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag = MaterialModifyObserver::ModifyFlag::NONE);
+  void ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag    = MaterialModifyObserver::ModifyFlag::NONE,
+                               Loader::ShaderOption::HashType     oldHash = 0u);
 
   /**
    * @brief Updates the uniform of renderer.
@@ -250,6 +259,7 @@ private:
   Scene3D::Loader::BlendShapes::BlendShapeData mBlendShapeData;
   Dali::Texture                                mBlendShapeGeometry;
   bool                                         mHasSkinning       = false;
+  bool                                         mHasVertexColor    = false;
   bool                                         mHasPositions      = false;
   bool                                         mHasNormals        = false;
   bool                                         mHasTangents       = false;
index 7875012..b7f8efc 100644 (file)
@@ -967,6 +967,12 @@ bool MeshDefinition::IsSkinned() const
 {
   return !mJoints.empty() && !mWeights.empty();
 }
+
+bool MeshDefinition::HasVertexColor() const
+{
+  return !mColors.empty();
+}
+
 uint32_t MeshDefinition::GetNumberOfJointSets() const
 {
   return static_cast<uint32_t>(mJoints.size());
index 2dec49b..2c129c8 100644 (file)
@@ -264,6 +264,11 @@ struct DALI_SCENE3D_API MeshDefinition
   bool IsSkinned() const;
 
   /**
+   * @brief Determines if the mesh has any vertex colors
+   */
+  bool HasVertexColor() const;
+
+  /**
    * @brief Returns the number of joint sets defined by the mesh
    */
   uint32_t GetNumberOfJointSets() const;
index 61f1491..56e63af 100644 (file)
@@ -253,12 +253,18 @@ void ModelRenderable::ReflectResources(IResourceReflector& reflector)
   reflector.Reflect(ResourceType::Material, mMaterialIdx);
 }
 
+// How many shader managers are there?!
 void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinition::CreateParams& params, ModelNode& node) const
 {
   DALI_ASSERT_DEBUG(mMeshIdx != INVALID_INDEX);
+  ShaderOption::HashType shaderOptionHash{0u};
   if(mShaderIdx == INVALID_INDEX)
   {
-    Shader          shader          = params.mShaderManager->ProduceShader(params.mResources.mMaterials[mMaterialIdx].first, params.mResources.mMeshes[mMeshIdx].first);
+    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);
 
@@ -299,23 +305,24 @@ void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinit
 
   {
     mesh.first.mModelPrimitive = ModelPrimitive::New();
-    auto primitive             = mesh.first.mModelPrimitive;
-    GetImplementation(primitive).SetRenderer(renderer);
+    auto& primitive            = GetImplementation(mesh.first.mModelPrimitive);
+    primitive.SetRenderer(renderer);
 
     Index    envIndex       = resources.mMaterials[mMaterialIdx].first.mEnvironmentIdx;
     uint32_t specularMipmap = resources.mEnvironmentMaps[envIndex].second.mSpecularMipmapLevels;
-    GetImplementation(primitive).SetImageBasedLightTexture(resources.mEnvironmentMaps[envIndex].second.mDiffuse,
-                                                           resources.mEnvironmentMaps[envIndex].second.mSpecular,
-                                                           resources.mEnvironmentMaps[envIndex].first.mIblIntensity,
-                                                           specularMipmap);
+    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);
-    GetImplementation(primitive).SetBlendShapeOptions(hasPositions, hasNormals, hasTangents, mesh.first.mBlendShapeVersion);
-    GetImplementation(primitive).SetBlendShapeGeometry(mesh.second.blendShapeGeometry);
-    GetImplementation(primitive).SetSkinned(mesh.first.IsSkinned(), mesh.first.GetNumberOfJointSets());
+    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());
   }
 
   auto shader = renderer.GetShader();
@@ -383,11 +390,13 @@ void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinit
     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();
   }
 
-  node.AddModelPrimitive(mesh.first.mModelPrimitive);
+  Internal::GetImplementation(node).AddModelPrimitive(mesh.first.mModelPrimitive, shaderOptionHash);
 }
 
 void ArcRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinition::CreateParams& params, ModelNode& node) const
index 69a804d..6adb452 100644 (file)
@@ -184,11 +184,10 @@ ShaderManager::ShaderManager()
 
 ShaderManager::~ShaderManager() = default;
 
-Dali::Shader ShaderManager::ProduceShader(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
+ShaderOption ShaderManager::ProduceShaderOption(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
 {
   DALI_LOG_INFO(gLogFilter, Debug::Concise, "Defining shader from mat/mesh definitions\n");
-  ShaderOption option = MakeOption(materialDefinition, meshDefinition);
-  return ProduceShader(option);
+  return MakeOption(materialDefinition, meshDefinition);
 }
 
 Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
index 4ca1384..af28cd8 100644 (file)
 
 // INTERNAL INCLUDES
 #include <dali-scene3d/public-api/api.h>
+#include <dali-scene3d/public-api/light/light.h>
 #include <dali-scene3d/public-api/loader/index.h>
 #include <dali-scene3d/public-api/loader/material-definition.h>
 #include <dali-scene3d/public-api/loader/mesh-definition.h>
 #include <dali-scene3d/public-api/loader/renderer-state.h>
 #include <dali-scene3d/public-api/loader/shader-option.h>
-#include <dali-scene3d/public-api/light/light.h>
 
 namespace Dali::Scene3D::Loader
 {
@@ -55,9 +55,9 @@ public:
    * (Although the input materialDefinition and meshDefinition are not identical to those used to create the cached Dali::Shader, they share the cached one.)
    * @param[in] materialDefinition MaterialDefinition that includes information of material to create Shader.
    * @param[in] meshDefinition meshDefinition that includes information of mesh to create Shader.
-   * @return Dali::Shader for the materialDefinition and meshDefinition.
+   * @return ShaderOption for the materialDefinition and meshDefinition.
    */
-  Dali::Shader ProduceShader(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition);
+  ShaderOption ProduceShaderOption(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition);
 
   /**
    * @brief Produces a Dali::Shader for the input ShaderOption
@@ -147,6 +147,7 @@ private:
    * @param[in] shader Shader that the constraint will be applied.
    */
   DALI_INTERNAL void SetShadowConstraintToShader(Dali::Shader shader);
+
 private:
   struct Impl;
   const std::unique_ptr<Impl> mImpl;
index bca29f7..378d85b 100644 (file)
@@ -33,25 +33,25 @@ class DALI_SCENE3D_API ShaderOption
 public:
   enum class Type
   {
-    GLTF_CHANNELS = 0,
-    THREE_TEXTURE,
-    BASE_COLOR_TEXTURE,
-    METALLIC_ROUGHNESS_TEXTURE,
-    NORMAL_TEXTURE,
-    OCCLUSION,
-    EMISSIVE,
-    ALPHA_TEST,
-    SUBSURFACE,
-    SPECULAR,
-    SPECULAR_COLOR,
-    SKINNING,
-    FLIP_UVS_VERTICAL,
-    COLOR_ATTRIBUTE,
-    VEC4_TANGENT,
-    MORPH_POSITION,
-    MORPH_NORMAL,
-    MORPH_TANGENT,
-    MORPH_VERSION_2_0
+    GLTF_CHANNELS = 0,          // 00001
+    THREE_TEXTURE,              // 00002
+    BASE_COLOR_TEXTURE,         // 00004
+    METALLIC_ROUGHNESS_TEXTURE, // 00008
+    NORMAL_TEXTURE,             // 00010
+    OCCLUSION,                  // 00020
+    EMISSIVE,                   // 00040
+    ALPHA_TEST,                 // 00080
+    SUBSURFACE,                 // 00100
+    SPECULAR,                   // 00200
+    SPECULAR_COLOR,             // 00400
+    SKINNING,                   // 00800
+    FLIP_UVS_VERTICAL,          // 01000
+    COLOR_ATTRIBUTE,            // 02000
+    VEC4_TANGENT,               // 04000
+    MORPH_POSITION,             // 08000
+    MORPH_NORMAL,               // 10000
+    MORPH_TANGENT,              // 20000
+    MORPH_VERSION_2_0           // 40000
   };
 
   struct MacroDefinition
@@ -64,6 +64,8 @@ public:
   ShaderOption(const ShaderOption& rhs);
   ShaderOption& operator=(const ShaderOption& rhs);
 
+  using HashType = uint64_t;
+
 public:
   /**
    * @brief Sets transparency option.
@@ -93,7 +95,7 @@ public:
    *
    * @return Hash value of currently added options.
    */
-  uint64_t GetOptionHash() const;
+  HashType GetOptionHash() const;
 
   /**
    * @brief Retrieves a list of define keywords.
@@ -116,7 +118,7 @@ public:
   const std::vector<MacroDefinition>& GetMacroDefinitions() const;
 
 private:
-  uint64_t mOptionHash{0u};
+  HashType mOptionHash{0u};
 
   std::vector<MacroDefinition> mMacros;
 };
index a664eeb..f4bd758 100644 (file)
@@ -95,7 +95,7 @@ uint32_t ModelNode::GetModelPrimitiveCount() const
 
 void ModelNode::AddModelPrimitive(ModelPrimitive modelPrimitive)
 {
-  Internal::GetImplementation(*this).AddModelPrimitive(modelPrimitive);
+  Internal::GetImplementation(*this).AddModelPrimitive(modelPrimitive, 0u);
 }
 
 void ModelNode::RemoveModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)