[Tizen] Fix bug that IBLFactor / Roughness not works well when we change material 07/304107/1 accepted/tizen/7.0/unified/20240111.013537
authorEunki Hong <eunkiki.hong@samsung.com>
Fri, 5 Jan 2024 16:01:50 +0000 (01:01 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Wed, 10 Jan 2024 06:09:50 +0000 (15:09 +0900)
There was some bug when we change Material info, uMaxLOD and uIblIntensity does not applied what primitive has.

This is because Material's SetUniform API overwrite the value of those uniform.

This patch make we ensure the order of uniform register, so let we use correct LOD and IBL intensity.

Change-Id: Ic14b7f9b6c0e443ac17188a8968ac71a7c6328d6
Signed-off-by: Eunki Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-scene3d/utc-Dali-Model.cpp
dali-scene3d/internal/model-components/material-impl.cpp
dali-scene3d/internal/model-components/model-primitive-impl.cpp

index 1b898a0..959f746 100644 (file)
@@ -18,6 +18,7 @@
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali/devel-api/common/map-wrapper.h>
+#include <dali/public-api/common/vector-wrapper.h>
 #include <stdlib.h>
 #include <iostream>
 
@@ -32,6 +33,8 @@
 #include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
 #include <dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h>
 
+#include <dali-scene3d/public-api/loader/node-definition.h>
+
 #include <dali/devel-api/actors/camera-actor-devel.h>
 
 using namespace Dali;
@@ -118,6 +121,39 @@ void        OnResourceReady(Control control)
   gResourceReadyCalled = true;
 }
 
+void ApplyAllMaterialPropertyRecursively(Scene3D::ModelNode modelNode, const std::vector<KeyValuePair>& materialPropertyValues)
+{
+  if(!modelNode)
+  {
+    return;
+  }
+
+  for(uint32_t primitiveIndex = 0u; primitiveIndex < modelNode.GetModelPrimitiveCount(); ++primitiveIndex)
+  {
+    Scene3D::ModelPrimitive primitive = modelNode.GetModelPrimitive(primitiveIndex);
+    if(primitive)
+    {
+      Scene3D::Material material = primitive.GetMaterial();
+      if(material)
+      {
+        for(const auto& keyValuePair : materialPropertyValues)
+        {
+          if(keyValuePair.first.type == Property::Key::Type::INDEX)
+          {
+            material.SetProperty(keyValuePair.first.indexKey, keyValuePair.second);
+          }
+        }
+      }
+    }
+  }
+
+  for(uint32_t childIndex = 0u; childIndex < modelNode.GetChildCount(); ++childIndex)
+  {
+    Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(modelNode.GetChildAt(childIndex));
+    ApplyAllMaterialPropertyRecursively(childNode, materialPropertyValues);
+  }
+}
+
 } // namespace
 
 // Negative test case for a method
@@ -1687,3 +1723,73 @@ int UtcDaliModelBlendShapeMotionDataByName(void)
 
   END_TEST;
 }
+
+int UtcDaliModelMaterialUniformChange(void)
+{
+  ToolkitTestApplication application;
+
+  static std::vector<UniformData> customUniforms =
+    {
+      UniformData("uColorFactor", Property::Type::VECTOR4),
+      UniformData("uBaseColorTextureTransformAvailable", Property::Type::FLOAT),
+      UniformData(Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName().data(), Property::Type::FLOAT),
+      UniformData(Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), Property::Type::FLOAT),
+    };
+
+  TestGraphicsController& graphics = application.GetGraphicsController();
+  graphics.AddCustomUniforms(customUniforms);
+
+  auto& gl = application.GetGlAbstraction();
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
+
+  gResourceReadyCalled = false;
+  model.ResourceReadySignal().Connect(&OnResourceReady);
+
+  float expectIblFactor = 0.5f;
+  model.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE, expectIblFactor);
+  DALI_TEST_EQUALS(model.GetImageBasedLightScaleFactor(), expectIblFactor, TEST_LOCATION);
+
+  DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION);
+  application.GetScene().Add(model);
+
+  application.SendNotification();
+  application.Render();
+
+  // Wait 3 task. (Load 1 model + Load 2 IBL)
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(3), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION);
+  DALI_TEST_EQUALS(model.GetImageBasedLightScaleFactor(), expectIblFactor, TEST_LOCATION);
+
+  // Check uniform values before change material value
+  Vector4 expectBaseColorFactor = Vector4(1.000f, 0.766f, 0.336f, 1.0f); // Defined at AnimatedCube.gltf
+  float   expectTransformValid  = 1.0f; ///< Note : This value will be true when gltf have BaseColorTexture.
+  float   expectMaxLOD          = 5.0f; ///< Note : The number of LOD what TEST_SPECULAR_TEXTURE file has is 5.
+
+  tet_printf("Check uniform value result\n");
+  DALI_TEST_EQUALS(gl.CheckUniformValue<Vector4>("uColorFactor", expectBaseColorFactor), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gl.CheckUniformValue<float>("uBaseColorTextureTransformAvailable", expectTransformValid), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gl.CheckUniformValue<float>(Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName().data(), expectMaxLOD), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gl.CheckUniformValue<float>(Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), expectIblFactor), true, TEST_LOCATION);
+
+  // Change all materials in Model.
+  expectBaseColorFactor = Color::BLUE;
+
+  Scene3D::ModelNode rootModelNode = model.GetModelRoot();
+  DALI_TEST_CHECK(rootModelNode);
+  ApplyAllMaterialPropertyRecursively(rootModelNode, {{Dali::Scene3D::Material::Property::BASE_COLOR_FACTOR, expectBaseColorFactor}});
+
+  application.SendNotification();
+  application.Render();
+
+  tet_printf("Check whether uniform values are not changed instead what we change now\n");
+  DALI_TEST_EQUALS(gl.CheckUniformValue<Vector4>("uColorFactor", expectBaseColorFactor), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gl.CheckUniformValue<float>("uBaseColorTextureTransformAvailable", expectTransformValid), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gl.CheckUniformValue<float>(Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName().data(), expectMaxLOD), true, TEST_LOCATION);
+  DALI_TEST_EQUALS(gl.CheckUniformValue<float>(Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), expectIblFactor), true, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
index 7496e4e..084e080 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -61,6 +61,8 @@ static constexpr uint32_t         ALPHA_CUTOFF_FLAG                = Scene3D::Lo
 static constexpr std::string_view THREE_TEX_KEYWORD                = "THREE_TEX";
 static constexpr std::string_view GLTF_CHANNELS_KEYWORD            = "GLTF_CHANNELS";
 
+static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f);
+
 enum TextureIndex
 {
   BASE_COLOR,
@@ -73,6 +75,23 @@ enum TextureIndex
   TEXTURE_TYPE_NUMBER,
 };
 
+/**
+ * @brief Helper API to register uniform property only if don't register before.
+ *
+ * @tparam T Type of uniform value.
+ * @param[in] renderer The renderer what we want to check / register property.
+ * @param[in] uniformName The name of uniform.
+ * @param[in] defaultUniformValue The default value if renderer don't register given uniform before.
+ */
+template<typename T>
+void RegisterUniformIfNotDefinedBefore(Renderer renderer, const std::string_view& uniformName, const T& defaultUniformValue)
+{
+  if(renderer.GetPropertyIndex(uniformName.data()) == Property::INVALID_INDEX)
+  {
+    renderer.RegisterProperty(uniformName, defaultUniformValue);
+  }
+}
+
 } // unnamed namespace
 
 MaterialPtr Material::New()
@@ -700,11 +719,12 @@ void Material::SetRendererUniform(Dali::Renderer renderer)
   renderer.RegisterProperty("uMask", mask);
   renderer.RegisterProperty("uAlphaThreshold", mAlphaCutoff);
 
-  renderer.RegisterProperty("uCubeMatrix", Matrix::IDENTITY);
+  // Setup default uniform values what we might need.
+  RegisterUniformIfNotDefinedBefore(renderer, "uCubeMatrix", Matrix::IDENTITY);
 
-  renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName().data(), 6.f);
-  renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), 1.0f);
-  renderer.RegisterProperty(Scene3D::Loader::NodeDefinition::GetIblYDirectionUniformName().data(), Vector3(1.0f, -1.0, 1.0));
+  RegisterUniformIfNotDefinedBefore(renderer, Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName(), 1.0f);
+  RegisterUniformIfNotDefinedBefore(renderer, Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName(), 1.0f);
+  RegisterUniformIfNotDefinedBefore(renderer, Scene3D::Loader::NodeDefinition::GetIblYDirectionUniformName(), Y_DIRECTION);
 
   Scene3D::Loader::RendererState::Apply(mRendererState, renderer);
 }
index f86b951..ba78874 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -464,9 +464,9 @@ void ModelPrimitive::UpdateRendererUniform()
 {
   if(mMaterial)
   {
+    GetImplementation(mMaterial).SetRendererUniform(mRenderer);
     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
     mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
-    GetImplementation(mMaterial).SetRendererUniform(mRenderer);
   }
 }