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 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
76 static constexpr std::string_view Y_FLIP_MASK_TEXTURE = "uYFlipMaskTexture";
77 static constexpr float FLIP_MASK_TEXTURE = 1.0f;
79 Dali::Actor CreateSkybox()
86 Vertex skyboxVertices[] = {
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)},
93 {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)},
101 {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)},
109 {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)},
117 {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)},
125 {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)},
133 {Vector3(1.0f, -1.0f, 1.0f)}};
135 Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3));
136 vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
138 Dali::Geometry skyboxGeometry = Geometry::New();
139 skyboxGeometry.AddVertexBuffer(vertexBuffer);
140 skyboxGeometry.SetType(Geometry::TRIANGLES);
142 Dali::Shader shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
143 Dali::Renderer skyboxRenderer;
144 skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
145 skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
146 // Enables the depth test.
147 skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
148 // The fragment shader will run only is those pixels that have the max depth value.
149 skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
151 Dali::Actor skyboxActor = Actor::New();
152 skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
153 skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
154 skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
155 skyboxActor.AddRenderer(skyboxRenderer);
159 void SetShadowLightConstraint(Dali::CameraActor selectedCamera, Dali::CameraActor shadowLightCamera)
161 shadowLightCamera.SetProperty(Dali::CameraActor::Property::ASPECT_RATIO, 1.0f);
162 shadowLightCamera.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, 1.0f);
163 shadowLightCamera.SetProperty(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE, 0.5f);
164 shadowLightCamera.SetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE, 3.5f);
166 //< Make constraint for above properties.
167 shadowLightCamera.RemoveConstraints();
169 // Compute ViewProjectionMatrix and store it to "tempViewProjectionMatrix" property
170 auto tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY);
171 Constraint projectionMatrixConstraint = Constraint::New<Matrix>(shadowLightCamera, tempViewProjectionMatrixIndex, [](Matrix& output, const PropertyInputContainer& inputs) {
172 Matrix worldMatrix = inputs[0]->GetMatrix();
173 float tangentFov_2 = tanf(inputs[4]->GetFloat());
174 float nearDistance = inputs[5]->GetFloat();
175 float farDistance = inputs[6]->GetFloat();
176 float aspectRatio = inputs[7]->GetFloat();
181 if(inputs[1]->GetInteger() == Dali::Camera::ProjectionMode::PERSPECTIVE_PROJECTION)
183 if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
185 nearY = tangentFov_2 * nearDistance;
186 nearX = nearY * aspectRatio;
187 farY = tangentFov_2 * farDistance;
188 farX = farY * aspectRatio;
192 nearX = tangentFov_2 * nearDistance;
193 nearY = nearX / aspectRatio;
194 farX = tangentFov_2 * farDistance;
195 farY = farX / aspectRatio;
200 if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
202 nearY = inputs[3]->GetFloat();
203 nearX = nearY * aspectRatio;
207 nearX = inputs[3]->GetFloat();
208 nearY = nearX / aspectRatio;
214 std::vector<Vector4> points;
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(nearX, -nearY, nearDistance, 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));
222 points.push_back(Vector4(farX, -farY, farDistance, 1.0f));
224 Matrix shadowCameraWorldMatrix = inputs[8]->GetMatrix();
226 for(auto&& point : points)
228 point = worldMatrix * point;
229 worldCenter += point;
232 shadowCameraWorldMatrix.SetTranslation(Vector3(worldCenter));
233 Matrix shadowCameraViewMatrix = shadowCameraWorldMatrix;
234 shadowCameraViewMatrix.Invert();
236 Vector3 areaMin = Vector3::ONE * MAXFLOAT, areaMax = Vector3::ONE * -MAXFLOAT;
237 for(auto&& point : points)
239 Vector4 pointV = shadowCameraViewMatrix * point;
240 areaMin.x = std::min(areaMin.x, pointV.x);
241 areaMin.y = std::min(areaMin.y, pointV.y);
242 areaMin.z = std::min(areaMin.z, pointV.z);
243 areaMax.x = std::max(areaMax.x, pointV.x);
244 areaMax.y = std::max(areaMax.y, pointV.y);
245 areaMax.z = std::max(areaMax.z, pointV.z);
248 Vector2 center = Vector2(areaMax + areaMin) * 0.5;
249 float delta = std::max(std::abs(areaMax.x - areaMin.x), std::abs(areaMax.y - areaMin.y));
250 float delta_2 = delta * 0.5f;
251 Vector2 squareAreaMin = center - Vector2::ONE * delta_2;
252 Vector2 squareAreaMax = center + Vector2::ONE * delta_2;
253 float deltaZ = areaMax.z - areaMin.z;
255 float right = -squareAreaMin.x;
256 float left = -squareAreaMax.x;
257 float top = squareAreaMin.y;
258 float bottom = squareAreaMax.y;
259 float near = areaMin.z;
260 float far = areaMax.z;
262 float* projMatrix = output.AsFloat();
264 projMatrix[0] = -2.0f / delta;
265 projMatrix[1] = 0.0f;
266 projMatrix[2] = 0.0f;
267 projMatrix[3] = 0.0f;
269 projMatrix[4] = 0.0f;
270 projMatrix[5] = -2.0f / delta;
271 projMatrix[6] = 0.0f;
272 projMatrix[7] = 0.0f;
274 projMatrix[8] = 0.0f;
275 projMatrix[9] = 0.0f;
276 projMatrix[10] = 2.0f / deltaZ;
277 projMatrix[11] = 0.0f;
279 projMatrix[12] = -(right + left) / delta;
280 projMatrix[13] = -(top + bottom) / delta;
281 projMatrix[14] = -(near + far) / deltaZ;
282 projMatrix[15] = 1.0f;
284 output = output * shadowCameraViewMatrix;
286 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::Actor::Property::WORLD_MATRIX});
287 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::PROJECTION_MODE});
288 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::PROJECTION_DIRECTION});
289 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE});
290 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FIELD_OF_VIEW});
291 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::NEAR_PLANE_DISTANCE});
292 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FAR_PLANE_DISTANCE});
293 projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::ASPECT_RATIO});
294 projectionMatrixConstraint.AddSource(Source{shadowLightCamera, Dali::Actor::Property::WORLD_MATRIX});
295 projectionMatrixConstraint.ApplyPost();
298 } // anonymous namespace
300 SceneView::SceneView()
301 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
302 mWindowOrientation(DEFAULT_ORIENTATION),
304 mSkyboxOrientation(Quaternion()),
305 mSkyboxIntensity(1.0f),
306 mShaderManager(new Scene3D::Loader::ShaderManager())
310 SceneView::~SceneView()
312 if(Dali::Adaptor::IsAvailable())
314 if(mIblDiffuseLoadTask)
316 Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
317 mIblDiffuseLoadTask.Reset();
319 if(mIblSpecularLoadTask)
321 Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
322 mIblSpecularLoadTask.Reset();
326 Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
327 mSkyboxLoadTask.Reset();
330 // Request image resource GC
331 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
335 Dali::Scene3D::SceneView SceneView::New()
337 SceneView* impl = new SceneView();
339 Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl);
341 // Second-phase init of the implementation
342 // This can only be done after the CustomActor connection has been made...
348 void SceneView::AddCamera(CameraActor camera)
354 UpdateCamera(camera);
356 mCameras.push_back(camera);
360 void SceneView::RemoveCamera(CameraActor camera)
362 if(camera == mDefaultCamera)
364 DALI_LOG_ERROR("Default Camera cannot removed.\n");
370 for(uint32_t i = 0; i < mCameras.size(); ++i)
372 if(mCameras[i] == camera)
374 mCameras.erase(mCameras.begin() + i);
379 if(mSelectedCamera == camera)
381 CameraActor newCurrentCamera = *mCameras.begin();
382 UpdateCamera(newCurrentCamera);
387 uint32_t SceneView::GetCameraCount() const
389 return mCameras.size();
392 CameraActor SceneView::GetSelectedCamera() const
394 return mSelectedCamera;
397 CameraActor SceneView::GetCamera(uint32_t index) const
399 if(index < mCameras.size())
401 return mCameras[index];
403 DALI_LOG_ERROR("Input index is out of bounds\n");
404 return CameraActor();
407 CameraActor SceneView::GetCamera(const std::string& name) const
409 CameraActor returnCamera;
410 for(auto&& camera : mCameras)
412 if(camera.GetProperty<std::string>(Actor::Property::NAME) == name)
414 returnCamera = camera;
421 void SceneView::SelectCamera(uint32_t index)
423 UpdateCamera(GetCamera(index));
426 void SceneView::SelectCamera(const std::string& name)
428 UpdateCamera(GetCamera(name));
431 void SceneView::RegisterSceneItem(Scene3D::Internal::LightObserver* item)
435 item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
436 item->NotifyShadowMapTexture(mShadowTexture);
437 mItems.push_back(item);
441 void SceneView::UnregisterSceneItem(Scene3D::Internal::LightObserver* item)
445 for(uint32_t i = 0; i < mItems.size(); ++i)
447 if(mItems[i] == item)
449 mItems.erase(mItems.begin() + i);
456 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
458 bool needIblReset = false;
459 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
460 if(mDiffuseIblUrl != diffuseUrl)
462 mDiffuseIblUrl = diffuseUrl;
463 if(mDiffuseIblUrl.empty())
469 mIblDiffuseDirty = true;
470 mIblDiffuseResourceReady = false;
474 if(mSpecularIblUrl != specularUrl)
476 mSpecularIblUrl = specularUrl;
477 if(mSpecularIblUrl.empty())
483 mIblSpecularDirty = true;
484 mIblSpecularResourceReady = false;
488 // If one or both of diffuse url and specular url are empty,
489 // we don't need to request to load texture.
492 if(mIblDiffuseLoadTask)
494 Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
495 mIblDiffuseLoadTask.Reset();
498 if(mIblSpecularLoadTask)
500 Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
501 mIblSpecularLoadTask.Reset();
504 mIblDiffuseDirty = false;
505 mIblSpecularDirty = false;
506 mIblDiffuseResourceReady = true;
507 mIblSpecularResourceReady = true;
509 mDiffuseTexture.Reset();
510 mSpecularTexture.Reset();
512 mSpecularMipmapLevels = 1u;
513 NotifyImageBasedLightTextureChange();
515 // Request image resource GC
516 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
520 if(isOnScene && mIblDiffuseDirty)
522 if(mIblDiffuseLoadTask)
524 Dali::AsyncTaskManager::Get().RemoveTask(mIblDiffuseLoadTask);
525 mIblDiffuseLoadTask.Reset();
527 // Request image resource GC
528 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
530 mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblDiffuseLoadComplete));
531 Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
532 mIblDiffuseDirty = false;
535 if(isOnScene && mIblSpecularDirty)
537 if(mIblSpecularLoadTask)
539 Dali::AsyncTaskManager::Get().RemoveTask(mIblSpecularLoadTask);
540 mIblSpecularLoadTask.Reset();
542 // Request image resource GC
543 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
545 mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &SceneView::OnIblSpecularLoadComplete));
546 Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
547 mIblSpecularDirty = false;
551 if(!Dali::Equals(mIblScaleFactor, scaleFactor))
553 SetImageBasedLightScaleFactor(scaleFactor);
556 // If diffuse and specular textures are already loaded, emits resource ready signal here.
557 if(IsResourceReady())
559 Control::SetResourceReady();
563 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
565 mIblScaleFactor = scaleFactor;
566 for(auto&& item : mItems)
570 item->NotifyImageBasedLightScaleFactor(scaleFactor);
575 float SceneView::GetImageBasedLightScaleFactor() const
577 return mIblScaleFactor;
580 void SceneView::AddLight(Scene3D::Light light)
582 bool enabled = mShaderManager->AddLight(light);
583 mLights.push_back(std::make_pair(light, enabled));
585 if(light.IsShadowEnabled())
591 void SceneView::RemoveLight(Scene3D::Light light)
593 mShaderManager->RemoveLight(light);
594 for(uint32_t i = 0; i < mLights.size(); ++i)
596 if(mLights[i].first == light)
598 mLights.erase(mLights.begin() + i);
603 if(mLights.size() > mShaderManager->GetLightCount())
605 for(auto&& waitingLight : mLights)
607 if(waitingLight.second)
612 waitingLight.second = mShaderManager->AddLight(waitingLight.first);
617 if(light == mShadowLight)
624 for(auto&& lightEntity : mLights)
626 if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
630 SetShadow(lightEntity.first);
636 void SceneView::SetShadow(Scene3D::Light light)
643 auto foundLight = std::find_if(mLights.begin(), mLights.end(), [light](std::pair<Scene3D::Light, bool> lightEntity) -> bool { return (lightEntity.second && lightEntity.first == light); });
645 if(foundLight == mLights.end())
650 mShadowLight = light;
652 // Directional Light setting.
653 CameraActor lightCamera = GetImplementation(light).GetCamera();
654 CameraActor selectedCamera = GetSelectedCamera();
655 SetShadowLightConstraint(selectedCamera, lightCamera);
657 // make framebuffer for depth map and set it to render task.
658 uint32_t shadowMapBufferSize = std::min(std::max(GetResolutionWidth(), GetResolutionHeight()), MAXIMUM_SIZE_SHADOW_MAP);
659 UpdateShadowMapBuffer(shadowMapBufferSize);
661 // use lightCamera as a camera of shadow render task.
662 mShadowMapRenderTask.SetCameraActor(lightCamera);
664 mShaderManager->SetShadow(light);
667 void SceneView::RemoveShadow(Scene3D::Light light)
669 if(mShadowLight != light)
674 // remove all constraint from light camera
675 CameraActor lightCamera = GetImplementation(mShadowLight).GetCamera();
676 lightCamera.RemoveConstraints();
678 // reset framebuffer and remove it from render task.
679 mShadowFrameBuffer.Reset();
680 mShaderManager->RemoveShadow();
681 mShadowMapRenderTask.SetCameraActor(CameraActor());
683 mShadowLight.Reset();
685 mShadowTexture.Reset();
686 for(auto&& item : mItems)
690 item->NotifyShadowMapTexture(mShadowTexture);
694 for(auto&& lightEntity : mLights)
696 if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
700 SetShadow(lightEntity.first);
705 uint32_t SceneView::GetActivatedLightCount() const
707 return mShaderManager->GetLightCount();
710 void SceneView::UseFramebuffer(bool useFramebuffer)
712 if(mUseFrameBuffer != useFramebuffer)
714 mUseFrameBuffer = useFramebuffer;
719 bool SceneView::IsUsingFramebuffer() const
721 return mUseFrameBuffer;
724 void SceneView::SetResolution(uint32_t width, uint32_t height)
726 if(mWindowWidth != width || mWindowHeight != height)
728 mWindowWidth = width;
729 mWindowHeight = height;
732 mWindowSizeChanged = true;
738 uint32_t SceneView::GetResolutionWidth()
740 if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
742 return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_WIDTH));
747 uint32_t SceneView::GetResolutionHeight()
749 if(!mUseFrameBuffer || mWindowWidth == 0u || mWindowHeight == 0u)
751 return static_cast<uint32_t>(Self().GetProperty<float>(Dali::Actor::Property::SIZE_HEIGHT));
753 return mWindowHeight;
756 void SceneView::ResetResolution()
758 SetResolution(0u, 0u);
761 void SceneView::SetFramebufferMultiSamplingLevel(uint8_t multiSamplingLevel)
763 if(mFrameBufferMultiSamplingLevel != multiSamplingLevel)
765 mFrameBufferMultiSamplingLevel = multiSamplingLevel;
767 // Create new framebuffer with changed multiSamplingLevel.
768 if(mRenderTask && mFrameBuffer && mTexture)
770 mFrameBuffer = FrameBuffer::New(GetResolutionWidth(), GetResolutionHeight(), FrameBuffer::Attachment::DEPTH_STENCIL);
771 mFrameBuffer.AttachColorTexture(mTexture);
772 DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
773 mRenderTask.SetFrameBuffer(mFrameBuffer);
775 // Note : we don't need to create new visual since visual's url is depend on mTexture.
780 uint8_t SceneView::GetFramebufferMultiSamplingLevel() const
782 return mFrameBufferMultiSamplingLevel;
785 void SceneView::SetSkybox(const std::string& skyboxUrl)
787 if(mSkyboxUrl != skyboxUrl)
789 UpdateSkybox(skyboxUrl, mSkyboxEnvironmentMapType);
793 void SceneView::SetSkyboxEnvironmentMapType(Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
795 if(mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
797 UpdateSkybox(mSkyboxUrl, skyboxEnvironmentMapType);
801 void SceneView::SetSkyboxIntensity(float intensity)
803 mSkyboxIntensity = intensity;
806 DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
807 mSkyboxIntensity = 0.0f;
812 mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
816 float SceneView::GetSkyboxIntensity() const
818 return mSkyboxIntensity;
821 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
823 mSkyboxOrientation = orientation;
826 mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
830 Quaternion SceneView::GetSkyboxOrientation() const
832 return mSkyboxOrientation;
835 Dali::Scene3D::Loader::ShaderManagerPtr SceneView::GetShaderManager() const
837 return mShaderManager;
840 void SceneView::UpdateShadowUniform(Scene3D::Light light)
842 mShaderManager->UpdateShadowUniform(light);
845 void SceneView::SetAlphaMaskUrl(std::string& alphaMaskUrl)
847 if(mAlphaMaskUrl != alphaMaskUrl)
849 mAlphaMaskUrl = alphaMaskUrl;
850 mMaskingPropertyChanged = true;
855 std::string SceneView::GetAlphaMaskUrl()
857 return mAlphaMaskUrl;
860 void SceneView::SetMaskContentScaleFactor(float maskContentScaleFactor)
862 if(mMaskContentScaleFactor != maskContentScaleFactor)
864 mMaskContentScaleFactor = maskContentScaleFactor;
865 mMaskingPropertyChanged = true;
870 float SceneView::GetMaskContentScaleFactor()
872 return mMaskContentScaleFactor;
875 void SceneView::EnableCropToMask(bool enableCropToMask)
877 if(mCropToMask != enableCropToMask)
879 mCropToMask = enableCropToMask;
880 mMaskingPropertyChanged = true;
885 bool SceneView::IsEnabledCropToMask()
890 void SceneView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
892 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
896 SceneView& sceneViewImpl(GetImpl(sceneView));
900 case Scene3D::SceneView::Property::ALPHA_MASK_URL:
902 std::string alphaMaskUrl = value.Get<std::string>();
903 sceneViewImpl.SetAlphaMaskUrl(alphaMaskUrl);
906 case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
908 sceneViewImpl.SetMaskContentScaleFactor(value.Get<float>());
911 case Scene3D::SceneView::Property::CROP_TO_MASK:
913 sceneViewImpl.EnableCropToMask(value.Get<bool>());
920 Property::Value SceneView::GetProperty(BaseObject* object, Property::Index index)
922 Property::Value value;
924 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(Dali::BaseHandle(object));
928 SceneView& sceneViewImpl(GetImpl(sceneView));
932 case Scene3D::SceneView::Property::ALPHA_MASK_URL:
934 value = sceneViewImpl.GetAlphaMaskUrl();
937 case Scene3D::SceneView::Property::MASK_CONTENT_SCALE:
939 value = sceneViewImpl.GetMaskContentScaleFactor();
942 case Scene3D::SceneView::Property::CROP_TO_MASK:
944 value = sceneViewImpl.IsEnabledCropToMask();
952 ///////////////////////////////////////////////////////////
957 void SceneView::OnSceneConnection(int depth)
959 // If diffuse and specular url is not valid, IBL does not need to be loaded.
960 if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
962 SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
965 if(!mSkyboxUrl.empty())
967 UpdateSkybox(mSkyboxUrl, mSkyboxEnvironmentMapType);
970 Window window = DevelWindow::Get(Self());
973 // Only for on-screen window
974 window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
977 mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
980 // On-screen / Off-screen window
981 mSceneHolder = Integration::SceneHolder::Get(Self());
984 RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
985 mShadowMapRenderTask = taskList.CreateTask();
986 mShadowMapRenderTask.SetSourceActor(mRootLayer);
987 mShadowMapRenderTask.SetExclusive(true);
988 mShadowMapRenderTask.SetInputEnabled(false);
989 mShadowMapRenderTask.SetCullMode(false);
990 mShadowMapRenderTask.SetClearEnabled(true);
991 mShadowMapRenderTask.SetClearColor(Color::WHITE);
992 mShadowMapRenderTask.SetRenderPassTag(10);
993 mShadowMapRenderTask.SetCameraActor(CameraActor());
995 mRenderTask = taskList.CreateTask();
996 mRenderTask.SetSourceActor(mRootLayer);
997 mRenderTask.SetExclusive(true);
998 mRenderTask.SetInputEnabled(true);
999 mRenderTask.SetCullMode(false);
1000 mRenderTask.SetScreenToFrameBufferMappingActor(Self());
1005 Control::OnSceneConnection(depth);
1008 void SceneView::OnSceneDisconnection()
1012 Window window = mWindow.GetHandle();
1015 window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
1023 RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1024 taskList.RemoveTask(mRenderTask);
1025 mRenderTask.Reset();
1027 if(mShadowMapRenderTask)
1029 RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
1030 taskList.RemoveTask(mShadowMapRenderTask);
1031 mShadowMapRenderTask.Reset();
1033 mSceneHolder.Reset();
1035 mFrameBuffer.Reset();
1036 mShadowFrameBuffer.Reset();
1038 Control::OnSceneDisconnection();
1041 void SceneView::OnInitialize()
1043 Actor self = Self();
1044 mRootLayer = Layer::New();
1045 mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
1046 mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
1047 // The models in the SceneView should be have independent coordinate with DALi default coordinate.
1048 mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
1049 mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
1050 mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
1051 self.Add(mRootLayer);
1053 mDefaultCamera = Dali::CameraActor::New3DCamera();
1054 mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
1055 mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
1056 AddCamera(mDefaultCamera);
1057 UpdateCamera(mDefaultCamera);
1060 void SceneView::OnChildAdd(Actor& child)
1062 if(child != mRootLayer)
1064 mRootLayer.Add(child);
1066 Control::OnChildAdd(child);
1069 void SceneView::OnChildRemove(Actor& child)
1071 mRootLayer.Remove(child);
1072 Control::OnChildRemove(child);
1075 float SceneView::GetHeightForWidth(float width)
1078 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1079 return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
1082 float SceneView::GetWidthForHeight(float height)
1085 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
1086 return Control::GetWidthForHeight(height) + padding.start + padding.end;
1089 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
1091 Control::OnRelayout(size, container);
1092 // Change canvas size of camera actor.
1096 bool SceneView::IsResourceReady() const
1098 return mIblDiffuseResourceReady && mIblSpecularResourceReady && mSkyboxResourceReady;
1101 void SceneView::UpdateCamera(CameraActor camera)
1105 if(mSelectedCamera && mSelectedCamera.GetParent())
1107 mSelectedCamera.Unparent();
1109 mRootLayer.Add(camera);
1112 mSelectedCamera = camera;
1115 SetShadowLightConstraint(mSelectedCamera, GetImplementation(mShadowLight).GetCamera());
1120 void SceneView::UpdateRenderTask()
1124 if(mSelectedCamera != mRenderTask.GetCameraActor())
1126 mRenderTask.SetCameraActor(mSelectedCamera);
1128 uint32_t width = GetResolutionWidth();
1129 uint32_t height = GetResolutionHeight();
1131 uint32_t shadowMapBufferSize = std::min(std::max(width, height), MAXIMUM_SIZE_SHADOW_MAP);
1132 UpdateShadowMapBuffer(shadowMapBufferSize);
1136 Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
1137 if(!currentFrameBuffer ||
1138 !Dali::Equals(currentFrameBuffer.GetColorTexture().GetWidth(), width) ||
1139 !Dali::Equals(currentFrameBuffer.GetColorTexture().GetHeight(), height) ||
1140 mMaskingPropertyChanged ||
1143 mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_COLOR);
1144 mRenderTask.ResetViewportGuideActor();
1145 mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
1147 // create offscreen buffer of new size to render our child actors to
1148 mTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, width, height);
1149 mFrameBuffer = FrameBuffer::New(width, height, FrameBuffer::Attachment::DEPTH_STENCIL);
1150 mFrameBuffer.AttachColorTexture(mTexture);
1151 DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, mFrameBufferMultiSamplingLevel);
1152 Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
1154 Property::Map imagePropertyMap;
1155 imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
1156 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
1157 // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
1158 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
1159 if(!mAlphaMaskUrl.empty())
1161 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::ALPHA_MASK_URL, mAlphaMaskUrl);
1162 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, true);
1163 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::MASK_CONTENT_SCALE, mMaskContentScaleFactor);
1164 imagePropertyMap.Insert(Toolkit::ImageVisual::Property::CROP_TO_MASK, mCropToMask);
1165 imagePropertyMap.Insert(Toolkit::DevelImageVisual::Property::MASKING_TYPE, Toolkit::DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
1166 Self().RegisterProperty(Y_FLIP_MASK_TEXTURE, FLIP_MASK_TEXTURE);
1169 mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
1170 Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
1172 mRenderTask.SetFrameBuffer(mFrameBuffer);
1173 mRenderTask.SetClearEnabled(true);
1174 mRenderTask.SetClearColor(Color::TRANSPARENT);
1176 mMaskingPropertyChanged = false;
1177 mWindowSizeChanged = false;
1182 mRenderTask.SetViewportGuideActor(Self());
1183 if(mRenderTask.GetFrameBuffer())
1185 mRootLayer.SetProperty(Dali::Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_ALPHA);
1186 FrameBuffer framebuffer;
1187 mRenderTask.SetFrameBuffer(framebuffer);
1188 mRenderTask.SetClearEnabled(false);
1190 Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
1193 mFrameBuffer.Reset();
1198 if(width > 0u && height > 0u)
1200 float aspectRatio = static_cast<float>(width) / static_cast<float>(height);
1201 mSelectedCamera.SetAspectRatio(aspectRatio);
1208 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
1210 mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
1214 void SceneView::RotateCamera()
1218 DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
1222 DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
1226 void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentMapType skyboxEnvironmentMapType)
1228 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
1229 if(mSkyboxUrl != skyboxUrl || mSkyboxEnvironmentMapType != skyboxEnvironmentMapType)
1231 mSkyboxDirty = true;
1232 mSkyboxResourceReady = false;
1233 mSkyboxUrl = skyboxUrl;
1234 mSkyboxEnvironmentMapType = skyboxEnvironmentMapType;
1237 if(mSkyboxUrl.empty())
1241 Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1242 mSkyboxLoadTask.Reset();
1249 mSkyboxTexture.Reset();
1252 mSkyboxDirty = false;
1253 mSkyboxResourceReady = true;
1255 // Request image resource GC
1256 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
1260 if(isOnScene && mSkyboxDirty)
1264 Dali::AsyncTaskManager::Get().RemoveTask(mSkyboxLoadTask);
1265 mSkyboxLoadTask.Reset();
1267 // Request image resource GC
1268 Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
1271 mSkyboxLoadTask = new EnvironmentMapLoadTask(mSkyboxUrl, mSkyboxEnvironmentMapType, MakeCallback(this, &SceneView::OnSkyboxLoadComplete));
1272 Dali::AsyncTaskManager::Get().AddTask(mSkyboxLoadTask);
1273 mSkyboxDirty = false;
1277 if(IsResourceReady())
1279 Control::SetResourceReady();
1283 void SceneView::OnSkyboxLoadComplete()
1287 mSkybox = CreateSkybox();
1288 SetSkyboxIntensity(mSkyboxIntensity);
1289 SetSkyboxOrientation(mSkyboxOrientation);
1292 mRootLayer.Add(mSkybox);
1296 mSkyboxResourceReady = true;
1297 mSkyboxTexture = mSkyboxLoadTask->GetLoadedTexture();
1298 Shader skyboxShader;
1299 if(mSkyboxLoadTask->GetEnvironmentMapType() == Scene3D::EnvironmentMapType::CUBEMAP)
1301 skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
1305 skyboxShader = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_EQUIRECTANGULAR_SHADER_FRAG.data());
1308 Renderer skyboxRenderer = (mSkybox.GetRendererCount() > 0u) ? mSkybox.GetRendererAt(0u) : Renderer();
1311 Dali::TextureSet skyboxTextures = TextureSet::New();
1312 skyboxTextures.SetTexture(0, mSkyboxTexture);
1313 skyboxRenderer.SetTextures(skyboxTextures);
1314 skyboxRenderer.SetShader(skyboxShader);
1317 mSkyboxLoadTask.Reset();
1319 if(IsResourceReady())
1321 Control::SetResourceReady();
1325 void SceneView::OnIblDiffuseLoadComplete()
1327 mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
1328 mIblDiffuseResourceReady = true;
1329 mIblDiffuseLoadTask.Reset();
1330 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1332 OnIblLoadComplete();
1336 void SceneView::OnIblSpecularLoadComplete()
1338 mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
1339 mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
1340 mIblSpecularResourceReady = true;
1341 mIblSpecularLoadTask.Reset();
1342 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
1344 OnIblLoadComplete();
1348 void SceneView::OnIblLoadComplete()
1350 NotifyImageBasedLightTextureChange();
1351 if(IsResourceReady())
1353 Control::SetResourceReady();
1357 void SceneView::NotifyImageBasedLightTextureChange()
1359 for(auto&& item : mItems)
1363 item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
1368 void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize)
1370 Dali::FrameBuffer currentShadowFrameBuffer = mShadowMapRenderTask.GetFrameBuffer();
1372 (!currentShadowFrameBuffer ||
1374 !Dali::Equals(DevelFrameBuffer::GetDepthTexture(currentShadowFrameBuffer).GetWidth(), shadowMapSize)))
1376 mShadowFrameBuffer.Reset();
1377 mShadowTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::DEPTH_UNSIGNED_INT, shadowMapSize, shadowMapSize);
1378 mShadowFrameBuffer = FrameBuffer::New(shadowMapSize, shadowMapSize, FrameBuffer::Attachment::NONE);
1379 DevelFrameBuffer::AttachDepthTexture(mShadowFrameBuffer, mShadowTexture);
1380 mShadowMapRenderTask.SetFrameBuffer(mShadowFrameBuffer);
1382 for(auto&& item : mItems)
1386 item->NotifyShadowMapTexture(mShadowTexture);
1392 } // namespace Internal
1393 } // namespace Scene3D