2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-scene3d/internal/controls/scene-view/scene-view-impl.h>
22 #include <dali-toolkit/dali-toolkit.h>
23 #include <dali-toolkit/devel-api/controls/control-devel.h>
24 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
25 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
26 #include <dali-toolkit/public-api/image-loader/image-url.h>
27 #include <dali-toolkit/public-api/image-loader/image.h>
28 #include <dali/devel-api/actors/camera-actor-devel.h>
29 #include <dali/devel-api/adaptor-framework/window-devel.h>
30 #include <dali/devel-api/common/stage.h>
31 #include <dali/devel-api/rendering/frame-buffer-devel.h>
32 #include <dali/integration-api/adaptor-framework/adaptor.h>
33 #include <dali/integration-api/debug.h>
34 #include <dali/public-api/math/math-utils.h>
35 #include <dali/public-api/object/type-registry-helper.h>
36 #include <dali/public-api/object/type-registry.h>
37 #include <string_view>
40 #include <dali-scene3d/internal/controls/model/model-impl.h>
41 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
42 #include <dali-scene3d/internal/light/light-impl.h>
44 #include <dali/integration-api/debug.h>
58 return Scene3D::SceneView::New();
61 // Setup properties, signals and actions using the type-registry.
62 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create);
64 DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "AlphaMaskUrl", STRING, ALPHA_MASK_URL)
65 DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "MaskContentScale", FLOAT, MASK_CONTENT_SCALE)
66 DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "CropToMask", BOOLEAN, CROP_TO_MASK)
67 DALI_TYPE_REGISTRATION_END()
69 Property::Index RENDERING_BUFFER = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
70 constexpr int32_t DEFAULT_ORIENTATION = 0;
71 constexpr int32_t INVALID_INDEX = -1;
72 constexpr uint32_t MAXIMUM_SIZE_SHADOW_MAP = 2048;
74 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
75 static constexpr std::string_view Y_FLIP_MASK_TEXTURE = "uYFlipMaskTexture";
76 static constexpr float FLIP_MASK_TEXTURE = 1.0f;
78 Dali::Actor CreateSkybox()
85 Vertex skyboxVertices[] = {
87 {Vector3(-1.0f, 1.0f, -1.0f)},
88 {Vector3(-1.0f, -1.0f, -1.0f)},
89 {Vector3(1.0f, -1.0f, -1.0f)},
90 {Vector3(1.0f, -1.0f, -1.0f)},
91 {Vector3(1.0f, 1.0f, -1.0f)},
92 {Vector3(-1.0f, 1.0f, -1.0f)},
95 {Vector3(-1.0f, -1.0f, 1.0f)},
96 {Vector3(-1.0f, -1.0f, -1.0f)},
97 {Vector3(-1.0f, 1.0f, -1.0f)},
98 {Vector3(-1.0f, 1.0f, -1.0f)},
99 {Vector3(-1.0f, 1.0f, 1.0f)},
100 {Vector3(-1.0f, -1.0f, 1.0f)},
103 {Vector3(1.0f, -1.0f, -1.0f)},
104 {Vector3(1.0f, -1.0f, 1.0f)},
105 {Vector3(1.0f, 1.0f, 1.0f)},
106 {Vector3(1.0f, 1.0f, 1.0f)},
107 {Vector3(1.0f, 1.0f, -1.0f)},
108 {Vector3(1.0f, -1.0f, -1.0f)},
111 {Vector3(-1.0f, -1.0f, 1.0f)},
112 {Vector3(-1.0f, 1.0f, 1.0f)},
113 {Vector3(1.0f, 1.0f, 1.0f)},
114 {Vector3(1.0f, 1.0f, 1.0f)},
115 {Vector3(1.0f, -1.0f, 1.0f)},
116 {Vector3(-1.0f, -1.0f, 1.0f)},
119 {Vector3(-1.0f, 1.0f, -1.0f)},
120 {Vector3(1.0f, 1.0f, -1.0f)},
121 {Vector3(1.0f, 1.0f, 1.0f)},
122 {Vector3(1.0f, 1.0f, 1.0f)},
123 {Vector3(-1.0f, 1.0f, 1.0f)},
124 {Vector3(-1.0f, 1.0f, -1.0f)},
127 {Vector3(-1.0f, -1.0f, -1.0f)},
128 {Vector3(-1.0f, -1.0f, 1.0f)},
129 {Vector3(1.0f, -1.0f, -1.0f)},
130 {Vector3(1.0f, -1.0f, -1.0f)},
131 {Vector3(-1.0f, -1.0f, 1.0f)},
132 {Vector3(1.0f, -1.0f, 1.0f)}};
134 Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3));
135 vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
137 Dali::Geometry skyboxGeometry = Geometry::New();
138 skyboxGeometry.AddVertexBuffer(vertexBuffer);
139 skyboxGeometry.SetType(Geometry::TRIANGLES);
141 Dali::Shader shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
142 Dali::Renderer skyboxRenderer;
143 skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
144 skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
145 // Enables the depth test.
146 skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
147 // The fragment shader will run only is those pixels that have the max depth value.
148 skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
150 Dali::Actor skyboxActor = Actor::New();
151 skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
152 skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
153 skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
154 skyboxActor.AddRenderer(skyboxRenderer);
158 void SetShadowLightConstraint(Dali::CameraActor selectedCamera, Dali::CameraActor shadowLightCamera)
160 shadowLightCamera.SetProperty(Dali::CameraActor::Property::ASPECT_RATIO, 1.0f);
161 shadowLightCamera.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, 1.0f);
162 shadowLightCamera.SetProperty(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE, 0.5f);
163 shadowLightCamera.SetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE, 3.5f);
165 //< Make constraint for above properties.
166 shadowLightCamera.RemoveConstraints();
168 // Compute ViewProjectionMatrix and store it to "tempViewProjectionMatrix" property
169 auto tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY);
170 Constraint projectionMatrixConstraint = Constraint::New<Matrix>(shadowLightCamera, tempViewProjectionMatrixIndex, [](Matrix& output, const PropertyInputContainer& inputs) {
171 Matrix worldMatrix = inputs[0]->GetMatrix();
172 float tangentFov_2 = tanf(inputs[4]->GetFloat());
173 float nearDistance = inputs[5]->GetFloat();
174 float farDistance = inputs[6]->GetFloat();
175 float aspectRatio = inputs[7]->GetFloat();
180 if(inputs[1]->GetInteger() == Dali::Camera::ProjectionMode::PERSPECTIVE_PROJECTION)
182 if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
184 nearY = tangentFov_2 * nearDistance;
185 nearX = nearY * aspectRatio;
186 farY = tangentFov_2 * farDistance;
187 farX = farY * aspectRatio;
191 nearX = tangentFov_2 * nearDistance;
192 nearY = nearX / aspectRatio;
193 farX = tangentFov_2 * farDistance;
194 farY = farX / aspectRatio;
199 if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
201 nearY = inputs[3]->GetFloat();
202 nearX = nearY * aspectRatio;
206 nearX = inputs[3]->GetFloat();
207 nearY = nearX / aspectRatio;
213 std::vector<Vector4> points;
214 points.push_back(Vector4(nearX, nearY, nearDistance, 1.0f));
215 points.push_back(Vector4(-nearX, nearY, nearDistance, 1.0f));
216 points.push_back(Vector4(-nearX, -nearY, nearDistance, 1.0f));
217 points.push_back(Vector4(nearX, -nearY, nearDistance, 1.0f));
218 points.push_back(Vector4(farX, farY, farDistance, 1.0f));
219 points.push_back(Vector4(-farX, farY, farDistance, 1.0f));
220 points.push_back(Vector4(-farX, -farY, farDistance, 1.0f));
221 points.push_back(Vector4(farX, -farY, farDistance, 1.0f));
223 Matrix shadowCameraWorldMatrix = inputs[8]->GetMatrix();
225 for(auto&& point : points)
227 point = worldMatrix * point;
228 worldCenter += point;
231 shadowCameraWorldMatrix.SetTranslation(Vector3(worldCenter));
232 Matrix shadowCameraViewMatrix = shadowCameraWorldMatrix;
233 shadowCameraViewMatrix.Invert();
235 Vector3 areaMin = Vector3::ONE * MAXFLOAT, areaMax = Vector3::ONE * -MAXFLOAT;
236 for(auto&& point : points)
238 Vector4 pointV = shadowCameraViewMatrix * point;
239 areaMin.x = std::min(areaMin.x, pointV.x);
240 areaMin.y = std::min(areaMin.y, pointV.y);
241 areaMin.z = std::min(areaMin.z, pointV.z);
242 areaMax.x = std::max(areaMax.x, pointV.x);
243 areaMax.y = std::max(areaMax.y, pointV.y);
244 areaMax.z = std::max(areaMax.z, pointV.z);
247 Vector2 center = Vector2(areaMax + areaMin) * 0.5;
248 float delta = std::max(std::abs(areaMax.x - areaMin.x), std::abs(areaMax.y - areaMin.y));
249 float delta_2 = delta * 0.5f;
250 Vector2 squareAreaMin = center - Vector2::ONE * delta_2;
251 Vector2 squareAreaMax = center + Vector2::ONE * delta_2;
252 float deltaZ = areaMax.z - areaMin.z;
254 float right = -squareAreaMin.x;
255 float left = -squareAreaMax.x;
256 float top = squareAreaMin.y;
257 float bottom = squareAreaMax.y;
258 float near = areaMin.z;
259 float far = areaMax.z;
261 float* projMatrix = output.AsFloat();
263 projMatrix[0] = -2.0f / delta;
264 projMatrix[1] = 0.0f;
265 projMatrix[2] = 0.0f;
266 projMatrix[3] = 0.0f;
268 projMatrix[4] = 0.0f;
269 projMatrix[5] = -2.0f / delta;
270 projMatrix[6] = 0.0f;
271 projMatrix[7] = 0.0f;
273 projMatrix[8] = 0.0f;
274 projMatrix[9] = 0.0f;
275 projMatrix[10] = 2.0f / deltaZ;
276 projMatrix[11] = 0.0f;
278 projMatrix[12] = -(right + left) / delta;
279 projMatrix[13] = -(top + bottom) / delta;
280 projMatrix[14] = -(near + far) / deltaZ;
281 projMatrix[15] = 1.0f;
283 output = output * shadowCameraViewMatrix;
285 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::Actor::Property::WORLD_MATRIX});
286 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::PROJECTION_MODE});
287 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::PROJECTION_DIRECTION});
288 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE});
289 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FIELD_OF_VIEW});
290 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::NEAR_PLANE_DISTANCE});
291 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FAR_PLANE_DISTANCE});
292 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::ASPECT_RATIO});
293 projectionMatrixConstraint.AddSource(Source{shadowLightCamera, Dali::Actor::Property::WORLD_MATRIX});
294 projectionMatrixConstraint.ApplyPost();
297 } // anonymous namespace
299 SceneView::SceneView()
300 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
301 mWindowOrientation(DEFAULT_ORIENTATION),
303 mSkyboxOrientation(Quaternion()),
304 mSkyboxIntensity(1.0f),
305 mShaderManager(new Scene3D::Loader::ShaderManager())
309 SceneView::~SceneView()
311 if(Dali::Adaptor::IsAvailable())
313 if(mIblDiffuseLoadTask)
315 Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
316 mIblDiffuseLoadTask.Reset();
318 if(mIblSpecularLoadTask)
320 Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
321 mIblSpecularLoadTask.Reset();
325 Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
326 mSkyboxLoadTask.Reset();
331 Dali::Scene3D::SceneView SceneView::New()
333 SceneView* impl = new SceneView();
335 Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl);
337 // Second-phase init of the implementation
338 // This can only be done after the CustomActor connection has been made...
344 void SceneView::AddCamera(CameraActor camera)
350 UpdateCamera(camera);
352 mCameras.push_back(camera);
356 void SceneView::RemoveCamera(CameraActor camera)
358 if(camera == mDefaultCamera)
360 DALI_LOG_ERROR("Default Camera cannot removed.\n");
366 for(uint32_t i = 0; i < mCameras.size(); ++i)
368 if(mCameras[i] == camera)
370 mCameras.erase(mCameras.begin() + i);
375 if(mSelectedCamera == camera)
377 CameraActor newCurrentCamera = *mCameras.begin();
378 UpdateCamera(newCurrentCamera);
383 uint32_t SceneView::GetCameraCount() const
385 return mCameras.size();
388 CameraActor SceneView::GetSelectedCamera() const
390 return mSelectedCamera;
393 CameraActor SceneView::GetCamera(uint32_t index) const
395 if(index < mCameras.size())
397 return mCameras[index];
399 DALI_LOG_ERROR("Input index is out of bounds\n");
400 return CameraActor();
403 CameraActor SceneView::GetCamera(const std::string& name) const
405 CameraActor returnCamera;
406 for(auto&& camera : mCameras)
408 if(camera.GetProperty<std::string>(Actor::Property::NAME) == name)
410 returnCamera = camera;
417 void SceneView::SelectCamera(uint32_t index)
419 UpdateCamera(GetCamera(index));
422 void SceneView::SelectCamera(const std::string& name)
424 UpdateCamera(GetCamera(name));
427 void SceneView::RegisterSceneItem(Scene3D::Internal::LightObserver* item)
431 item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
432 item->NotifyShadowMapTexture(mShadowTexture);
433 mItems.push_back(item);
437 void SceneView::UnregisterSceneItem(Scene3D::Internal::LightObserver* item)
441 for(uint32_t i = 0; i < mItems.size(); ++i)
443 if(mItems[i] == item)
445 mItems.erase(mItems.begin() + i);
452 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
454 bool needIblReset = false;
455 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
456 if(mDiffuseIblUrl != diffuseUrl)
458 mDiffuseIblUrl = diffuseUrl;
459 if(mDiffuseIblUrl.empty())
465 mIblDiffuseDirty = true;
466 mIblDiffuseResourceReady = false;
470 if(mSpecularIblUrl != specularUrl)
472 mSpecularIblUrl = specularUrl;
473 if(mSpecularIblUrl.empty())
479 mIblSpecularDirty = true;
480 mIblSpecularResourceReady = false;
484 // If one or both of diffuse url and specular url are empty,
485 // we don't need to request to load texture.
488 if(mIblDiffuseLoadTask)
490 Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
491 mIblDiffuseLoadTask.Reset();
494 if(mIblSpecularLoadTask)
496 Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
497 mIblSpecularLoadTask.Reset();
500 mIblDiffuseDirty = false;
501 mIblSpecularDirty = false;
502 mIblDiffuseResourceReady = true;
503 mIblSpecularResourceReady = true;
505 mDiffuseTexture.Reset();
506 mSpecularTexture.Reset();
508 mSpecularMipmapLevels = 1u;
509 NotifyImageBasedLightTextureChange();
513 if(isOnScene && mIblDiffuseDirty)
515 if(mIblDiffuseLoadTask)
517 Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
518 mIblDiffuseLoadTask.Reset();
520 mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete));
521 Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
522 mIblDiffuseDirty = false;
525 if(isOnScene && mIblSpecularDirty)
527 if(mIblSpecularLoadTask)
529 Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
530 mIblSpecularLoadTask.Reset();
532 mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete));
533 Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
534 mIblSpecularDirty = false;
538 if(!Dali::Equals(mIblScaleFactor, scaleFactor))
540 SetImageBasedLightScaleFactor(scaleFactor);
543 // If diffuse and specular textures are already loaded, emits resource ready signal here.
544 if(IsResourceReady())
546 Control::SetResourceReady();
550 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
552 mIblScaleFactor = scaleFactor;
553 for(auto&& item : mItems)
557 item->NotifyImageBasedLightScaleFactor(scaleFactor);
562 float SceneView::GetImageBasedLightScaleFactor() const
564 return mIblScaleFactor;
567 void SceneView::AddLight(Scene3D::Light light)
569 bool enabled = mShaderManager->AddLight(light);
570 mLights.push_back(std::make_pair(light, enabled));
572 if(light.IsShadowEnabled())
578 void SceneView::RemoveLight(Scene3D::Light light)
580 mShaderManager->RemoveLight(light);
581 for(uint32_t i = 0; i < mLights.size(); ++i)
583 if(mLights[i].first == light)
585 mLights.erase(mLights.begin() + i);
590 if(mLights.size() > mShaderManager->GetLightCount())
592 for(auto&& waitingLight : mLights)
594 if(waitingLight.second)
599 waitingLight.second = mShaderManager->AddLight(waitingLight.first);
604 if(light == mShadowLight)
611 for(auto&& lightEntity : mLights)
613 if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
617 SetShadow(lightEntity.first);
623 void SceneView::SetShadow(Scene3D::Light light)
630 auto foundLight = std::find_if(mLights.begin(), mLights.end(), [light](std::pair<Scene3D::Light, bool> lightEntity) -> bool { return (lightEntity.second && lightEntity.first == light); });
632 if(foundLight == mLights.end())
637 mShadowLight = light;
639 // Directional Light setting.
640 CameraActor lightCamera = GetImplementation(light).GetCamera();
641 CameraActor selectedCamera = GetSelectedCamera();
642 SetShadowLightConstraint(selectedCamera, lightCamera);
644 // make framebuffer for depth map and set it to render task.
645 uint32_t shadowMapBufferSize = std::min(std::max(GetResolutionWidth(), GetResolutionHeight()), MAXIMUM_SIZE_SHADOW_MAP);
646 UpdateShadowMapBuffer(shadowMapBufferSize);
648 // use lightCamera as a camera of shadow render task.
649 mShadowMapRenderTask.SetCameraActor(lightCamera);
651 mShaderManager->SetShadow(light);
654 void SceneView::RemoveShadow(Scene3D::Light light)
656 if(mShadowLight != light)
661 // remove all constraint from light camera
662 CameraActor lightCamera = GetImplementation(mShadowLight).GetCamera();
663 lightCamera.RemoveConstraints();
665 // reset framebuffer and remove it from render task.
666 mShadowFrameBuffer.Reset();
667 mShaderManager->RemoveShadow();
668 mShadowMapRenderTask.SetCameraActor(CameraActor());
670 mShadowLight.Reset();
672 mShadowTexture.Reset();
673 for(auto&& item : mItems)
677 item->NotifyShadowMapTexture(mShadowTexture);
681 for(auto&& lightEntity : mLights)
683 if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
687 SetShadow(lightEntity.first);
692 uint32_t SceneView::GetActivatedLightCount() const
694 return mShaderManager->GetLightCount();
697 void SceneView::UseFramebuffer(bool useFramebuffer)
699 if(mUseFrameBuffer != useFramebuffer)
701 mUseFrameBuffer = useFramebuffer;
706 bool SceneView::IsUsingFramebuffer() const
708 return mUseFrameBuffer;
711 void SceneView::SetResolution(uint32_t width, uint32_t height)
713 if(mWindowWidth != width || mWindowHeight != height)
715 mWindowWidth = width;
716 mWindowHeight = height;
719 mWindowSizeChanged = true;
725 uint32_t SceneView::GetResolutionWidth()
727 if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
729 return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_WIDTH));
734 uint32_t SceneView::GetResolutionHeight()
736 if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
738 return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_HEIGHT));
740 return mWindowHeight;
743 void SceneView::ResetResolution()
745 SetResolution(0u, 0u);
748 void SceneView::SetFramebufferMultiSamplingLevel(uint8_t multiSamplingLevel)
750 if(mFrameBufferMultiSamplingLevel != multiSamplingLevel)
752 mFrameBufferMultiSamplingLevel = multiSamplingLevel;
754 // Create new framebuffer with changed multiSamplingLevel.
755 if(mRenderTask && mFrameBuffer && mTexture)
757 mFrameBuffer = FrameBuffer::New(GetResolutionWidth(), GetResolutionHeight(), FrameBuffer::Attachment::DEPTH_STENCIL);
758 mFrameBuffer.AttachColorTexture(mTexture);
759 DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
760 mRenderTask.SetFrameBuffer(mFrameBuffer);
762 // Note : we don't need to create new visual since visual's url is depend on mTexture.
767 uint8_t SceneView::GetFramebufferMultiSamplingLevel() const
769 return mFrameBufferMultiSamplingLevel;
772 void SceneView::SetSkybox(const std::string& skyboxUrl)
774 if(mSkyboxUrl != skyboxUrl)
776 UpdateSkybox(skyboxUrl, mSkyboxEnvironmentMapType);
780 void SceneView::SetSkyboxEnvironmentMapType(Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
782 if(mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
784 UpdateSkybox(mSkyboxUrl, skyboxEnvironmentMapType);
788 void SceneView::SetSkyboxIntensity(float intensity)
790 mSkyboxIntensity = intensity;
793 DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
794 mSkyboxIntensity = 0.0f;
799 mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
803 float SceneView::GetSkyboxIntensity() const
805 return mSkyboxIntensity;
808 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
810 mSkyboxOrientation = orientation;
813 mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
817 Quaternion SceneView::GetSkyboxOrientation() const
819 return mSkyboxOrientation;
822 Dali::Scene3D::Loader::ShaderManagerPtr SceneView::GetShaderManager() const
824 return mShaderManager;
827 void SceneView::UpdateShadowUniform(Scene3D::Light light)
829 mShaderManager->UpdateShadowUniform(light);
832 void SceneView::SetAlphaMaskUrl(std::string& alphaMaskUrl)
834 if(mAlphaMaskUrl != alphaMaskUrl)
836 mAlphaMaskUrl = alphaMaskUrl;
837 mMaskingPropertyChanged = true;
842 std::string SceneView::GetAlphaMaskUrl()
844 return mAlphaMaskUrl;
847 void SceneView::SetMaskContentScaleFactor(float maskContentScaleFactor)
849 if(mMaskContentScaleFactor != maskContentScaleFactor)
851 mMaskContentScaleFactor = maskContentScaleFactor;
852 mMaskingPropertyChanged = true;
857 float SceneView::GetMaskContentScaleFactor()
859 return mMaskContentScaleFactor;
862 void SceneView::EnableCropToMask(bool enableCropToMask)
864 if(mCropToMask != enableCropToMask)
866 mCropToMask = enableCropToMask;
867 mMaskingPropertyChanged = true;
872 bool SceneView::IsEnabledCropToMask()
877 void SceneView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
879 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
883 SceneView& sceneViewImpl(GetImpl(sceneView));
887 case Scene3D::SceneView::Property::ALPHA_MASK_URL:
889 std::string alphaMaskUrl = value.Get<std::string>();
890 sceneViewImpl.SetAlphaMaskUrl(alphaMaskUrl);
893 case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
895 sceneViewImpl.SetMaskContentScaleFactor(value.Get<float>());
898 case Scene3D::SceneView::Property::CROP_TO_MASK:
900 sceneViewImpl.EnableCropToMask(value.Get<bool>());
907 Property::Value SceneView::GetProperty(BaseObject* object, Property::Index index)
909 Property::Value value;
911 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
915 SceneView& sceneViewImpl(GetImpl(sceneView));
919 case Scene3D::SceneView::Property::ALPHA_MASK_URL:
921 value = sceneViewImpl.GetAlphaMaskUrl();
924 case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
926 value = sceneViewImpl.GetMaskContentScaleFactor();
929 case Scene3D::SceneView::Property::CROP_TO_MASK:
931 value = sceneViewImpl.IsEnabledCropToMask();
939 ///////////////////////////////////////////////////////////
944 void SceneView::OnSceneConnection(int depth)
946 // If diffuse and specular url is not valid, IBL does not need to be loaded.
947 if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
949 SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
952 if(!mSkyboxUrl.empty())
954 UpdateSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType);
957 Window window = DevelWindow::Get(Self());
960 // Only for on-screen window
961 window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
964 mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
967 // On-screen / Off-screen window
968 mSceneHolder = Integration::SceneHolder::Get(Self());
971 RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
972 mShadowMapRenderTask = taskList.CreateTask();
973 mShadowMapRenderTask.SetSourceActor(mRootLayer);
974 mShadowMapRenderTask.SetExclusive(true);
975 mShadowMapRenderTask.SetInputEnabled(false);
976 mShadowMapRenderTask.SetCullMode(false);
977 mShadowMapRenderTask.SetClearEnabled(true);
978 mShadowMapRenderTask.SetClearColor(Color::WHITE);
979 mShadowMapRenderTask.SetRenderPassTag(10);
980 mShadowMapRenderTask.SetCameraActor(CameraActor());
982 mRenderTask = taskList.CreateTask();
983 mRenderTask.SetSourceActor(mRootLayer);
984 mRenderTask.SetExclusive(true);
985 mRenderTask.SetInputEnabled(true);
986 mRenderTask.SetCullMode(false);
987 mRenderTask.SetScreenToFrameBufferMappingActor(Self());
992 Control::OnSceneConnection(depth);
995 void SceneView::OnSceneDisconnection()
999 Window window = mWindow.GetHandle();
1002 window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
1010 RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1011 taskList.RemoveTask(mRenderTask);
1012 mRenderTask.Reset();
1014 if(mShadowMapRenderTask)
1016 RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1017 taskList.RemoveTask(mShadowMapRenderTask);
1018 mShadowMapRenderTask.Reset();
1020 mSceneHolder.Reset();
1022 mFrameBuffer.Reset();
1023 mShadowFrameBuffer.Reset();
1025 Control::OnSceneDisconnection();
1028 void SceneView::OnInitialize()
1030 Actor self = Self();
1031 mRootLayer = Layer::New();
1032 mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
1033 mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
1034 // The models in the SceneView should be have independent coordinate with DALi default coordinate.
1035 mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
1036 mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
1037 mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
1038 self.Add(mRootLayer);
1040 mDefaultCamera = Dali::CameraActor::New3DCamera();
1041 mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
1042 mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
1043 AddCamera(mDefaultCamera);
1044 UpdateCamera(mDefaultCamera);
1047 void SceneView::OnChildAdd(Actor& child)
1049 if(child != mRootLayer)
1051 mRootLayer.Add(child);
1053 Control::OnChildAdd(child);
1056 void SceneView::OnChildRemove(Actor& child)
1058 mRootLayer.Remove(child);
1059 Control::OnChildRemove(child);
1062 float SceneView::GetHeightForWidth(float width)
1065 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1066 return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
1069 float SceneView::GetWidthForHeight(float height)
1072 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1073 return Control::GetWidthForHeight(height) + padding.start + padding.end;
1076 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
1078 Control::OnRelayout(size, container);
1079 // Change canvas size of camera actor.
1083 bool SceneView::IsResourceReady() const
1085 return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady;
1088 void SceneView::UpdateCamera(CameraActor camera)
1092 if(mSelectedCamera && mSelectedCamera.GetParent())
1094 mSelectedCamera.Unparent();
1096 mRootLayer.Add(camera);
1099 mSelectedCamera = camera;
1102 SetShadowLightConstraint(mSelectedCamera, GetImplementation(mShadowLight).GetCamera());
1107 void SceneView::UpdateRenderTask()
1111 if(mSelectedCamera != mRenderTask.GetCameraActor())
1113 mRenderTask.SetCameraActor(mSelectedCamera);
1115 uint32_t width = GetResolutionWidth();
1116 uint32_t height = GetResolutionHeight();
1118 uint32_t shadowMapBufferSize = std::min(std::max(width, height), MAXIMUM_SIZE_SHADOW_MAP);
1119 UpdateShadowMapBuffer(shadowMapBufferSize);
1123 Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
1124 if(!currentFrameBuffer ||
1125 !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), width) ||
1126 !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), height) ||
1127 mMaskingPropertyChanged ||
1130 mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR);
1131 mRenderTask.ResetViewportGuideActor();
1132 mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
1134 // create offscreen buffer of new size to render our child actors to
1135 mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
1136 mFrameBuffer = FrameBuffer::New(width, height, FrameBuffer::Attachment::DEPTH_STENCIL);
1137 mFrameBuffer.AttachColorTexture(mTexture);
1138 DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
1139 Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
1141 Property::Map imagePropertyMap;
1142 imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
1143 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
1144 // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
1145 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
1146 if(!mAlphaMaskUrl.empty())
1148 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mAlphaMaskUrl);
1149 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, true);
1150 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskContentScaleFactor);
1151 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mCropToMask);
1152 imagePropertyMap.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, Toolkit::DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
1153 Self().RegisterProperty(Y_FLIP_MASK_TEXTURE, FLIP_MASK_TEXTURE);
1156 mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
1157 Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
1159 mRenderTask.SetFrameBuffer(mFrameBuffer);
1160 mRenderTask.SetClearEnabled(true);
1161 mRenderTask.SetClearColor(Color::TRANSPARENT);
1163 mMaskingPropertyChanged = false;
1164 mWindowSizeChanged = false;
1169 mRenderTask.SetViewportGuideActor(Self());
1170 if(mRenderTask.GetFrameBuffer())
1172 mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA);
1173 FrameBuffer framebuffer;
1174 mRenderTask.SetFrameBuffer(framebuffer);
1175 mRenderTask.SetClearEnabled(false);
1177 Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
1180 mFrameBuffer.Reset();
1185 if(width > 0u && height > 0u)
1187 float aspectRatio = static_cast<float>(width) / static_cast<float>(height);
1188 mSelectedCamera.SetAspectRatio(aspectRatio);
1195 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
1197 mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
1201 void SceneView::RotateCamera()
1205 DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
1209 DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
1213 void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
1215 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
1216 if(mSkyboxUrl != skyboxUrl || mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
1218 mSkyboxDirty = true;
1219 mSkyboxResourceReady = false;
1220 mSkyboxUrl = skyboxUrl;
1221 mSkyboxEnvironmentMapType = skyboxEnvironmentMapType;
1224 if(mSkyboxUrl.empty())
1228 Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1229 mSkyboxLoadTask.Reset();
1236 mSkyboxTexture.Reset();
1239 mSkyboxDirty = false;
1240 mSkyboxResourceReady = true;
1244 if(isOnScene && mSkyboxDirty)
1248 Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1249 mSkyboxLoadTask.Reset();
1252 mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, mSkyboxEnvironmentMapType, MakeCallback(this, &SceneView::OnSkyboxLoadComplete));
1253 Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask);
1254 mSkyboxDirty = false;
1258 if(IsResourceReady())
1260 Control::SetResourceReady();
1264 void SceneView::OnSkyboxLoadComplete()
1268 mSkybox = CreateSkybox();
1269 SetSkyboxIntensity(mSkyboxIntensity);
1270 SetSkyboxOrientation(mSkyboxOrientation);
1273 mRootLayer.Add(mSkybox);
1277 mSkyboxResourceReady = true;
1278 mSkyboxTexture = mSkyboxLoadTask->GetLoadedTexture();
1279 Shader skyboxShader;
1280 if(mSkyboxLoadTask->GetEnvironmentMapType() == Scene3D::EnvironmentMapType::CUBEMAP)
1282 skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
1286 skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data());
1289 Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer();
1292 Dali::TextureSet skyboxTextures = TextureSet::New();
1293 skyboxTextures.SetTexture(0, mSkyboxTexture);
1294 skyboxRenderer.SetTextures(skyboxTextures);
1295 skyboxRenderer.SetShader(skyboxShader);
1298 mSkyboxLoadTask.Reset();
1300 if(IsResourceReady())
1302 Control::SetResourceReady();
1306 void SceneView::OnIblDiffuseLoadComplete()
1308 mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
1309 mIblDiffuseResourceReady = true;
1310 mIblDiffuseLoadTask.Reset();
1311 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1313 OnIblLoadComplete();
1317 void SceneView::OnIblSpecularLoadComplete()
1319 mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
1320 mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
1321 mIblSpecularResourceReady = true;
1322 mIblSpecularLoadTask.Reset();
1323 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1325 OnIblLoadComplete();
1329 void SceneView::OnIblLoadComplete()
1331 NotifyImageBasedLightTextureChange();
1332 if(IsResourceReady())
1334 Control::SetResourceReady();
1338 void SceneView::NotifyImageBasedLightTextureChange()
1340 for(auto&& item : mItems)
1344 item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
1349 void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize)
1351 Dali::FrameBuffer currentShadowFrameBuffer = mShadowMapRenderTask.GetFrameBuffer();
1353 (!currentShadowFrameBuffer ||
1355 !Dali::Equals(DevelFrameBuffer::GetDepthTexture(currentShadowFrameBuffer).GetWidth(), shadowMapSize)))
1357 mShadowFrameBuffer.Reset();
1358 mShadowTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::DEPTH_UNSIGNED_INT, shadowMapSize, shadowMapSize);
1359 mShadowFrameBuffer = FrameBuffer::New(shadowMapSize, shadowMapSize, FrameBuffer::Attachment::NONE);
1360 DevelFrameBuffer::AttachDepthTexture(mShadowFrameBuffer, mShadowTexture);
1361 mShadowMapRenderTask.SetFrameBuffer(mShadowFrameBuffer);
1363 for(auto&& item : mItems)
1367 item->NotifyShadowMapTexture(mShadowTexture);
1373 } // namespace Internal
1374 } // namespace Scene3D