/* * Copyright(c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using System; using System.Runtime.InteropServices; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using Tizen.NUI; using Tizen.NUI.Binding; using Tizen.NUI.BaseComponents; namespace Tizen.NUI.Scene3D { /// /// SceneView is a Class to show multiple 3D objects in a single 2D screen. /// Each SceneView has its own 3D space, and 3D objects added to SceneView are positioned in the space. /// SceneView uses left-handed coordinate system same as NUI. X as right, Y as down, and Z as forward. /// /// SceneView has internal root container to control inner rendering process like depth test. /// When a View is added to the SceneView with method, it is actually added on the root container. /// Therefore, the added Views exist in the sub tree of SceneView, but are not direct children. /// The sub tree of Views will be rendered with the SceneView's own Camera. /// /// SceneView has one built-in camera by default. /// The default Camera is not removed by using method. /// method with index "0" returns the default camera, /// and the minimum value returned by method is 1. /// /// SceneView also provides multiple Camera and one of them can be used to render multiple objects. /// , , , /// and are methods to manage Cameras of the SceneView. /// User can place multiple cameras in a scene to display the entire scene or to display individual objects. /// User can use the method to select the currently required camera. /// /// When the SceneView's size changes, some camera properties that depend on its size may also change. /// The changing properties are as follows: AspectRatio, LeftPlaneDistance, RightPlaneDistance, TopPlaneDistance, and BottomPlaneDistance. /// The Camera's FieldOfView is vertical fov. The horizontal fov is updated internally according to the SceneView size. /// /// The method sets the same IBL to all Model objects added to the SceneView. /// For the IBL, two cube map textures(diffuse and specular) are required. /// SceneView supports 4 types layout for Cube Map: Vertical/Horizontal Cross layouts, and Vertical/Horizontal Array layouts. /// And also, ktx format with cube map is supported. /// If a model already has an IBL, it is batch overridden with the IBL of the SceneView. /// If the SceneView has IBL, the IBL of newly added models is also overridden. /// /// The IBL textures start to be loaded asynchronously when method is called. /// ResourcesLoaded signal notifies that the loading of the IBL resources have been completed. /// /// If FBO is used, the rendering result of SceneView is drawn on the FBO and it is mapped on the plane of the SceneView. /// It could decreases performance slightly, but it is useful to show SceneView according to the rendering order with other Views. /// /// And since SceneView is a View, it can be placed together with other 2D UI components in the NUI window. /// /// 10 public class SceneView : View { private bool inCameraTransition = false; private Animation cameraTransition; private string skyboxUrl; internal SceneView(global::System.IntPtr cPtr, bool cMemoryOwn) : this(cPtr, cMemoryOwn, cMemoryOwn) { } internal SceneView(global::System.IntPtr cPtr, bool cMemoryOwn, bool cRegister) : base(cPtr, cMemoryOwn, true, cRegister) { } /// /// Create an initialized SceneView. /// /// 10 public SceneView() : this(Interop.SceneView.SceneNew(), true) { if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Copy constructor. /// /// The source object. /// 10 public SceneView(SceneView sceneView) : this(Interop.SceneView.NewScene(SceneView.getCPtr(sceneView)), true, false) { if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Assignment operator. /// /// Handle to an object. /// Reference to this. internal SceneView Assign(SceneView sceneView) { SceneView ret = new SceneView(Interop.SceneView.SceneAssign(SwigCPtr, SceneView.getCPtr(sceneView)), false); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return ret; } /// /// An event emitted when Camera Transition is finished. /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public event EventHandler CameraTransitionFinished; /// /// Set/Get the ImageBasedLight ScaleFactor. /// Scale factor controls light source intensity in [0.0f, 1.0f] /// /// 10 public float ImageBasedLightScaleFactor { set { SetImageBasedLightScaleFactor(value); } get { return GetImageBasedLightScaleFactor(); } } /// /// Set/Get the UseFramebuffer. /// If this property is true, rendering result of SceneView is drawn on FBO and it is mapping on this SceneView plane. /// If this property is false, each item in SceneView is rendered on window directly. /// Default is false. /// /// /// If UseFramebuffer is true, it could decrease performance but entire rendering order is satisfied. /// If UseFramebuffer is false, the performance becomes better but SceneView is rendered on the top of the other 2D components regardless tree order. /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public bool UseFramebuffer { set { SetUseFramebuffer(value); } get { return IsUsingFramebuffer(); } } /// /// Set/Get the Framebuffer's MultiSamplingLevel. /// Only has effects if UseFramebuffer is true, and Framebuffer MultiSampling is supported. /// Default is 0. /// /// /// Getter didn't consider Framebuffer MultiSampling is supported or not. /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public uint FramebufferMultiSamplingLevel { set { SetFramebufferMultiSamplingLevel(value); } get { return GetFramebufferMultiSamplingLevel(); } } /// /// Set/Get SkyboxUrl. /// If SkyboxUrl is set, the cube map image is loaded and skybox is attached on scene. /// Skybox texture is asynchronously loaded. When loading is finished, ResourcesLoaded is emitted. /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public string SkyboxUrl { set { SetSkybox(value); } get { return skyboxUrl; } } /// /// Set/Get Skybox intensity. /// The skybox intensity is multiplied to the color of skybox texture. /// Default value is 1.0f. /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public float SkyboxIntensity { set { SetSkyboxIntensity(value); } get { return GetSkyboxIntensity(); } } /// /// Set/Get angle of orientation of the skybox. /// If orientation is set, the skybox will be rotate by the Radian orientation along YAxis. /// Default value is 0.0f. /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public Rotation SkyboxOrientation { set { SetSkyboxOrientation(value); } get { return GetSkyboxOrientation(); } } /// /// Adds a Camera to the SceneView at the end of the camera list of SceneView. /// The Camera can be used as a selected camera to render the scene by using or /// /// Camera added on this SceneView. /// /// Some properties of the Camera will be change depending on the Size of this SceneView. /// Those properties are as follows: /// AspectRatio, LeftPlaneDistance, RightPlaneDistance, TopPlaneDistance, and BottomPlaneDistance. /// /// The FieldOfView of Camera is for vertical fov. /// When the size of the SceneView is changed, the vertical fov is maintained /// and the horizontal fov is automatically calculated according to the SceneView's AspectRatio. /// /// 10 public void AddCamera(Camera camera) { if (camera != null) { Interop.SceneView.AddCamera(SwigCPtr, camera.SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } } /// /// Removes a Camera from this SceneView. /// If removed Camera is selected Camera, /// first camera in the list becomes the selected Camera. /// /// camera Camera to be removed from this Camera. /// /// When Camera.Dispose() is called, the NUI object is disposed, but camera information is maintained internally. /// Therefore, even if Camera.Dispose() is called, RemoveCamera() or RemoveCamera() methods can be used. /// If RemoveCamera() is called too, all information is deleted together. /// /// 10 public void RemoveCamera(Camera camera) { if (camera != null) { Interop.SceneView.RemoveCamera(SwigCPtr, camera.SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } } /// /// Retrieves the number of cameras. /// /// The number of Cameras. /// 10 public uint GetCameraCount() { uint count = Interop.SceneView.GetCameraCount(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return count; } /// /// Retrieves a Camera of the index. /// /// Index of Camera to be retrieved. /// Camera of the index. /// 10 public Camera GetCamera(uint index) { global::System.IntPtr cPtr = Interop.SceneView.GetCamera(SwigCPtr, index); Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera; if (camera == null) { // Register new camera into Registry. camera = new Camera(cPtr, true); } else { // We found matched NUI camera. Reduce cPtr reference count. HandleRef handle = new HandleRef(this, cPtr); Interop.Camera.DeleteCameraProperty(handle); handle = new HandleRef(null, IntPtr.Zero); } if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return camera; } /// /// Retrieves a Camera of the input name. /// /// string keyword of Camera to be retrieved. /// Camera that has the name as a View.Name property /// 10 public Camera GetCamera(string name) { global::System.IntPtr cPtr = Interop.SceneView.GetCamera(SwigCPtr, name); Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera; if (camera == null) { // Register new camera into Registry. camera = new Camera(cPtr, true); } else { // We found matched NUI camera. Reduce cPtr reference count. HandleRef handle = new HandleRef(this, cPtr); Interop.Camera.DeleteCameraProperty(handle); handle = new HandleRef(null, IntPtr.Zero); } if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return camera; } /// /// Makes SceneView use a Camera of index as a selected camera. /// /// Index of Camera to be used as a selected camera. /// 10 public void SelectCamera(uint index) { if (inCameraTransition) { return; } this.GetSelectedCamera()?.Unparent(); Interop.SceneView.SelectCamera(SwigCPtr, index); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Makes SceneView use a Camera of a name as a selected camera. /// /// string keyword of Camera to be used as a selected camera. /// 10 public void SelectCamera(string name) { if (inCameraTransition) { return; } this.GetSelectedCamera()?.Unparent(); Interop.SceneView.SelectCamera(SwigCPtr, name); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Starts camera transition from currently selected camera to a camera of index. /// Camera Position, Orientation and FieldOfView are smoothly animated. /// /// /// The selected camera is switched to the Camera of the index when the transition is started. /// During camera transition, Selected Camera should not be changed by using SelectCamera() or CameraTransition() method. /// During camera transition, Camera properties of Selected Camera should not be changed. /// /// Index of destination Camera of Camera transition. /// The duration in milliseconds. /// The alpha function to apply. /// 10 [SuppressMessage("Microsoft.Design", "CA2000: Dispose objects before losing scope", Justification = "The ownership of camera object is not owned by this class.")] public void CameraTransition(uint index, int durationMilliSeconds, AlphaFunction alphaFunction = null) { if (inCameraTransition || GetSelectedCamera() == GetCamera(index)) { return; } Camera source = GetSelectedCamera(); SelectCamera(index); Camera destination = GetSelectedCamera(); CameraTransition(source, destination, durationMilliSeconds, alphaFunction); } /// /// Starts camera transition from currently selected camera to a camera of input name. /// Camera Position, Orientation and FieldOfView are smoothly animated. /// /// /// The selected camera is switched to the Camera of the input name when the transition is started. /// During camera transition, Selected Camera should not be changed by using SelectCamera() or CameraTransition() method. /// During camera transition, Camera properties of Selected Camera should not be changed. /// /// string keyword of destination Camera of Camera transition. /// The duration in milliseconds. /// The alpha function to apply. /// 10 [SuppressMessage("Microsoft.Design", "CA2000: Dispose objects before losing scope", Justification = "The ownership of camera object is not owned by this class.")] public void CameraTransition(string name, int durationMilliSeconds, AlphaFunction alphaFunction = null) { if (inCameraTransition || GetSelectedCamera() == GetCamera(name)) { return; } Camera source = GetSelectedCamera(); SelectCamera(name); Camera destination = GetSelectedCamera(); CameraTransition(source, destination, durationMilliSeconds, alphaFunction); } /// /// Retrieves selected Camera. /// /// Camera currently used in SceneView as a selected Camera. /// 10 public Camera GetSelectedCamera() { global::System.IntPtr cPtr = Interop.SceneView.GetSelectedCamera(SwigCPtr); Camera camera = Registry.GetManagedBaseHandleFromNativePtr(cPtr) as Camera; if (camera == null) { // Register new camera into Registry. camera = new Camera(cPtr, true); } else { // We found matched NUI camera. Reduce cPtr reference count. HandleRef handle = new HandleRef(this, cPtr); Interop.Camera.DeleteCameraProperty(handle); handle = new HandleRef(null, IntPtr.Zero); } if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return camera; } /// /// Changes Image Based Light as the input textures. /// /// The path of Cube map image that can be used as a diffuse IBL source. /// The path of Cube map image that can be used as a specular IBL source. /// Scale factor that controls light source intensity in [0.0f, 1.0f]. Default value is 1.0f. /// /// http://tizen.org/privilege/mediastorage for local files in media storage. /// http://tizen.org/privilege/externalstorage for local files in external storage. /// /// 10 public void SetImageBasedLightSource(string diffuseUrl, string specularUrl, float scaleFactor = 1.0f) { Interop.SceneView.SetImageBasedLightSource(SwigCPtr, diffuseUrl, specularUrl, scaleFactor); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Add Lights to this SceneView. /// /// The light what we want to add // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public void AddLight(Light light) { Interop.SceneView.AddLight(SwigCPtr, Light.getCPtr(light)); NDalicPINVOKE.ThrowExceptionIfExists(); } /// /// Remove Lights from this SceneView. /// /// The light what we want to remove // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public void RemoveLight(Light light) { Interop.SceneView.RemoveLight(SwigCPtr, Light.getCPtr(light)); NDalicPINVOKE.ThrowExceptionIfExists(); } /// /// Sets SceneView's resolution manually. /// /// The input width. /// The input height. /// /// This manual resolution is only available when the SceneView uses FBO for rendering by using FBO (UseFrameBuffer is true). /// If the aspect ratio of input width/height is different with SceneView's aspect ratio, the rendered result is stretched to fill SceneView's area. /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public void SetResolution(uint width, uint height) { Interop.SceneView.SetResolution(SwigCPtr, width, height); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Retrieves width of resolution of the SceneView. /// /// /// If the SceneView not uses FBO, this method returns SceneView's width. /// /// Camera currently used in SceneView as a selected Camera. // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public uint GetResolutionWidth() { uint result = Interop.SceneView.GetResolutionWidth(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return result; } /// /// Retrieves height of resolution of the SceneView. /// /// /// If the SceneView not uses FBO, this method returns SceneView's height. /// /// Camera currently used in SceneView as a selected Camera. // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public uint GetResolutionHeight() { uint result = Interop.SceneView.GetResolutionHeight(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return result; } /// /// Resets SceneView's resolution to the current size of SceneView. /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] public void ResetResolution() { Interop.SceneView.ResetResolution(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } internal void SetUseFramebuffer(bool useFramebuffer) { Interop.SceneView.UseFramebuffer(SwigCPtr, useFramebuffer); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } internal bool IsUsingFramebuffer() { bool result = Interop.SceneView.IsUsingFramebuffer(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return result; } internal void SetFramebufferMultiSamplingLevel(uint multiSamplingLevel) { Interop.SceneView.SetFramebufferMultiSamplingLevel(SwigCPtr, multiSamplingLevel); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } internal uint GetFramebufferMultiSamplingLevel() { uint result = Interop.SceneView.GetFramebufferMultiSamplingLevel(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return result; } /// /// Set the ImageBasedLight ScaleFactor. /// /// Scale factor that controls light source intensity in [0.0f, 1.0f]. private void SetImageBasedLightScaleFactor(float scaleFactor) { Interop.SceneView.SetImageBasedLightScaleFactor(SwigCPtr, scaleFactor); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Get the ImageBasedLight ScaleFactor. /// /// ImageBasedLightScaleFactor that controls light source intensity. private float GetImageBasedLightScaleFactor() { float scaleFactor = Interop.SceneView.GetImageBasedLightScaleFactor(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return scaleFactor; } /// /// Set the Skybox from cube map image. /// Skybox texture is asynchronously loaded. When loading is finished, ResourcesLoaded is emitted. /// /// Cube map image url for skybox. private void SetSkybox(string skyboxUrl) { this.skyboxUrl = skyboxUrl; Interop.SceneView.SetSkybox(SwigCPtr, skyboxUrl); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Sets Skybox intensity. /// The skybox intensity is multiplied to the color of skybox texture. /// Default value is 1.0f. /// /// Intensity value to be multiplied to the cube map color. private void SetSkyboxIntensity(float intensity) { Interop.SceneView.SetSkyboxIntensity(SwigCPtr, intensity); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Gets Skybox intensity. /// Default value is 1.0f. /// /// skybox intensity. private float GetSkyboxIntensity() { float intensity = Interop.SceneView.GetSkyboxIntensity(SwigCPtr); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return intensity; } /// /// Sets orientation of the skybox. /// /// Rotation angle of the skybox along YAxis. private void SetSkyboxOrientation(Rotation orientation) { Interop.SceneView.SetSkyboxOrientation(SwigCPtr, Rotation.getCPtr(orientation)); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); } /// /// Gets Skybox orientation. /// /// skybox orientation. private Rotation GetSkyboxOrientation() { global::System.IntPtr cPtr = Interop.SceneView.GetSkyboxOrientation(SwigCPtr); Rotation ret = (cPtr == global::System.IntPtr.Zero) ? null : new Rotation(cPtr, true); if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve(); return ret; } private void CameraTransition(Camera sourceCamera, Camera destinationCamera, int durationMilliSeconds, AlphaFunction alphaFunction) { inCameraTransition = true; Position sourcePosition = sourceCamera.Position; Rotation sourceOrientation = sourceCamera.Orientation; Position destinationPosition = destinationCamera.Position; Rotation destinationOrientation = destinationCamera.Orientation; cameraTransition = new Animation(durationMilliSeconds); KeyFrames positionKeyFrames = new KeyFrames(); positionKeyFrames.Add(0.0f, sourcePosition); positionKeyFrames.Add(1.0f, destinationPosition); KeyFrames orientationKeyFrames = new KeyFrames(); orientationKeyFrames.Add(0.0f, sourceOrientation); orientationKeyFrames.Add(1.0f, destinationOrientation); cameraTransition.AnimateBetween(destinationCamera, "Position", positionKeyFrames, Animation.Interpolation.Linear, alphaFunction); cameraTransition.AnimateBetween(destinationCamera, "Orientation", orientationKeyFrames, Animation.Interpolation.Linear, alphaFunction); if (destinationCamera.ProjectionMode == Camera.ProjectionModeType.Perspective) { Radian sourceFieldOfView = sourceCamera.FieldOfView; Radian destinationFieldOfView = destinationCamera.FieldOfView; // If ProjectionDirection is not equal, match the value. if (sourceCamera.ProjectionDirection != destinationCamera.ProjectionDirection) { float aspect = destinationCamera.AspectRatio; if (destinationCamera.ProjectionDirection == Camera.ProjectionDirectionType.Vertical) { Camera.ConvertFovFromHorizontalToVertical(aspect, ref sourceFieldOfView); } else { Camera.ConvertFovFromVerticalToHorizontal(aspect, ref sourceFieldOfView); } } KeyFrames fieldOfViewKeyFrames = new KeyFrames(); fieldOfViewKeyFrames.Add(0.0f, sourceFieldOfView.ConvertToFloat()); fieldOfViewKeyFrames.Add(1.0f, destinationFieldOfView.ConvertToFloat()); cameraTransition.AnimateBetween(destinationCamera, "FieldOfView", fieldOfViewKeyFrames, Animation.Interpolation.Linear, alphaFunction); sourceFieldOfView.Dispose(); destinationFieldOfView.Dispose(); fieldOfViewKeyFrames.Dispose(); } else { float sourceOrthographicSize = sourceCamera.OrthographicSize; float destinationOrthographicSize = destinationCamera.OrthographicSize; // If ProjectionDirection is not equal, match the value. if (sourceCamera.ProjectionDirection != destinationCamera.ProjectionDirection) { float aspect = destinationCamera.AspectRatio; if (destinationCamera.ProjectionDirection == Camera.ProjectionDirectionType.Vertical) { sourceOrthographicSize = sourceOrthographicSize / aspect; } else { sourceOrthographicSize = sourceOrthographicSize * aspect; } } KeyFrames orthographicSizeKeyFrames = new KeyFrames(); orthographicSizeKeyFrames.Add(0.0f, sourceOrthographicSize); orthographicSizeKeyFrames.Add(1.0f, destinationOrthographicSize); cameraTransition.AnimateBetween(destinationCamera, "OrthographicSize", orthographicSizeKeyFrames, Animation.Interpolation.Linear, alphaFunction); orthographicSizeKeyFrames.Dispose(); } float destinationNearPlaneDistance = destinationCamera.NearPlaneDistance; float destinationFarPlaneDistance = destinationCamera.FarPlaneDistance; destinationCamera.NearPlaneDistance = Math.Min(sourceCamera.NearPlaneDistance, destinationCamera.NearPlaneDistance); destinationCamera.FarPlaneDistance = Math.Max(sourceCamera.FarPlaneDistance, destinationCamera.FarPlaneDistance); cameraTransition.Finished += (s, e) => { this.GetSelectedCamera().NearPlaneDistance = destinationNearPlaneDistance; this.GetSelectedCamera().FarPlaneDistance = destinationFarPlaneDistance; inCameraTransition = false; CameraTransitionFinished?.Invoke(this, EventArgs.Empty); }; cameraTransition.Play(); positionKeyFrames.Dispose(); orientationKeyFrames.Dispose(); } /// /// Release swigCPtr. /// // This will be public opened after ACR done. (Before ACR, need to be hidden as Inhouse API) [EditorBrowsable(EditorBrowsableState.Never)] protected override void ReleaseSwigCPtr(global::System.Runtime.InteropServices.HandleRef swigCPtr) { Interop.SceneView.DeleteScene(swigCPtr); } } }