Fix bug that IBLFactor / Roughness not works well when we change material 44/303844/5
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 14:36:48 +0000 (23:36 +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 0962643..e8a372c 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.
@@ -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>
 
@@ -33,6 +34,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;
@@ -72,7 +75,7 @@ const char* TEST_DLI_EXERCISE_FILE_NAME            = TEST_RESOURCE_DIR "/exercis
  * These textures are based off version of Wave engine sample
  * Take from https://github.com/WaveEngine/Samples
  *
- * Copyright (c) 2023 Wave Coorporation
+ * Copyright (c) 2024 Wave Coorporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -121,6 +124,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
@@ -1817,3 +1853,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  = 0.0f;                                  ///< Note : This value will be true when gltf have BaseColorTexture, and use KHR_texture_transform extension.
+  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 3b35ffd..baebb4a 100644 (file)
@@ -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 IBL_BASIS(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()
@@ -694,32 +713,32 @@ void Material::SetRendererUniform(Dali::Renderer renderer)
   renderer.RegisterProperty("uSpecularFactor", mTextureInformations[TextureIndex::SPECULAR].mFactor.x);
   renderer.RegisterProperty("uSpecularColorFactor", Vector3(mTextureInformations[TextureIndex::SPECULAR_COLOR].mFactor));
 
-  // No requirement to use texture transform for runtime generated models.
-  renderer.RegisterProperty("uBaseColorTextureTransformAvailable", 0.0f);
-  renderer.RegisterProperty("uNormalTextureTransformAvailable", 0.0f);
-  renderer.RegisterProperty("uNormalRoughnessTextureTransformAvailable", 0.0f);
-  renderer.RegisterProperty("uMetalRoughnessTextureTransformAvailable", 0.0f);
-  renderer.RegisterProperty("uOcclusionTextureTransformAvailable", 0.0f);
-  renderer.RegisterProperty("uEmissiveTextureTransformAvailable", 0.0f);
-
-  renderer.RegisterProperty("uBaseColorTextureTransform", Matrix3::IDENTITY);
-  renderer.RegisterProperty("uNormalRoughnessTextureTransform", Matrix3::IDENTITY);
-  renderer.RegisterProperty("uNormalTextureTransform", Matrix3::IDENTITY);
-  renderer.RegisterProperty("uMetalRoughnessTextureTransform", Matrix3::IDENTITY);
-  renderer.RegisterProperty("uOcclusionTextureTransform", Matrix3::IDENTITY);
-  renderer.RegisterProperty("uEmissiveTextureTransform", Matrix3::IDENTITY);
-
   float opaque = mIsOpaque ? 1.0f : 0.0f;
   float mask   = mIsMask ? 1.0f : 0.0f;
   renderer.RegisterProperty("uOpaque", opaque);
   renderer.RegisterProperty("uMask", mask);
   renderer.RegisterProperty("uAlphaThreshold", mAlphaCutoff);
 
-  renderer.RegisterProperty("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));
+  // Setup default uniform values what we might need.
+  RegisterUniformIfNotDefinedBefore(renderer, "uBaseColorTextureTransformAvailable", 0.0f);
+  RegisterUniformIfNotDefinedBefore(renderer, "uNormalTextureTransformAvailable", 0.0f);
+  RegisterUniformIfNotDefinedBefore(renderer, "uNormalRoughnessTextureTransformAvailable", 0.0f);
+  RegisterUniformIfNotDefinedBefore(renderer, "uMetalRoughnessTextureTransformAvailable", 0.0f);
+  RegisterUniformIfNotDefinedBefore(renderer, "uOcclusionTextureTransformAvailable", 0.0f);
+  RegisterUniformIfNotDefinedBefore(renderer, "uEmissiveTextureTransformAvailable", 0.0f);
+
+  RegisterUniformIfNotDefinedBefore(renderer, "uBaseColorTextureTransform", Matrix3::IDENTITY);
+  RegisterUniformIfNotDefinedBefore(renderer, "uNormalRoughnessTextureTransform", Matrix3::IDENTITY);
+  RegisterUniformIfNotDefinedBefore(renderer, "uNormalTextureTransform", Matrix3::IDENTITY);
+  RegisterUniformIfNotDefinedBefore(renderer, "uMetalRoughnessTextureTransform", Matrix3::IDENTITY);
+  RegisterUniformIfNotDefinedBefore(renderer, "uOcclusionTextureTransform", Matrix3::IDENTITY);
+  RegisterUniformIfNotDefinedBefore(renderer, "uEmissiveTextureTransform", Matrix3::IDENTITY);
+
+  RegisterUniformIfNotDefinedBefore(renderer, "uCubeMatrix", Matrix::IDENTITY);
+
+  RegisterUniformIfNotDefinedBefore(renderer, Scene3D::Loader::NodeDefinition::GetIblMaxLodUniformName(), 1.0f);
+  RegisterUniformIfNotDefinedBefore(renderer, Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName(), 1.0f);
+  RegisterUniformIfNotDefinedBefore(renderer, Scene3D::Loader::NodeDefinition::GetIblYDirectionUniformName(), IBL_BASIS);
 
   Scene3D::Loader::RendererState::Apply(mRendererState, renderer);
 }
index 12bbf6e..1adf514 100644 (file)
@@ -549,9 +549,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);
   }
 }