From 80a2331cdb57f5398fdfddd12985420287e7844f Mon Sep 17 00:00:00 2001 From: seungho Date: Sat, 22 Oct 2022 01:24:00 +0900 Subject: [PATCH] Add Skybox in SceneView Change-Id: I37483af74efe3f0514d00cd1c7bc103066d455ee Signed-off-by: seungho --- .../src/dali-scene3d/utc-Dali-SceneView.cpp | 64 +++++++++ .../controls/scene-view/scene-view-impl.cpp | 157 ++++++++++++++++++++- .../internal/controls/scene-view/scene-view-impl.h | 29 ++++ .../internal/graphics/shaders/skybox-shader.frag | 9 ++ .../internal/graphics/shaders/skybox-shader.vert | 21 +++ .../public-api/controls/scene-view/scene-view.cpp | 25 ++++ .../public-api/controls/scene-view/scene-view.h | 45 ++++++ 7 files changed, 347 insertions(+), 3 deletions(-) create mode 100644 dali-scene3d/internal/graphics/shaders/skybox-shader.frag create mode 100644 dali-scene3d/internal/graphics/shaders/skybox-shader.vert diff --git a/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp b/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp index 6996ec6..a98e430 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp @@ -586,3 +586,67 @@ int UtcDaliSceneViewResourceReady(void) END_TEST; } + +int UtcDaliSceneViewSetSkybox(void) +{ + ToolkitTestApplication application; + + gResourceReadyCalled = false; + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + view.ResourceReadySignal().Connect(OnResourceReady); + // SceneView::IsResourceReady() returns true by default. + DALI_TEST_EQUALS(view.IsResourceReady(), true, TEST_LOCATION); + + // Sanity check + DALI_TEST_CHECK(!gResourceReadyCalled); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(view.IsResourceReady(), true, TEST_LOCATION); + DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION); + + gResourceReadyCalled = false; + + view.SetSkybox(TEST_SPECULAR_TEXTURE); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliSceneViewSetSkyboxIntensity(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + + float intensity = 0.5f; + DALI_TEST_EQUALS(view.GetSkyboxIntensity(), 1.0f, TEST_LOCATION); + + view.SetSkyboxIntensity(intensity); + DALI_TEST_EQUALS(view.GetSkyboxIntensity(), intensity, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliSceneViewSetSkyboxOrientation(void) +{ + ToolkitTestApplication application; + + Scene3D::SceneView view = Scene3D::SceneView::New(); + view.SetProperty(Actor::Property::SIZE, Vector2(100.0f, 100.0f)); + + Dali::Quaternion orientation = Dali::Quaternion(Radian(0.5f), Vector3::YAXIS); + view.SetSkyboxOrientation(orientation); + DALI_TEST_EQUALS(view.GetSkyboxOrientation(), orientation, TEST_LOCATION); + + END_TEST; +} diff --git a/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp index 593daf0..d19010f 100644 --- a/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp +++ b/dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp @@ -31,9 +31,11 @@ #include #include #include +#include // INTERNAL INCLUDES #include +#include #include #include @@ -60,11 +62,100 @@ DALI_TYPE_REGISTRATION_END() Property::Index RENDERING_BUFFER = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1; constexpr int32_t DEFAULT_ORIENTATION = 0; +static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity"; + +Dali::Actor CreateSkybox(const std::string& skyboxUrl) +{ + struct Vertex + { + Vector3 aPosition; + }; + + Vertex skyboxVertices[] = { + // back + {Vector3(-1.0f, 1.0f, -1.0f)}, + {Vector3(-1.0f, -1.0f, -1.0f)}, + {Vector3(1.0f, -1.0f, -1.0f)}, + {Vector3(1.0f, -1.0f, -1.0f)}, + {Vector3(1.0f, 1.0f, -1.0f)}, + {Vector3(-1.0f, 1.0f, -1.0f)}, + + // left + {Vector3(-1.0f, -1.0f, 1.0f)}, + {Vector3(-1.0f, -1.0f, -1.0f)}, + {Vector3(-1.0f, 1.0f, -1.0f)}, + {Vector3(-1.0f, 1.0f, -1.0f)}, + {Vector3(-1.0f, 1.0f, 1.0f)}, + {Vector3(-1.0f, -1.0f, 1.0f)}, + + // right + {Vector3(1.0f, -1.0f, -1.0f)}, + {Vector3(1.0f, -1.0f, 1.0f)}, + {Vector3(1.0f, 1.0f, 1.0f)}, + {Vector3(1.0f, 1.0f, 1.0f)}, + {Vector3(1.0f, 1.0f, -1.0f)}, + {Vector3(1.0f, -1.0f, -1.0f)}, + + // front + {Vector3(-1.0f, -1.0f, 1.0f)}, + {Vector3(-1.0f, 1.0f, 1.0f)}, + {Vector3(1.0f, 1.0f, 1.0f)}, + {Vector3(1.0f, 1.0f, 1.0f)}, + {Vector3(1.0f, -1.0f, 1.0f)}, + {Vector3(-1.0f, -1.0f, 1.0f)}, + + // botton + {Vector3(-1.0f, 1.0f, -1.0f)}, + {Vector3(1.0f, 1.0f, -1.0f)}, + {Vector3(1.0f, 1.0f, 1.0f)}, + {Vector3(1.0f, 1.0f, 1.0f)}, + {Vector3(-1.0f, 1.0f, 1.0f)}, + {Vector3(-1.0f, 1.0f, -1.0f)}, + + // top + {Vector3(-1.0f, -1.0f, -1.0f)}, + {Vector3(-1.0f, -1.0f, 1.0f)}, + {Vector3(1.0f, -1.0f, -1.0f)}, + {Vector3(1.0f, -1.0f, -1.0f)}, + {Vector3(-1.0f, -1.0f, 1.0f)}, + {Vector3(1.0f, -1.0f, 1.0f)}}; + + Dali::Shader shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data()); + Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3)); + vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex)); + + Dali::Geometry skyboxGeometry = Geometry::New(); + skyboxGeometry.AddVertexBuffer(vertexBuffer); + skyboxGeometry.SetType(Geometry::TRIANGLES); + + Dali::Texture skyboxTexture = Dali::Scene3D::Loader::LoadCubeMap(skyboxUrl); + Dali::TextureSet skyboxTextures = TextureSet::New(); + skyboxTextures.SetTexture(0, skyboxTexture); + + Dali::Renderer skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox); + skyboxRenderer.SetTextures(skyboxTextures); + skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f); + // Enables the depth test. + skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON); + // The fragment shader will run only is those pixels that have the max depth value. + skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL); + + Dali::Actor skyboxActor = Actor::New(); + skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox"); + skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER); + skyboxActor.AddRenderer(skyboxRenderer); + return skyboxActor; +} + } // anonymous namespace SceneView::SceneView() : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)), - mWindowOrientation(DEFAULT_ORIENTATION) + mWindowOrientation(DEFAULT_ORIENTATION), + mSkybox(), + mSkyboxOrientation(Quaternion()), + mSkyboxIntensity(1.0f) { } @@ -213,7 +304,10 @@ void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const st } } mIBLResourceReady = true; - Control::SetResourceReady(false); + if(IsResourceReady()) + { + Control::SetResourceReady(false); + } } void SceneView::SetImageBasedLightScaleFactor(float scaleFactor) @@ -247,6 +341,63 @@ bool SceneView::IsUsingFramebuffer() const return mUseFrameBuffer; } +void SceneView::SetSkybox(const std::string& skyboxUrl) +{ + mSkyboxResourceReady = false; + if(mSkybox) + { + mSkybox.Unparent(); + mSkybox.Reset(); + } + mSkybox = CreateSkybox(skyboxUrl); + SetSkyboxIntensity(mSkyboxIntensity); + SetSkyboxOrientation(mSkyboxOrientation); + if(mRootLayer) + { + mRootLayer.Add(mSkybox); + } + + mSkyboxResourceReady = true; + if(IsResourceReady()) + { + Control::SetResourceReady(false); + } +} + +void SceneView::SetSkyboxIntensity(float intensity) +{ + mSkyboxIntensity = intensity; + if(intensity < 0) + { + DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n"); + mSkyboxIntensity = 0.0f; + } + + if(mSkybox) + { + mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity); + } +} + +float SceneView::GetSkyboxIntensity() const +{ + return mSkyboxIntensity; +} + +void SceneView::SetSkyboxOrientation(const Quaternion& orientation) +{ + mSkyboxOrientation = orientation; + if(mSkybox) + { + mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation); + } +} + +Quaternion SceneView::GetSkyboxOrientation() const +{ + return mSkyboxOrientation; +} + /////////////////////////////////////////////////////////// // // Private methods @@ -344,7 +495,7 @@ void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container) bool SceneView::IsResourceReady() const { - return mIBLResourceReady; + return mIBLResourceReady & mSkyboxResourceReady; } void SceneView::UpdateCamera(CameraActor camera) diff --git a/dali-scene3d/internal/controls/scene-view/scene-view-impl.h b/dali-scene3d/internal/controls/scene-view/scene-view-impl.h index 548bfee..480ffb0 100644 --- a/dali-scene3d/internal/controls/scene-view/scene-view-impl.h +++ b/dali-scene3d/internal/controls/scene-view/scene-view-impl.h @@ -136,6 +136,31 @@ public: */ bool IsUsingFramebuffer() const; + /** + * @copydoc SceneView::SetSkybox() + */ + void SetSkybox(const std::string& skyboxUrl); + + /** + * @copydoc SceneView::SetSkyboxIntensity() + */ + void SetSkyboxIntensity(float intensity); + + /** + * @copydoc SceneView::GetSkyboxIntensity() + */ + float GetSkyboxIntensity() const; + + /** + * @copydoc SceneView::SetSkyboxOrientation() + */ + void SetSkyboxOrientation(const Quaternion& orientation); + + /** + * @copydoc SceneView::GetSkyboxOrientation() + */ + Quaternion GetSkyboxOrientation() const; + protected: /** * @brief Constructs a new SceneView. @@ -229,12 +254,16 @@ private: Dali::RenderTask mRenderTask; Layer mRootLayer; int32_t mWindowOrientation; + Dali::Actor mSkybox; + Quaternion mSkyboxOrientation; + float mSkyboxIntensity{1.0f}; Dali::Texture mSpecularTexture; Dali::Texture mDiffuseTexture; float mIblScaleFactor{1.0f}; bool mUseFrameBuffer{false}; bool mIBLResourceReady{true}; + bool mSkyboxResourceReady{true}; // TODO : Light Source }; diff --git a/dali-scene3d/internal/graphics/shaders/skybox-shader.frag b/dali-scene3d/internal/graphics/shaders/skybox-shader.frag new file mode 100644 index 0000000..2a6024d --- /dev/null +++ b/dali-scene3d/internal/graphics/shaders/skybox-shader.frag @@ -0,0 +1,9 @@ +uniform samplerCube uSkyBoxTexture; +uniform mediump float uIntensity; +varying mediump vec3 vTexCoord; + +void main() +{ + mediump vec4 texColor = textureCube(uSkyBoxTexture, vTexCoord) * uIntensity; + gl_FragColor = texColor; +} \ No newline at end of file diff --git a/dali-scene3d/internal/graphics/shaders/skybox-shader.vert b/dali-scene3d/internal/graphics/shaders/skybox-shader.vert new file mode 100644 index 0000000..944bbb0 --- /dev/null +++ b/dali-scene3d/internal/graphics/shaders/skybox-shader.vert @@ -0,0 +1,21 @@ +attribute mediump vec3 aPosition; +uniform mediump mat4 uModelView; +uniform mediump mat4 uModelMatrix; +uniform mediump mat4 uViewMatrix; +uniform mediump mat4 uProjection; +uniform mediump mat4 uMvpMatrix; +varying mediump vec3 vTexCoord; + +void main() +{ + vTexCoord.x = aPosition.x; + vTexCoord.y = -aPosition.y; // convert to GL coords + vTexCoord.z = aPosition.z; + + mediump vec4 vertexPosition = vec4(aPosition, 1.0); + vec4 clipSpacePosition = uProjection * mat4(mat3(uModelView)) * vertexPosition; + // Writes 1.0, the maximum depth value, into the depth buffer. + // This is an optimization to avoid running the fragment shader + // for the pixels hidden by the scene's objects. + gl_Position = clipSpacePosition.xyww; +} \ No newline at end of file diff --git a/dali-scene3d/public-api/controls/scene-view/scene-view.cpp b/dali-scene3d/public-api/controls/scene-view/scene-view.cpp index 1aea71c..bc41050 100644 --- a/dali-scene3d/public-api/controls/scene-view/scene-view.cpp +++ b/dali-scene3d/public-api/controls/scene-view/scene-view.cpp @@ -127,6 +127,31 @@ bool SceneView::IsUsingFramebuffer() const return GetImpl(*this).IsUsingFramebuffer(); } +void SceneView::SetSkybox(const std::string& skyboxUrl) +{ + GetImpl(*this).SetSkybox(skyboxUrl); +} + +void SceneView::SetSkyboxIntensity(float intensity) +{ + GetImpl(*this).SetSkyboxIntensity(intensity); +} + +float SceneView::GetSkyboxIntensity() const +{ + return GetImpl(*this).GetSkyboxIntensity(); +} + +void SceneView::SetSkyboxOrientation(const Quaternion& orientation) +{ + GetImpl(*this).SetSkyboxOrientation(orientation); +} + +Quaternion SceneView::GetSkyboxOrientation() const +{ + return GetImpl(*this).GetSkyboxOrientation(); +} + } // namespace Scene3D } // namespace Dali diff --git a/dali-scene3d/public-api/controls/scene-view/scene-view.h b/dali-scene3d/public-api/controls/scene-view/scene-view.h index fce3b19..9c72d9c 100644 --- a/dali-scene3d/public-api/controls/scene-view/scene-view.h +++ b/dali-scene3d/public-api/controls/scene-view/scene-view.h @@ -315,6 +315,51 @@ public: */ bool IsUsingFramebuffer() const; + /** + * @brief Sets Skybox for this scene. + * Skybox texture is asynchronously loaded. When loading is finished, ResourceReady is emitted. + * + * @SINCE_2_2.0 + * @param[in] skyboxUrl Cube map image url for skybox. + */ + void SetSkybox(const std::string& skyboxUrl); + + /** + * @brief Sets Skybox intensity. + * The skybox intensity is multiplied to the color of skybox texture. + * Default value is 1.0f. + * + * @SINCE_2_2.0 + * @note Intensity should be positive value. + * @param[in] intensity Intensity value to be multiplied to the cube map color + */ + void SetSkyboxIntensity(float intensity); + + /** + * @brief Gets Skybox intensity. + * Default value is 1.0f. + * + * @SINCE_2_2.0 + * @return skybox intensity + */ + float GetSkyboxIntensity() const; + + /** + * @brief Sets Orientation of Skybox. + * + * @SINCE_2_2.0 + * @param[in] orientation Quaternion for orientation of Skybox. + */ + void SetSkyboxOrientation(const Quaternion& orientation); + + /** + * @brief Gets Skybox orientation. + * + * @SINCE_2_2.0 + * @return skybox orientation + */ + Quaternion GetSkyboxOrientation() const; + public: // Not intended for application developers /// @cond internal /** -- 2.7.4