2 * Copyright (c) 2023 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/public-api/loader/camera-parameters.h>
22 #include <dali/devel-api/actors/camera-actor-devel.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/actors/camera-actor.h>
25 #include <dali/public-api/math/quaternion.h>
28 #include <dali-scene3d/internal/loader/gltf2-asset.h> // for gltf2::UNDEFINED_FLOAT_VALUE
29 #include <dali-scene3d/public-api/loader/utils.h>
31 namespace Dali::Scene3D::Loader
36 * @brief Creates a perspective matrix.
38 * @param[out] result The perspective matrix.
39 * @param[in] left The coordinate for the left vertical clipping plane.
40 * @param[in] right The coordinate for the right vertical clipping plane.
41 * @param[in] bottom The coordinate for the bottom horizontal clipping plane.
42 * @param[in] top The coordinate for the top horizontal clipping plane.
43 * @param[in] near The distance to the near depth clipping plane.
44 * @param[in] far The distance to the far depth clipping plane.
45 * @param[in] invertYAxis Whether to invert the 'Y' axis.
47 void Frustum(Matrix& result, float left, float right, float bottom, float top, float nearPlane, float farPlane, bool invertYAxis)
49 float deltaZ = farPlane - nearPlane;
50 if((nearPlane <= 0.0f) || (farPlane <= 0.0f) || Equals(right, left) || Equals(bottom, top) || (deltaZ <= 0.0f))
52 DALI_LOG_ERROR("Invalid parameters passed into Frustum!\n");
53 DALI_ASSERT_DEBUG("Invalid parameters passed into Frustum!");
57 float deltaX = right - left;
58 float deltaY = invertYAxis ? bottom - top : top - bottom;
62 float* m = result.AsFloat();
63 m[0] = -2.0f * nearPlane / deltaX;
64 m[1] = m[2] = m[3] = 0.0f;
66 m[5] = -2.0f * nearPlane / deltaY;
67 m[4] = m[6] = m[7] = 0.0f;
69 m[8] = (right + left) / deltaX;
70 m[9] = (top + bottom) / deltaY;
71 m[10] = (nearPlane + farPlane) / deltaZ;
74 m[14] = -2.0f * nearPlane * farPlane / deltaZ;
75 m[12] = m[13] = m[15] = 0.0f;
79 * @brief Creates a perspective projection matrix.
83 * @param[out] result The perspective projection matrix.
84 * @param[in] fovy The vertical field of view.
85 * @param[in] aspect The aspect ratio.
86 * @param[in] nearPlane The distance to the near depth clipping plane.
87 * @param[in] farPlane The distance to the far depth clipping plane.
88 * @param[in] invertYAxis Whether to invert the 'Y' axis.
90 void Perspective(Matrix& result, float fovy, float aspect, float nearPlane, float farPlane, bool invertYAxis)
92 float frustumH = tanf(fovy * 0.5f) * nearPlane;
93 float frustumW = frustumH * aspect;
95 Frustum(result, -frustumW, frustumW, -frustumH, frustumH, nearPlane, farPlane, invertYAxis);
99 * @brief Creates an orthographic projection matrix.
101 * @param[out] result The orthographic projection matrix.
102 * @param[in] left The coordinate for the left vertical clipping plane.
103 * @param[in] right The coordinate for the right vertical clipping plane.
104 * @param[in] bottom The coordinate for the bottom horizontal clipping plane.
105 * @param[in] top The coordinate for the top horizontal clipping plane.
106 * @param[in] nearPlane The distance to the near depth clipping plane.
107 * @param[in] farPlane The distance to the far depth clipping plane.
108 * @param[in] invertYAxis Whether to invert the 'Y' axis.
110 void Orthographic(Matrix& result, float left, float right, float bottom, float top, float nearPlane, float farPlane, bool invertYAxis)
112 if(Equals(right, left) || Equals(top, bottom) || Equals(farPlane, nearPlane))
114 DALI_LOG_ERROR("Cannot create orthographic projection matrix with a zero dimension.\n");
115 DALI_ASSERT_DEBUG("Cannot create orthographic projection matrix with a zero dimension.");
119 float deltaX = right - left;
120 float deltaY = invertYAxis ? bottom - top : top - bottom;
121 float deltaZ = farPlane - nearPlane;
123 float* m = result.AsFloat();
124 m[0] = -2.0f / deltaX;
130 m[5] = -2.0f / deltaY;
136 m[10] = 2.0f / deltaZ;
138 m[12] = -(right + left) / deltaX;
139 m[13] = -(top + bottom) / deltaY;
140 m[14] = -(nearPlane + farPlane) / deltaZ;
146 ViewProjection CameraParameters::GetViewProjection() const
148 ViewProjection viewProjection;
150 // The projection matrix.
153 Perspective(viewProjection.GetProjection(),
162 Orthographic(viewProjection.GetProjection(),
163 -orthographicSize * aspectRatio,
164 orthographicSize * aspectRatio,
173 const Quaternion viewQuaternion(ANGLE_180, Vector3::YAXIS);
175 Quaternion cameraOrientation;
177 matrix.GetTransformComponents(translation, cameraOrientation, scale);
178 cameraOrientation *= viewQuaternion;
180 viewProjection.GetView().SetInverseTransformComponents(scale,
184 viewProjection.Update();
185 return viewProjection;
188 void CameraParameters::CalculateTransformComponents(Vector3& position, Quaternion& orientation, Vector3& scale) const
190 matrix.GetTransformComponents(position, orientation, scale);
192 // The CameraActor is expected to look down the negative Z axis, towards the scene.
193 // Here we emulate the default direction of the camera in DALi.
194 Quaternion viewQuaternion(ANGLE_180, Vector3::YAXIS);
195 orientation *= viewQuaternion;
198 bool CameraParameters::ConfigureCamera(CameraActor& camera, bool invertY) const
200 camera[Actor::Property::NAME] = name;
204 if(Dali::Equals(zNear, gltf2::UNDEFINED_FLOAT_VALUE) ||
205 Dali::Equals(yFovDegree.degree, gltf2::UNDEFINED_FLOAT_VALUE))
210 camera.SetProjectionMode(Camera::PERSPECTIVE_PROJECTION);
211 camera.SetNearClippingPlane(zNear);
212 camera.SetFieldOfView(Radian(yFovDegree));
214 if(!Dali::Equals(zFar, gltf2::UNDEFINED_FLOAT_VALUE))
216 camera.SetFarClippingPlane(zFar);
220 // TODO : Infinite perspective projection didn't support yet. Just set big enough value now
221 camera.SetFarClippingPlane(1000.0f);
224 if(!Dali::Equals(aspectRatio, gltf2::UNDEFINED_FLOAT_VALUE))
226 // TODO: By gltf 2.0 spec, we should not 'crop' and 'non-uniform scaling' by viewport.
227 // If we skip to setup this value, 'non-uniform scaling' problem fixed.
228 // But we need to resolve 'crop' case in future.
229 //camera.SetAspectRatio(aspectRatio);
234 if(Dali::Equals(zNear, gltf2::UNDEFINED_FLOAT_VALUE) ||
235 Dali::Equals(zFar, gltf2::UNDEFINED_FLOAT_VALUE) ||
236 Dali::Equals(orthographicSize, gltf2::UNDEFINED_FLOAT_VALUE))
241 camera.SetProjectionMode(Camera::ORTHOGRAPHIC_PROJECTION);
242 camera.SetNearClippingPlane(zNear);
243 camera.SetFarClippingPlane(zFar);
244 camera.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, orthographicSize);
246 if(!Dali::Equals(aspectRatio, gltf2::UNDEFINED_FLOAT_VALUE))
248 // TODO: By gltf 2.0 spec, we should not 'crop' and 'non-uniform scaling' by viewport.
249 // If we skip to setup this value, 'non-uniform scaling' problem fixed.
250 // But we need to resolve 'crop' case in future.
251 //camera.SetAspectRatio(aspectRatio);
255 SetActorCentered(camera);
258 Vector3 camTranslation;
260 Quaternion camOrientation;
261 CalculateTransformComponents(camTranslation, camOrientation, camScale);
263 camera.SetInvertYAxis(invertY);
264 camera.SetProperty(Actor::Property::POSITION, camTranslation);
265 camera.SetProperty(Actor::Property::ORIENTATION, camOrientation);
266 camera.SetProperty(Actor::Property::SCALE, camScale);
271 } // namespace Dali::Scene3D::Loader