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/common/image-resource-loader.h>
41 #include <dali-scene3d/internal/controls/model/model-impl.h>
42 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
43 #include <dali-scene3d/internal/light/light-impl.h>
45 #include <dali/integration-api/debug.h>
59 return Scene3D::SceneView::New();
62 // Setup properties, signals and actions using the type-registry.
63 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create);
65 DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "AlphaMaskUrl", STRING, ALPHA_MASK_URL)
66 DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "MaskContentScale", FLOAT, MASK_CONTENT_SCALE)
67 DALI_PROPERTY_REGISTRATION(Scene3D, SceneView, "CropToMask", BOOLEAN, CROP_TO_MASK)
68 DALI_TYPE_REGISTRATION_END()
70 Property::Index RENDERING_BUFFER = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
71 constexpr int32_t DEFAULT_ORIENTATION = 0;
72 constexpr int32_t INVALID_INDEX = -1;
73 constexpr uint32_t MAXIMUM_SIZE_SHADOW_MAP = 2048;
75 constexpr int32_t SCENE_ORDER_INDEX = 100;
76 constexpr int32_t SHADOW_ORDER_INDEX = 99;
78 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
79 static constexpr std::string_view Y_FLIP_MASK_TEXTURE = "uYFlipMaskTexture";
80 static constexpr float FLIP_MASK_TEXTURE = 1.0f;
82 Dali::Actor CreateSkybox()
89 Vertex skyboxVertices[] = {
91 {Vector3(-1.0f, 1.0f, -1.0f)},
92 {Vector3(-1.0f, -1.0f, -1.0f)},
93 {Vector3(1.0f, -1.0f, -1.0f)},
94 {Vector3(1.0f, -1.0f, -1.0f)},
95 {Vector3(1.0f, 1.0f, -1.0f)},
96 {Vector3(-1.0f, 1.0f, -1.0f)},
99 {Vector3(-1.0f, -1.0f, 1.0f)},
100 {Vector3(-1.0f, -1.0f, -1.0f)},
101 {Vector3(-1.0f, 1.0f, -1.0f)},
102 {Vector3(-1.0f, 1.0f, -1.0f)},
103 {Vector3(-1.0f, 1.0f, 1.0f)},
104 {Vector3(-1.0f, -1.0f, 1.0f)},
107 {Vector3(1.0f, -1.0f, -1.0f)},
108 {Vector3(1.0f, -1.0f, 1.0f)},
109 {Vector3(1.0f, 1.0f, 1.0f)},
110 {Vector3(1.0f, 1.0f, 1.0f)},
111 {Vector3(1.0f, 1.0f, -1.0f)},
112 {Vector3(1.0f, -1.0f, -1.0f)},
115 {Vector3(-1.0f, -1.0f, 1.0f)},
116 {Vector3(-1.0f, 1.0f, 1.0f)},
117 {Vector3(1.0f, 1.0f, 1.0f)},
118 {Vector3(1.0f, 1.0f, 1.0f)},
119 {Vector3(1.0f, -1.0f, 1.0f)},
120 {Vector3(-1.0f, -1.0f, 1.0f)},
123 {Vector3(-1.0f, 1.0f, -1.0f)},
124 {Vector3(1.0f, 1.0f, -1.0f)},
125 {Vector3(1.0f, 1.0f, 1.0f)},
126 {Vector3(1.0f, 1.0f, 1.0f)},
127 {Vector3(-1.0f, 1.0f, 1.0f)},
128 {Vector3(-1.0f, 1.0f, -1.0f)},
131 {Vector3(-1.0f, -1.0f, -1.0f)},
132 {Vector3(-1.0f, -1.0f, 1.0f)},
133 {Vector3(1.0f, -1.0f, -1.0f)},
134 {Vector3(1.0f, -1.0f, -1.0f)},
135 {Vector3(-1.0f, -1.0f, 1.0f)},
136 {Vector3(1.0f, -1.0f, 1.0f)}};
138 Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3));
139 vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
141 Dali::Geometry skyboxGeometry = Geometry::New();
142 skyboxGeometry.AddVertexBuffer(vertexBuffer);
143 skyboxGeometry.SetType(Geometry::TRIANGLES);
145 Dali::Shader shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_CUBE");
146 Dali::Renderer skyboxRenderer;
147 skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
148 skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
149 // Enables the depth test.
150 skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
151 // The fragment shader will run only is those pixels that have the max depth value.
152 skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
154 Dali::Actor skyboxActor = Actor::New();
155 skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
156 skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
157 skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
158 skyboxActor.AddRenderer(skyboxRenderer);
162 void SetShadowLightConstraint(Dali::CameraActor selectedCamera, Dali::CameraActor shadowLightCamera)
164 shadowLightCamera.SetProperty(Dali::CameraActor::Property::ASPECT_RATIO, 1.0f);
165 shadowLightCamera.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, 1.0f);
166 shadowLightCamera.SetProperty(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE, 0.5f);
167 shadowLightCamera.SetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE, 3.5f);
169 //< Make constraint for above properties.
170 shadowLightCamera.RemoveConstraints();
172 // Compute ViewProjectionMatrix and store it to "tempViewProjectionMatrix" property
173 auto tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY);
174 Constraint projectionMatrixConstraint = Constraint::New<Matrix>(shadowLightCamera, tempViewProjectionMatrixIndex, [](Matrix& output, const PropertyInputContainer& inputs) {
175 Matrix worldMatrix = inputs[0]->GetMatrix();
176 float tangentFov_2 = tanf(inputs[4]->GetFloat());
177 float nearDistance = inputs[5]->GetFloat();
178 float farDistance = inputs[6]->GetFloat();
179 float aspectRatio = inputs[7]->GetFloat();
184 if(inputs[1]->GetInteger() == Dali::Camera::ProjectionMode::PERSPECTIVE_PROJECTION)
186 if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
188 nearY = tangentFov_2 * nearDistance;
189 nearX = nearY * aspectRatio;
190 farY = tangentFov_2 * farDistance;
191 farX = farY * aspectRatio;
195 nearX = tangentFov_2 * nearDistance;
196 nearY = nearX / aspectRatio;
197 farX = tangentFov_2 * farDistance;
198 farY = farX / aspectRatio;
203 if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
205 nearY = inputs[3]->GetFloat();
206 nearX = nearY * aspectRatio;
210 nearX = inputs[3]->GetFloat();
211 nearY = nearX / aspectRatio;
217 std::vector<Vector4> points;
218 points.push_back(Vector4(nearX, nearY, nearDistance, 1.0f));
219 points.push_back(Vector4(-nearX, nearY, nearDistance, 1.0f));
220 points.push_back(Vector4(-nearX, -nearY, nearDistance, 1.0f));
221 points.push_back(Vector4(nearX, -nearY, nearDistance, 1.0f));
222 points.push_back(Vector4(farX, farY, farDistance, 1.0f));
223 points.push_back(Vector4(-farX, farY, farDistance, 1.0f));
224 points.push_back(Vector4(-farX, -farY, farDistance, 1.0f));
225 points.push_back(Vector4(farX, -farY, farDistance, 1.0f));
227 Matrix shadowCameraWorldMatrix = inputs[8]->GetMatrix();
229 for(auto&& point : points)
231 point = worldMatrix * point;
232 worldCenter += point;
235 shadowCameraWorldMatrix.SetTranslation(Vector3(worldCenter));
236 Matrix shadowCameraViewMatrix = shadowCameraWorldMatrix;
237 shadowCameraViewMatrix.Invert();
239 Vector3 areaMin = Vector3::ONE * MAXFLOAT, areaMax = Vector3::ONE * -MAXFLOAT;
240 for(auto&& point : points)
242 Vector4 pointV = shadowCameraViewMatrix * point;
243 areaMin.x = std::min(areaMin.x, pointV.x);
244 areaMin.y = std::min(areaMin.y, pointV.y);
245 areaMin.z = std::min(areaMin.z, pointV.z);
246 areaMax.x = std::max(areaMax.x, pointV.x);
247 areaMax.y = std::max(areaMax.y, pointV.y);
248 areaMax.z = std::max(areaMax.z, pointV.z);
251 Vector2 center = Vector2(areaMax + areaMin) * 0.5;
252 float delta = std::max(std::abs(areaMax.x - areaMin.x), std::abs(areaMax.y - areaMin.y));
253 float delta_2 = delta * 0.5f;
254 Vector2 squareAreaMin = center - Vector2::ONE * delta_2;
255 Vector2 squareAreaMax = center + Vector2::ONE * delta_2;
256 float deltaZ = areaMax.z - areaMin.z;
258 float right = -squareAreaMin.x;
259 float left = -squareAreaMax.x;
260 float top = squareAreaMin.y;
261 float bottom = squareAreaMax.y;
262 float near = areaMin.z;
263 float far = areaMax.z;
265 float* projMatrix = output.AsFloat();
267 projMatrix[0] = -2.0f / delta;
268 projMatrix[1] = 0.0f;
269 projMatrix[2] = 0.0f;
270 projMatrix[3] = 0.0f;
272 projMatrix[4] = 0.0f;
273 projMatrix[5] = -2.0f / delta;
274 projMatrix[6] = 0.0f;
275 projMatrix[7] = 0.0f;
277 projMatrix[8] = 0.0f;
278 projMatrix[9] = 0.0f;
279 projMatrix[10] = 2.0f / deltaZ;
280 projMatrix[11] = 0.0f;
282 projMatrix[12] = -(right + left) / delta;
283 projMatrix[13] = -(top + bottom) / delta;
284 projMatrix[14] = -(near + far) / deltaZ;
285 projMatrix[15] = 1.0f;
287 output = output * shadowCameraViewMatrix;
289 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::Actor::Property::WORLD_MATRIX});
290 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::PROJECTION_MODE});
291 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::PROJECTION_DIRECTION});
292 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE});
293 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FIELD_OF_VIEW});
294 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::NEAR_PLANE_DISTANCE});
295 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FAR_PLANE_DISTANCE});
296 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::ASPECT_RATIO});
297 projectionMatrixConstraint.AddSource(Source{shadowLightCamera, Dali::Actor::Property::WORLD_MATRIX});
298 projectionMatrixConstraint.ApplyPost();
301 } // anonymous namespace
303 SceneView::SceneView()
304 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
305 mWindowOrientation(DEFAULT_ORIENTATION),
307 mSkyboxOrientation(Quaternion()),
308 mSkyboxIntensity(1.0f),
309 mShaderManager(new Scene3D::Loader::ShaderManager())
313 SceneView::~SceneView()
315 if(Dali::Adaptor::IsAvailable())
317 if(mIblDiffuseLoadTask)
319 Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
320 mIblDiffuseLoadTask.Reset();
322 if(mIblSpecularLoadTask)
324 Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
325 mIblSpecularLoadTask.Reset();
329 Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
330 mSkyboxLoadTask.Reset();
333 // Request image resource GC
334 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
338 Dali::Scene3D::SceneView SceneView::New()
340 SceneView* impl = new SceneView();
342 Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl);
344 // Second-phase init of the implementation
345 // This can only be done after the CustomActor connection has been made...
351 void SceneView::AddCamera(CameraActor camera)
357 UpdateCamera(camera);
359 mCameras.push_back(camera);
363 void SceneView::RemoveCamera(CameraActor camera)
365 if(camera == mDefaultCamera)
367 DALI_LOG_ERROR("Default Camera cannot removed.\n");
373 for(uint32_t i = 0; i < mCameras.size(); ++i)
375 if(mCameras[i] == camera)
377 mCameras.erase(mCameras.begin() + i);
382 if(mSelectedCamera == camera)
384 CameraActor newCurrentCamera = *mCameras.begin();
385 UpdateCamera(newCurrentCamera);
390 uint32_t SceneView::GetCameraCount() const
392 return mCameras.size();
395 CameraActor SceneView::GetSelectedCamera() const
397 return mSelectedCamera;
400 CameraActor SceneView::GetCamera(uint32_t index) const
402 if(index < mCameras.size())
404 return mCameras[index];
406 DALI_LOG_ERROR("Input index is out of bounds\n");
407 return CameraActor();
410 CameraActor SceneView::GetCamera(const std::string& name) const
412 CameraActor returnCamera;
413 for(auto&& camera : mCameras)
415 if(camera.GetProperty<std::string>(Actor::Property::NAME) == name)
417 returnCamera = camera;
424 void SceneView::SelectCamera(uint32_t index)
426 UpdateCamera(GetCamera(index));
429 void SceneView::SelectCamera(const std::string& name)
431 UpdateCamera(GetCamera(name));
434 void SceneView::RegisterSceneItem(Scene3D::Internal::LightObserver* item)
438 item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
439 item->NotifyShadowMapTexture(mShadowTexture);
440 mItems.push_back(item);
444 void SceneView::UnregisterSceneItem(Scene3D::Internal::LightObserver* item)
448 for(uint32_t i = 0; i < mItems.size(); ++i)
450 if(mItems[i] == item)
452 mItems.erase(mItems.begin() + i);
459 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
461 bool needIblReset = false;
462 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
463 if(mDiffuseIblUrl != diffuseUrl)
465 mDiffuseIblUrl = diffuseUrl;
466 if(mDiffuseIblUrl.empty())
472 mIblDiffuseDirty = true;
473 mIblDiffuseResourceReady = false;
477 if(mSpecularIblUrl != specularUrl)
479 mSpecularIblUrl = specularUrl;
480 if(mSpecularIblUrl.empty())
486 mIblSpecularDirty = true;
487 mIblSpecularResourceReady = false;
491 // If one or both of diffuse url and specular url are empty,
492 // we don't need to request to load texture.
495 if(mIblDiffuseLoadTask)
497 Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
498 mIblDiffuseLoadTask.Reset();
501 if(mIblSpecularLoadTask)
503 Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
504 mIblSpecularLoadTask.Reset();
507 mIblDiffuseDirty = false;
508 mIblSpecularDirty = false;
509 mIblDiffuseResourceReady = true;
510 mIblSpecularResourceReady = true;
512 mDiffuseTexture.Reset();
513 mSpecularTexture.Reset();
515 mSpecularMipmapLevels = 1u;
516 NotifyImageBasedLightTextureChange();
518 // Request image resource GC
519 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
523 if(isOnScene && mIblDiffuseDirty)
525 if(mIblDiffuseLoadTask)
527 Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
528 mIblDiffuseLoadTask.Reset();
530 // Request image resource GC
531 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
533 mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete));
534 Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
535 mIblDiffuseDirty = false;
538 if(isOnScene && mIblSpecularDirty)
540 if(mIblSpecularLoadTask)
542 Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
543 mIblSpecularLoadTask.Reset();
545 // Request image resource GC
546 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
548 mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete));
549 Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
550 mIblSpecularDirty = false;
554 if(!Dali::Equals(mIblScaleFactor, scaleFactor))
556 SetImageBasedLightScaleFactor(scaleFactor);
559 // If diffuse and specular textures are already loaded, emits resource ready signal here.
560 if(IsResourceReady())
562 Control::SetResourceReady();
566 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
568 mIblScaleFactor = scaleFactor;
569 for(auto&& item : mItems)
573 item->NotifyImageBasedLightScaleFactor(scaleFactor);
578 float SceneView::GetImageBasedLightScaleFactor() const
580 return mIblScaleFactor;
583 void SceneView::AddLight(Scene3D::Light light)
585 bool enabled = mShaderManager->AddLight(light);
586 mLights.push_back(std::make_pair(light, enabled));
588 if(light.IsShadowEnabled())
594 void SceneView::RemoveLight(Scene3D::Light light)
596 mShaderManager->RemoveLight(light);
597 for(uint32_t i = 0; i < mLights.size(); ++i)
599 if(mLights[i].first == light)
601 mLights.erase(mLights.begin() + i);
606 if(mLights.size() > mShaderManager->GetLightCount())
608 for(auto&& waitingLight : mLights)
610 if(waitingLight.second)
615 waitingLight.second = mShaderManager->AddLight(waitingLight.first);
620 if(light == mShadowLight)
627 for(auto&& lightEntity : mLights)
629 if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
633 SetShadow(lightEntity.first);
639 void SceneView::SetShadow(Scene3D::Light light)
646 auto foundLight = std::find_if(mLights.begin(), mLights.end(), [light](std::pair<Scene3D::Light, bool> lightEntity) -> bool { return (lightEntity.second && lightEntity.first == light); });
648 if(foundLight == mLights.end())
653 mShadowLight = light;
655 // Directional Light setting.
656 CameraActor lightCamera = GetImplementation(light).GetCamera();
657 CameraActor selectedCamera = GetSelectedCamera();
658 SetShadowLightConstraint(selectedCamera, lightCamera);
660 // make framebuffer for depth map and set it to render task.
661 uint32_t shadowMapBufferSize = std::min(std::max(GetResolutionWidth(), GetResolutionHeight()), MAXIMUM_SIZE_SHADOW_MAP);
662 UpdateShadowMapBuffer(shadowMapBufferSize);
664 // use lightCamera as a camera of shadow render task.
665 if(mShadowMapRenderTask)
667 mShadowMapRenderTask.SetCameraActor(lightCamera);
670 mShaderManager->SetShadow(light);
671 UpdateShadowMapBuffer(shadowMapBufferSize);
674 void SceneView::RemoveShadow(Scene3D::Light light)
676 if(mShadowLight != light)
681 // remove all constraint from light camera
682 CameraActor lightCamera = GetImplementation(mShadowLight).GetCamera();
683 lightCamera.RemoveConstraints();
685 // reset framebuffer and remove it from render task.
686 mShadowFrameBuffer.Reset();
687 mShaderManager->RemoveShadow();
688 if(mShadowMapRenderTask)
690 mShadowMapRenderTask.SetCameraActor(CameraActor());
693 mShadowLight.Reset();
695 mShadowTexture.Reset();
696 for(auto&& item : mItems)
700 item->NotifyShadowMapTexture(mShadowTexture);
704 for(auto&& lightEntity : mLights)
706 if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
710 SetShadow(lightEntity.first);
714 if(mShadowMapRenderTask)
716 RenderTaskList taskList = Integration::SceneHolder::Get(Self()).GetRenderTaskList();
717 taskList.RemoveTask(mShadowMapRenderTask);
718 mShadowMapRenderTask.Reset();
722 uint32_t SceneView::GetActivatedLightCount() const
724 return mShaderManager->GetLightCount();
727 void SceneView::UseFramebuffer(bool useFramebuffer)
729 if(mUseFrameBuffer != useFramebuffer)
731 mUseFrameBuffer = useFramebuffer;
736 bool SceneView::IsUsingFramebuffer() const
738 return mUseFrameBuffer;
741 void SceneView::SetResolution(uint32_t width, uint32_t height)
743 if(mWindowWidth != width || mWindowHeight != height)
745 mWindowWidth = width;
746 mWindowHeight = height;
749 mWindowSizeChanged = true;
755 uint32_t SceneView::GetResolutionWidth()
757 if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
759 return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_WIDTH));
764 uint32_t SceneView::GetResolutionHeight()
766 if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
768 return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_HEIGHT));
770 return mWindowHeight;
773 void SceneView::ResetResolution()
775 SetResolution(0u, 0u);
778 void SceneView::SetFramebufferMultiSamplingLevel(uint8_t multiSamplingLevel)
780 if(mFrameBufferMultiSamplingLevel != multiSamplingLevel)
782 mFrameBufferMultiSamplingLevel = multiSamplingLevel;
784 // Create new framebuffer with changed multiSamplingLevel.
785 if(mRenderTask && mFrameBuffer && mTexture)
787 mFrameBuffer = FrameBuffer::New(GetResolutionWidth(), GetResolutionHeight(), FrameBuffer::Attachment::DEPTH_STENCIL);
788 mFrameBuffer.AttachColorTexture(mTexture);
789 DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
790 mRenderTask.SetFrameBuffer(mFrameBuffer);
792 // Note : we don't need to create new visual since visual's url is depend on mTexture.
797 uint8_t SceneView::GetFramebufferMultiSamplingLevel() const
799 return mFrameBufferMultiSamplingLevel;
802 void SceneView::SetSkybox(const std::string& skyboxUrl)
804 if(mSkyboxUrl != skyboxUrl)
806 UpdateSkybox(skyboxUrl, mSkyboxEnvironmentMapType);
810 void SceneView::SetSkyboxEnvironmentMapType(Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
812 if(mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
814 UpdateSkybox(mSkyboxUrl, skyboxEnvironmentMapType);
818 void SceneView::SetSkyboxIntensity(float intensity)
820 mSkyboxIntensity = intensity;
823 DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
824 mSkyboxIntensity = 0.0f;
829 mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
833 float SceneView::GetSkyboxIntensity() const
835 return mSkyboxIntensity;
838 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
840 mSkyboxOrientation = orientation;
843 mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
847 Quaternion SceneView::GetSkyboxOrientation() const
849 return mSkyboxOrientation;
852 Dali::Scene3D::Loader::ShaderManagerPtr SceneView::GetShaderManager() const
854 return mShaderManager;
857 void SceneView::UpdateShadowUniform(Scene3D::Light light)
859 mShaderManager->UpdateShadowUniform(light);
862 void SceneView::SetAlphaMaskUrl(std::string& alphaMaskUrl)
864 if(mAlphaMaskUrl != alphaMaskUrl)
866 mAlphaMaskUrl = alphaMaskUrl;
867 mMaskingPropertyChanged = true;
872 std::string SceneView::GetAlphaMaskUrl()
874 return mAlphaMaskUrl;
877 void SceneView::SetMaskContentScaleFactor(float maskContentScaleFactor)
879 if(mMaskContentScaleFactor != maskContentScaleFactor)
881 mMaskContentScaleFactor = maskContentScaleFactor;
882 mMaskingPropertyChanged = true;
887 float SceneView::GetMaskContentScaleFactor()
889 return mMaskContentScaleFactor;
892 void SceneView::EnableCropToMask(bool enableCropToMask)
894 if(mCropToMask != enableCropToMask)
896 mCropToMask = enableCropToMask;
897 mMaskingPropertyChanged = true;
902 bool SceneView::IsEnabledCropToMask()
907 void SceneView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
909 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
913 SceneView& sceneViewImpl(GetImpl(sceneView));
917 case Scene3D::SceneView::Property::ALPHA_MASK_URL:
919 std::string alphaMaskUrl = value.Get<std::string>();
920 sceneViewImpl.SetAlphaMaskUrl(alphaMaskUrl);
923 case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
925 sceneViewImpl.SetMaskContentScaleFactor(value.Get<float>());
928 case Scene3D::SceneView::Property::CROP_TO_MASK:
930 sceneViewImpl.EnableCropToMask(value.Get<bool>());
937 Property::Value SceneView::GetProperty(BaseObject* object, Property::Index index)
939 Property::Value value;
941 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
945 SceneView& sceneViewImpl(GetImpl(sceneView));
949 case Scene3D::SceneView::Property::ALPHA_MASK_URL:
951 value = sceneViewImpl.GetAlphaMaskUrl();
954 case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
956 value = sceneViewImpl.GetMaskContentScaleFactor();
959 case Scene3D::SceneView::Property::CROP_TO_MASK:
961 value = sceneViewImpl.IsEnabledCropToMask();
969 ///////////////////////////////////////////////////////////
974 void SceneView::OnSceneConnection(int depth)
976 // If diffuse and specular url is not valid, IBL does not need to be loaded.
977 if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
979 SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
982 if(!mSkyboxUrl.empty())
984 UpdateSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType);
987 Window window = DevelWindow::Get(Self());
990 // Only for on-screen window
991 window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
994 mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
997 // On-screen / Off-screen window
998 mSceneHolder = Integration::SceneHolder::Get(Self());
1001 RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1002 mRenderTask = taskList.CreateTask();
1003 mRenderTask.SetSourceActor(mRootLayer);
1004 mRenderTask.SetExclusive(true);
1005 mRenderTask.SetInputEnabled(true);
1006 mRenderTask.SetCullMode(false);
1007 mRenderTask.SetOrderIndex(SCENE_ORDER_INDEX);
1008 mRenderTask.SetScreenToFrameBufferMappingActor(Self());
1013 Control::OnSceneConnection(depth);
1016 void SceneView::OnSceneDisconnection()
1020 Window window = mWindow.GetHandle();
1023 window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
1031 RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1032 taskList.RemoveTask(mRenderTask);
1033 mRenderTask.Reset();
1035 if(mShadowMapRenderTask)
1037 RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1038 taskList.RemoveTask(mShadowMapRenderTask);
1039 mShadowMapRenderTask.Reset();
1041 mSceneHolder.Reset();
1043 mFrameBuffer.Reset();
1044 mShadowFrameBuffer.Reset();
1046 Control::OnSceneDisconnection();
1049 void SceneView::OnInitialize()
1051 Actor self = Self();
1052 mRootLayer = Layer::New();
1053 mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
1054 mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
1055 // The models in the SceneView should be have independent coordinate with DALi default coordinate.
1056 mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
1057 mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
1058 mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
1059 self.Add(mRootLayer);
1061 mDefaultCamera = Dali::CameraActor::New3DCamera();
1062 mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
1063 mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
1064 AddCamera(mDefaultCamera);
1065 UpdateCamera(mDefaultCamera);
1068 void SceneView::OnChildAdd(Actor& child)
1070 if(child != mRootLayer)
1072 mRootLayer.Add(child);
1074 Control::OnChildAdd(child);
1077 void SceneView::OnChildRemove(Actor& child)
1079 mRootLayer.Remove(child);
1080 Control::OnChildRemove(child);
1083 float SceneView::GetHeightForWidth(float width)
1086 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1087 return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
1090 float SceneView::GetWidthForHeight(float height)
1093 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1094 return Control::GetWidthForHeight(height) + padding.start + padding.end;
1097 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
1099 Control::OnRelayout(size, container);
1100 // Change canvas size of camera actor.
1104 bool SceneView::IsResourceReady() const
1106 return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady;
1109 void SceneView::UpdateCamera(CameraActor camera)
1113 if(mSelectedCamera && mSelectedCamera.GetParent())
1115 mSelectedCamera.Unparent();
1117 mRootLayer.Add(camera);
1120 mSelectedCamera = camera;
1123 SetShadowLightConstraint(mSelectedCamera, GetImplementation(mShadowLight).GetCamera());
1128 void SceneView::UpdateRenderTask()
1132 if(mSelectedCamera != mRenderTask.GetCameraActor())
1134 mRenderTask.SetCameraActor(mSelectedCamera);
1136 uint32_t width = GetResolutionWidth();
1137 uint32_t height = GetResolutionHeight();
1139 uint32_t shadowMapBufferSize = std::min(std::max(width, height), MAXIMUM_SIZE_SHADOW_MAP);
1140 UpdateShadowMapBuffer(shadowMapBufferSize);
1144 Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
1145 if(!currentFrameBuffer ||
1146 !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), width) ||
1147 !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), height) ||
1148 mMaskingPropertyChanged ||
1151 mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR);
1152 mRenderTask.ResetViewportGuideActor();
1153 mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
1155 // create offscreen buffer of new size to render our child actors to
1156 mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
1157 mFrameBuffer = FrameBuffer::New(width, height, FrameBuffer::Attachment::DEPTH_STENCIL);
1158 mFrameBuffer.AttachColorTexture(mTexture);
1159 DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
1160 Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
1162 Property::Map imagePropertyMap;
1163 imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
1164 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
1165 // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
1166 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
1167 if(!mAlphaMaskUrl.empty())
1169 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mAlphaMaskUrl);
1170 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, true);
1171 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskContentScaleFactor);
1172 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mCropToMask);
1173 imagePropertyMap.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, Toolkit::DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
1174 Self().RegisterProperty(Y_FLIP_MASK_TEXTURE, FLIP_MASK_TEXTURE);
1177 mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
1178 Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
1180 mRenderTask.SetFrameBuffer(mFrameBuffer);
1181 mRenderTask.SetClearEnabled(true);
1182 mRenderTask.SetClearColor(Color::TRANSPARENT);
1184 mMaskingPropertyChanged = false;
1185 mWindowSizeChanged = false;
1190 mRenderTask.SetViewportGuideActor(Self());
1191 if(mRenderTask.GetFrameBuffer())
1193 mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA);
1194 FrameBuffer framebuffer;
1195 mRenderTask.SetFrameBuffer(framebuffer);
1196 mRenderTask.SetClearEnabled(false);
1198 Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
1201 mFrameBuffer.Reset();
1206 if(width > 0u && height > 0u)
1208 float aspectRatio = static_cast<float>(width) / static_cast<float>(height);
1209 mSelectedCamera.SetAspectRatio(aspectRatio);
1216 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
1218 mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
1222 void SceneView::RotateCamera()
1226 DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
1230 DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
1234 void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
1236 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
1237 if(mSkyboxUrl != skyboxUrl || mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
1239 mSkyboxDirty = true;
1240 mSkyboxResourceReady = false;
1241 mSkyboxUrl = skyboxUrl;
1242 mSkyboxEnvironmentMapType = skyboxEnvironmentMapType;
1245 if(mSkyboxUrl.empty())
1249 Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1250 mSkyboxLoadTask.Reset();
1257 mSkyboxTexture.Reset();
1260 mSkyboxDirty = false;
1261 mSkyboxResourceReady = true;
1263 // Request image resource GC
1264 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
1268 if(isOnScene && mSkyboxDirty)
1272 Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1273 mSkyboxLoadTask.Reset();
1275 // Request image resource GC
1276 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
1279 mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, mSkyboxEnvironmentMapType, MakeCallback(this, &SceneView::OnSkyboxLoadComplete));
1280 Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask);
1281 mSkyboxDirty = false;
1285 if(IsResourceReady())
1287 Control::SetResourceReady();
1291 void SceneView::OnSkyboxLoadComplete()
1295 mSkybox = CreateSkybox();
1296 SetSkyboxIntensity(mSkyboxIntensity);
1297 SetSkyboxOrientation(mSkyboxOrientation);
1300 mRootLayer.Add(mSkybox);
1304 mSkyboxResourceReady = true;
1305 mSkyboxTexture = mSkyboxLoadTask->GetLoadedTexture();
1306 Shader skyboxShader;
1307 if(mSkyboxLoadTask->GetEnvironmentMapType() == Scene3D::EnvironmentMapType::CUBEMAP)
1309 skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_CUBE");
1313 skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data(), Shader::Hint::NONE, "SCENE3D_SKYBOX_EQUIRECTANGULAR");
1316 Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer();
1319 Dali::TextureSet skyboxTextures = TextureSet::New();
1320 skyboxTextures.SetTexture(0, mSkyboxTexture);
1321 skyboxRenderer.SetTextures(skyboxTextures);
1322 skyboxRenderer.SetShader(skyboxShader);
1325 mSkyboxLoadTask.Reset();
1327 if(IsResourceReady())
1329 Control::SetResourceReady();
1333 void SceneView::OnIblDiffuseLoadComplete()
1335 mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
1336 mIblDiffuseResourceReady = true;
1337 mIblDiffuseLoadTask.Reset();
1338 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1340 OnIblLoadComplete();
1344 void SceneView::OnIblSpecularLoadComplete()
1346 mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
1347 mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
1348 mIblSpecularResourceReady = true;
1349 mIblSpecularLoadTask.Reset();
1350 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1352 OnIblLoadComplete();
1356 void SceneView::OnIblLoadComplete()
1358 NotifyImageBasedLightTextureChange();
1359 if(IsResourceReady())
1361 Control::SetResourceReady();
1365 void SceneView::NotifyImageBasedLightTextureChange()
1367 for(auto&& item : mItems)
1371 item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
1376 void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize)
1383 if(!mShadowMapRenderTask)
1385 RenderTaskList taskList = Integration::SceneHolder::Get(Self()).GetRenderTaskList();
1386 mShadowMapRenderTask = taskList.CreateTask();
1387 mShadowMapRenderTask.SetSourceActor(mRootLayer);
1388 mShadowMapRenderTask.SetExclusive(true);
1389 mShadowMapRenderTask.SetInputEnabled(false);
1390 mShadowMapRenderTask.SetCullMode(false);
1391 mShadowMapRenderTask.SetClearEnabled(true);
1392 mShadowMapRenderTask.SetClearColor(Color::WHITE);
1393 mShadowMapRenderTask.SetRenderPassTag(10);
1394 mShadowMapRenderTask.SetCameraActor(GetImplementation(mShadowLight).GetCamera());
1395 mShadowMapRenderTask.SetOrderIndex(SHADOW_ORDER_INDEX);
1398 Dali::FrameBuffer currentShadowFrameBuffer = mShadowMapRenderTask.GetFrameBuffer();
1399 if(!currentShadowFrameBuffer ||
1401 !Dali::Equals(DevelFrameBuffer::GetDepthTexture(currentShadowFrameBuffer).GetWidth(), shadowMapSize))
1403 mShadowFrameBuffer.Reset();
1404 mShadowTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::DEPTH_UNSIGNED_INT, shadowMapSize, shadowMapSize);
1405 mShadowFrameBuffer = FrameBuffer::New(shadowMapSize, shadowMapSize, FrameBuffer::Attachment::NONE);
1406 DevelFrameBuffer::AttachDepthTexture(mShadowFrameBuffer, mShadowTexture);
1407 mShadowMapRenderTask.SetFrameBuffer(mShadowFrameBuffer);
1409 for(auto&& item : mItems)
1413 item->NotifyShadowMapTexture(mShadowTexture);
1419 } // namespace Internal
1420 } // namespace Scene3D