diff options
author | Eunki, Hong <eunkiki.hong@samsung.com> | 2024-01-05 21:47:48 +0900 |
---|---|---|
committer | Eunki, Hong <eunkiki.hong@samsung.com> | 2024-01-26 17:49:55 +0900 |
commit | f8a8cf99541d33019ee0d66b2a8c3739e41926f0 (patch) | |
tree | bae61e1fc63e242b07f839f17f1490d3d782bc5f /examples | |
parent | 2558ba5d54bce7c572614cc233136771a8ddb942 (diff) | |
download | dali-demo-f8a8cf99541d33019ee0d66b2a8c3739e41926f0.tar.gz dali-demo-f8a8cf99541d33019ee0d66b2a8c3739e41926f0.tar.bz2 dali-demo-f8a8cf99541d33019ee0d66b2a8c3739e41926f0.zip |
SceneViewTest demo use SetResolution / ModelNode's Material
Make more dynamic and interactable SceneView demo.
- SetResolution test
- FramebufferMultiSamplingLevel test
- ScreenExtent result test
- Touch / Focus signal test
- Materal property change test
Change-Id: Ifc8f276b8b5ca6d0f44de538f39adb676fb1f7a7
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
Diffstat (limited to 'examples')
-rw-r--r-- | examples/scene-view-test/README.md | 14 | ||||
-rw-r--r-- | examples/scene-view-test/scene-view-test-example.cpp | 564 | ||||
-rwxr-xr-x | examples/scene-view-test/scene-view-test.png | bin | 0 -> 1018619 bytes |
3 files changed, 578 insertions, 0 deletions
diff --git a/examples/scene-view-test/README.md b/examples/scene-view-test/README.md new file mode 100644 index 00000000..53ddb8f6 --- /dev/null +++ b/examples/scene-view-test/README.md @@ -0,0 +1,14 @@ +# Scene View Test Example + +This is a various test example for SceneView and Model API in the DALi Scene3D library. + + - Use Framebuffer instead of direct rendering + - Framebuffer multi samping level (Works only Framebuffer used) + - Resolution of target (Works only Framebuffer used) + - Screen extents calculation and show the result + - Focus change by keyboard + touch + - Change material property + +Please update this note if you add some more test cases. + +![](./scene-view-test.png) diff --git a/examples/scene-view-test/scene-view-test-example.cpp b/examples/scene-view-test/scene-view-test-example.cpp new file mode 100644 index 00000000..fd1cf12e --- /dev/null +++ b/examples/scene-view-test/scene-view-test-example.cpp @@ -0,0 +1,564 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include <dali-scene3d/dali-scene3d.h> +#include <dali-toolkit/dali-toolkit.h> + +#include <dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.h> +#include <dali/devel-api/actors/actor-devel.h> + +// INTERNAL INCLUDES +#include <dali/devel-api/adaptor-framework/file-stream.h> + +using namespace Dali; +using namespace Toolkit; +using namespace Scene3D; + +namespace +{ +const char* CUBEMAP_SKY_BOX_URL = DEMO_IMAGE_DIR "veste_oberhaus_cubemap.png"; +const char* CUBEMAP_IRRADIANCE_URL = DEMO_IMAGE_DIR "veste_oberhaus_irradiance.png"; +const char* CAMERA_NAME("MyCamera"); + +const char* MODEL_URL = DEMO_MODEL_DIR "SphereMetallic.gltf"; +constexpr Vector3 MODEL_SIZE(300.0f, 300.0f, 300.0f); +const char* SUB_MODEL_URL = DEMO_MODEL_DIR "Duck.gltf"; +constexpr Vector3 SUB_MODEL_SIZE(300.0f, 300.0f, 300.0f); +constexpr Vector3 SUB_MODEL_SCALE(1.2f, 0.6f, 1.0f); + +constexpr Vector4 ORIGINAL_BASE_COLOR_FACTOR(0.6039215686274509f, 0.6039215686274509f, 0.6039215686274509f, 1.0f); +constexpr Vector3 ORIGINAL_EMISSIVE_FACTOR(0.0f, 0.0f, 0.0f); +constexpr float ORIGINAL_METALLIC_FACTOR(1.0f); +constexpr float ORIGINAL_ROUGHNESS_FACTOR(0.0f); + +constexpr Vector4 ORIGINAL_SUB_BASE_COLOR_FACTOR(1.0f, 1.0f, 1.0f, 1.0f); +constexpr Vector3 ORIGINAL_SUB_EMISSIVE_FACTOR(0.0f, 0.0f, 0.0f); +constexpr float ORIGINAL_SUB_METALLIC_FACTOR(0.0f); +constexpr float ORIGINAL_SUB_ROUGHNESS_FACTOR(1.0f); + +constexpr Vector4 FOCUSED_BASE_COLOR_FACTOR(1.0f, 1.0f, 1.0f, 1.0f); +constexpr Vector3 FOCUSED_EMISSIVE_FACTOR(0.1f, 0.0f, 0.0f); +constexpr float FOCUSED_METALLIC_FACTOR(0.2f); +constexpr float FOCUSED_ROUGHNESS_FACTOR(0.5f); + +constexpr uint8_t FRAMEBUFFER_MULTI_SAMPLING_LEVEL = 4u; + +constexpr uint32_t MAX_BACKLOG_COUNT = 10; + +constexpr float RESOLUTION_RATE_DOWNSCALED = 0.25f; +constexpr float RESOLUTION_RATE_UPSCALED = 1.5f; +constexpr float RESOLUTION_RATE_OVER_DOWNSCALED = 0.1f; +constexpr float RESOLUTION_RATE_OVER_UPSCALED = 2.5f; + +const Quaternion MODEL_ROTATION(Degree(360.f), Vector3(0.1f, 1.0f, -0.1f)); + +enum ResolutionType +{ + DEFAULT = 0, + DOWNSCALED, + UPSCALED, + + OVER_DOWNSCALED, + OVER_UPSCALED, + + MAX, +}; + +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 + +class SceneViewExample : public ConnectionTracker +{ +public: + SceneViewExample(Application& application) + : mApplication(application) + { + // Connect to the Application's Init signal + mApplication.InitSignal().Connect(this, &SceneViewExample::Create); + } + + ~SceneViewExample() = default; + +private: + // The Init signal is received once (only) during the Application lifetime + void Create(Application& application) + { + // Get a handle to the window + mWindow = application.GetWindow(); + const Vector2 windowSize = mWindow.GetSize(); + + // Create a SceneView and set the Skybox + mSceneView = Handle::New<SceneView>({{Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER}, + {Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER}, + {Actor::Property::SIZE, windowSize}}); + mSceneView.SetSkybox(CUBEMAP_SKY_BOX_URL); + mWindow.Add(mSceneView); + + // Load the model and set IBL + mMainModel = Model::New(MODEL_URL); + mMainModel.SetProperties({ + {Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER}, + {Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER}, + {Actor::Property::POSITION, Vector3::ZERO}, + {Actor::Property::SIZE, MODEL_SIZE}, + {Actor::Property::NAME, "MainModel"}, + {Actor::Property::KEYBOARD_FOCUSABLE, true}, + {DevelActor::Property::TOUCH_FOCUSABLE, true}, + }); + mMainModel.SetImageBasedLightSource(CUBEMAP_IRRADIANCE_URL, CUBEMAP_SKY_BOX_URL); + mSceneView.Add(mMainModel); + + mSubModel = Model::New(SUB_MODEL_URL); + mSubModel.SetProperties({ + {Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER}, + {Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER}, + {Actor::Property::POSITION, Vector3(MODEL_SIZE.x, MODEL_SIZE.y * 0.5f, 0.0f)}, + {Actor::Property::SIZE, SUB_MODEL_SIZE}, + {Actor::Property::SCALE, SUB_MODEL_SCALE}, + {Actor::Property::NAME, "SubModel"}, + {Actor::Property::KEYBOARD_FOCUSABLE, true}, + {DevelActor::Property::TOUCH_FOCUSABLE, true}, + }); + mSubModel.SetImageBasedLightSource(CUBEMAP_IRRADIANCE_URL, CUBEMAP_SKY_BOX_URL, 0.25f); + mSceneView.Add(mSubModel); + + // Create a new camera and reparent as we want to rotate the camera around the origin + CameraActor cameraActor = Handle::New<CameraActor>({{Actor::Property::NAME, CAMERA_NAME}}); + mSceneView.AddCamera(cameraActor); + mSceneView.SelectCamera(CAMERA_NAME); + cameraActor.SetType(Camera::LOOK_AT_TARGET); + cameraActor.SetTargetPosition(Vector3::ZERO); + cameraActor.Unparent(); + Actor rotatingActor = Handle::New<Actor>({{Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER}, + {Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER}}); + rotatingActor.Add(cameraActor); + mSceneView.Add(rotatingActor); + + mCameraRotateAnimation = Animation::New(10.0f); + mCameraRotateAnimation.SetLooping(true); + mCameraRotateAnimation.AnimateBy(Property(rotatingActor, Actor::Property::ORIENTATION), MODEL_ROTATION); + if(mRotateCamera) + { + mCameraRotateAnimation.Play(); + } + + // Respond to key events + mWindow.KeyEventSignal().Connect(this, &SceneViewExample::OnKeyEvent); + mWindow.ResizeSignal().Connect(this, &SceneViewExample::OnWindowResize); + + DevelKeyboardFocusManager::EnableDefaultAlgorithm(KeyboardFocusManager::Get(), true); + + mMainModel.KeyInputFocusGainedSignal().Connect(this, &SceneViewExample::OnFocusGained); + mMainModel.KeyInputFocusLostSignal().Connect(this, &SceneViewExample::OnFocusLost); + mSubModel.KeyInputFocusGainedSignal().Connect(this, &SceneViewExample::OnFocusGained); + mSubModel.KeyInputFocusLostSignal().Connect(this, &SceneViewExample::OnFocusLost); + KeyboardFocusManager::Get().FocusChangedSignal().Connect(this, &SceneViewExample::OnFocusChanged); + + mScreenExtentTimer = Timer::New(16); + mScreenExtentTimer.TickSignal().Connect(this, &SceneViewExample::OnTick); + if(mShowScreenExtent) + { + mScreenExtentTimer.Start(); + } + + ApplyDebugLog(); + } + + /** + * @brief Called when any key event is received + * + * Will use this to quit the application if Back or the Escape key is received + * @param[in] event The key event information + */ + void OnKeyEvent(const KeyEvent& event) + { + if(event.GetState() == KeyEvent::DOWN) + { + if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK)) + { + if(KeyboardFocusManager::Get().GetCurrentFocusActor()) + { + KeyboardFocusManager::Get().ClearFocus(); + } + else + { + mApplication.Quit(); + } + } + + if(event.GetKeyName() == "1") + { + mShowDebugLabel ^= 1; + } + else if(event.GetKeyName() == "2") + { + mUseFrameBuffer ^= 1; + if(mSceneView) + { + mSceneView.UseFramebuffer(mUseFrameBuffer); + } + } + else if(event.GetKeyName() == "3") + { + mUseFrameBufferMultiSample ^= 1; + if(mSceneView) + { + mSceneView.SetFramebufferMultiSamplingLevel(mUseFrameBufferMultiSample ? FRAMEBUFFER_MULTI_SAMPLING_LEVEL : 0); + } + } + else if(event.GetKeyName() == "4") + { + mResolutionType = static_cast<ResolutionType>(static_cast<int>(mResolutionType + 1) % ResolutionType::MAX); + ApplyResolution(); + } + else if(event.GetKeyName() == "5") + { + mRotateCamera ^= true; + if(mCameraRotateAnimation) + { + if(!mRotateCamera && mCameraRotateAnimation.GetState() == Animation::PLAYING) + { + mCameraRotateAnimation.Stop(); + } + else if(mRotateCamera && mCameraRotateAnimation.GetState() != Animation::PLAYING) + { + mCameraRotateAnimation.Play(); + } + } + } + else if(event.GetKeyName() == "6") + { + mShowScreenExtent ^= true; + if(mScreenExtentTimer) + { + if(!mShowScreenExtent && mScreenExtentTimer.IsRunning()) + { + mScreenExtentTimer.Stop(); + } + else if(mShowScreenExtent && !mScreenExtentTimer.IsRunning()) + { + mScreenExtentTimer.Start(); + } + } + if(mMainModelAABB) + { + mMainModelAABB[Actor::Property::VISIBLE] = mShowScreenExtent; + } + if(mSubModelAABB) + { + mSubModelAABB[Actor::Property::VISIBLE] = mShowScreenExtent; + } + } + ApplyDebugLog(); + } + } + + void OnWindowResize(Window window, Window::WindowSize newSize) + { + if(mSceneView) + { + mSceneView[Actor::Property::SIZE_WIDTH] = newSize.GetWidth(); + mSceneView[Actor::Property::SIZE_HEIGHT] = newSize.GetHeight(); + ApplyResolution(); + } + } + + void OnFocusChanged(Actor from, Actor to) + { + if(!from && !to) + { + return; + } + std::ostringstream oss; + oss << "Focus changed from : ["; + oss << (from ? from.GetProperty<std::string>(Actor::Property::NAME) : "(nil)"); + oss << "] -> ["; + oss << (to ? to.GetProperty<std::string>(Actor::Property::NAME) : "(nil)"); + oss << "]"; + ApplyBackLog(oss.str()); + } + + void OnFocusGained(Control control) + { + std::ostringstream oss; + oss << "Focus gained : ["; + oss << (control ? control.GetProperty<std::string>(Actor::Property::NAME) : "(nil)"); + oss << "]"; + ApplyBackLog(oss.str()); + + Model model = Model::DownCast(control); + if(model) + { + ApplyAllMaterialPropertyRecursively( + model.GetModelRoot(), + { + {Material::Property::BASE_COLOR_FACTOR, FOCUSED_BASE_COLOR_FACTOR}, + {Material::Property::EMISSIVE_FACTOR, FOCUSED_EMISSIVE_FACTOR}, + {Material::Property::METALLIC_FACTOR, FOCUSED_METALLIC_FACTOR}, + {Material::Property::ROUGHNESS_FACTOR, FOCUSED_ROUGHNESS_FACTOR}, + }); + } + } + + void OnFocusLost(Control control) + { + std::ostringstream oss; + oss << "Focus lost : ["; + oss << (control ? control.GetProperty<std::string>(Actor::Property::NAME) : "(nil)"); + oss << "]"; + ApplyBackLog(oss.str()); + + Model model = Model::DownCast(control); + if(model) + { + bool isSubModel = model.GetProperty<std::string>(Actor::Property::NAME) == "SubModel"; + ApplyAllMaterialPropertyRecursively( + model.GetModelRoot(), + { + {Material::Property::BASE_COLOR_FACTOR, isSubModel ? ORIGINAL_SUB_BASE_COLOR_FACTOR : ORIGINAL_BASE_COLOR_FACTOR}, + {Material::Property::EMISSIVE_FACTOR, isSubModel ? ORIGINAL_SUB_EMISSIVE_FACTOR : ORIGINAL_EMISSIVE_FACTOR}, + {Material::Property::METALLIC_FACTOR, isSubModel ? ORIGINAL_SUB_METALLIC_FACTOR : ORIGINAL_METALLIC_FACTOR}, + {Material::Property::ROUGHNESS_FACTOR, isSubModel ? ORIGINAL_SUB_ROUGHNESS_FACTOR : ORIGINAL_ROUGHNESS_FACTOR}, + }); + } + } + + bool OnTick() + { + if(mShowScreenExtent) + { + RecalculateScreenExtent(); + } + return true; + } + +private: + void ApplyResolution() + { + if(mWindow && mSceneView) + { + Window::WindowSize windowSize = mWindow.GetSize(); + switch(mResolutionType) + { + case ResolutionType::DEFAULT: + default: + { + mResolutionRate = 0.0f; + break; + } + case ResolutionType::DOWNSCALED: + { + mResolutionRate = RESOLUTION_RATE_DOWNSCALED; + break; + } + case ResolutionType::UPSCALED: + { + mResolutionRate = RESOLUTION_RATE_UPSCALED; + break; + } + case ResolutionType::OVER_DOWNSCALED: + { + mResolutionRate = RESOLUTION_RATE_OVER_DOWNSCALED; + break; + } + case ResolutionType::OVER_UPSCALED: + { + mResolutionRate = RESOLUTION_RATE_OVER_UPSCALED; + break; + } + } + + if(Dali::EqualsZero(mResolutionRate)) + { + mSceneView.ResetResolution(); + } + else + { + mSceneView.SetResolution(static_cast<uint32_t>(windowSize.GetWidth() * mResolutionRate), static_cast<uint32_t>(windowSize.GetHeight() * mResolutionRate)); + } + } + } + + void ApplyDebugLog() + { + if(!mDebugLabel) + { + mDebugLabel = TextLabel::New(); + mDebugLabel[Actor::Property::PARENT_ORIGIN] = ParentOrigin::TOP_LEFT; + mDebugLabel[Actor::Property::ANCHOR_POINT] = AnchorPoint::TOP_LEFT; + mDebugLabel[TextLabel::Property::MULTI_LINE] = true; + mDebugLabel[Control::Property::BACKGROUND] = Vector4(1.0f, 1.0f, 1.0f, 0.2f); + } + + if(mShowDebugLabel) + { + if(mWindow && mDebugLabel && !mDebugLabel.GetParent()) + { + mWindow.GetOverlayLayer().Add(mDebugLabel); + } + std::ostringstream oss; + oss << "Key 1 : Toggle to show debug log\n"; + oss << "Key 2 : Toggle to use Framebuffer. Currently " << (mUseFrameBuffer ? "ON" : "OFF") << "\n"; + oss << "Key 3 : Toggle to use FramebufferMultiSampling. Currently " << (mUseFrameBufferMultiSample ? FRAMEBUFFER_MULTI_SAMPLING_LEVEL : 0) << "\n"; + oss << "Key 4 : Toggle to use SetResolution. Currently "; + oss << (mResolutionType == ResolutionType::DEFAULT ? "DEFAULT" : mResolutionType == ResolutionType::DOWNSCALED ? "DOWNSCALED" + : mResolutionType == ResolutionType::UPSCALED ? "UPSCALED" + : mResolutionType == ResolutionType::OVER_DOWNSCALED ? "OVER_DOWNSCALED" + : mResolutionType == ResolutionType::OVER_UPSCALED ? "OVER_UPSCALED" + : "ERROR") + << " (Scale rate : " << mResolutionRate << ")\n"; + oss << "Key 5 : Toggle to Rotate camera. Currently " << (mRotateCamera ? "ON" : "OFF") << "\n"; + oss << "Key 6 : Toggle to show Model ScreenExtent. Currently " << (mShowScreenExtent ? "ON" : "OFF") << "\n"; + + for(const auto& log : mBackLog) + { + oss << log; + if(log.length() == 0 || log.back() != '\n') + { + oss << "\n"; + } + } + + mDebugLabel[TextLabel::Property::TEXT] = oss.str(); + } + else + { + if(mDebugLabel) + { + mDebugLabel.Unparent(); + } + } + } + + void ApplyBackLog(std::string message) + { + if(mBackLog.size() == MAX_BACKLOG_COUNT) + { + mBackLog.clear(); + } + mBackLog.push_back(message); + + ApplyDebugLog(); + } + + void ApplyModelScreenExtent(Control aabb, Model model) + { + Rect<float> screenExtent = Dali::DevelActor::CalculateCurrentScreenExtents(model); + + aabb[Actor::Property::POSITION_X] = screenExtent.x; + aabb[Actor::Property::POSITION_Y] = screenExtent.y; + aabb[Actor::Property::SIZE_WIDTH] = screenExtent.width; + aabb[Actor::Property::SIZE_HEIGHT] = screenExtent.height; + } + +private: + void RecalculateScreenExtent() + { + if(mWindow && !mMainModelAABB) + { + mMainModelAABB = Control::New(); + mMainModelAABB.SetProperties({ + {Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT}, + {Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT}, + {Control::Property::BACKGROUND, Vector4(0.0f, 0.0f, 1.0f, 0.2f)}, + }); + mWindow.GetOverlayLayer().Add(mMainModelAABB); + } + if(mWindow && !mSubModelAABB) + { + mSubModelAABB = Control::New(); + mSubModelAABB.SetProperties({ + {Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT}, + {Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT}, + {Control::Property::BACKGROUND, Vector4(1.0f, 0.0f, 0.0f, 0.2f)}, + }); + mWindow.GetOverlayLayer().Add(mSubModelAABB); + } + + ApplyModelScreenExtent(mMainModelAABB, mMainModel); + ApplyModelScreenExtent(mSubModelAABB, mSubModel); + } + +private: + Application& mApplication; + Window mWindow; + SceneView mSceneView; + + Model mMainModel; + Model mSubModel; + + Animation mCameraRotateAnimation; + + // State of demo + TextLabel mDebugLabel; + bool mShowDebugLabel{true}; + + std::vector<std::string> mBackLog; + + Timer mScreenExtentTimer; + Control mMainModelAABB; + Control mSubModelAABB; + + bool mUseFrameBuffer{false}; + bool mUseFrameBufferMultiSample{false}; + bool mRotateCamera{true}; + bool mShowScreenExtent{false}; + + ResolutionType mResolutionType{ResolutionType::DEFAULT}; + float mResolutionRate{0.0f}; +}; + +int DALI_EXPORT_API main(int argc, char** argv) +{ + Application application = Application::New(&argc, &argv); + SceneViewExample test(application); + application.MainLoop(); + return 0; +} diff --git a/examples/scene-view-test/scene-view-test.png b/examples/scene-view-test/scene-view-test.png Binary files differnew file mode 100755 index 00000000..5312ab85 --- /dev/null +++ b/examples/scene-view-test/scene-view-test.png |