Merge "Allow to load uint32_t as indices" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / camera-parameters.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-scene3d/public-api/loader/camera-parameters.h>
20
21 // EXTERNAL INCLUDES
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>
26
27 // INTERNAL INCLUDES
28 #include <dali-scene3d/internal/loader/gltf2-asset.h> // for gltf2::UNDEFINED_FLOAT_VALUE
29 #include <dali-scene3d/public-api/loader/utils.h>
30
31 namespace Dali
32 {
33 namespace Scene3D
34 {
35 namespace Loader
36 {
37 namespace
38 {
39 /**
40  * @brief Creates a perspective matrix.
41  *
42  * @param[out] result The perspective matrix.
43  * @param[in] left The coordinate for the left vertical clipping plane.
44  * @param[in] right The coordinate for the right vertical clipping plane.
45  * @param[in] bottom The coordinate for the bottom horizontal clipping plane.
46  * @param[in] top The coordinate for the top horizontal clipping plane.
47  * @param[in] near The distance to the near depth clipping plane.
48  * @param[in] far The distance to the far depth clipping plane.
49  * @param[in] invertYAxis Whether to invert the 'Y' axis.
50  */
51 void Frustum(Matrix& result, float left, float right, float bottom, float top, float nearPlane, float farPlane, bool invertYAxis)
52 {
53   float deltaZ = farPlane - nearPlane;
54   if((nearPlane <= 0.0f) || (farPlane <= 0.0f) || Equals(right, left) || Equals(bottom, top) || (deltaZ <= 0.0f))
55   {
56     DALI_LOG_ERROR("Invalid parameters passed into Frustum!\n");
57     DALI_ASSERT_DEBUG("Invalid parameters passed into Frustum!");
58     return;
59   }
60
61   float deltaX = right - left;
62   float deltaY = invertYAxis ? bottom - top : top - bottom;
63
64   result.SetIdentity();
65
66   float* m = result.AsFloat();
67   m[0]     = -2.0f * nearPlane / deltaX;
68   m[1] = m[2] = m[3] = 0.0f;
69
70   m[5] = -2.0f * nearPlane / deltaY;
71   m[4] = m[6] = m[7] = 0.0f;
72
73   m[8]  = (right + left) / deltaX;
74   m[9]  = (top + bottom) / deltaY;
75   m[10] = (nearPlane + farPlane) / deltaZ;
76   m[11] = 1.0f;
77
78   m[14] = -2.0f * nearPlane * farPlane / deltaZ;
79   m[12] = m[13] = m[15] = 0.0f;
80 }
81
82 /**
83  * @brief Creates a perspective projection matrix.
84  *
85  * It calls Frustum()
86  *
87  * @param[out] result The perspective projection matrix.
88  * @param[in] fovy The vertical field of view.
89  * @param[in] aspect The aspect ratio.
90  * @param[in] nearPlane The distance to the near depth clipping plane.
91  * @param[in] farPlane The distance to the far depth clipping plane.
92  * @param[in] invertYAxis Whether to invert the 'Y' axis.
93  */
94 void Perspective(Matrix& result, float fovy, float aspect, float nearPlane, float farPlane, bool invertYAxis)
95 {
96   float frustumH = tanf(fovy * 0.5f) * nearPlane;
97   float frustumW = frustumH * aspect;
98
99   Frustum(result, -frustumW, frustumW, -frustumH, frustumH, nearPlane, farPlane, invertYAxis);
100 }
101
102 /**
103 * @brief Creates an orthographic projection matrix.
104 *
105 * @param[out] result The orthographic projection matrix.
106 * @param[in] left The coordinate for the left vertical clipping plane.
107 * @param[in] right The coordinate for the right vertical clipping plane.
108 * @param[in] bottom The coordinate for the bottom horizontal clipping plane.
109 * @param[in] top The coordinate for the top horizontal clipping plane.
110 * @param[in] nearPlane The distance to the near depth clipping plane.
111 * @param[in] farPlane The distance to the far depth clipping plane.
112 * @param[in] invertYAxis Whether to invert the 'Y' axis.
113 */
114 void Orthographic(Matrix& result, float left, float right, float bottom, float top, float nearPlane, float farPlane, bool invertYAxis)
115 {
116   if(Equals(right, left) || Equals(top, bottom) || Equals(farPlane, nearPlane))
117   {
118     DALI_LOG_ERROR("Cannot create orthographic projection matrix with a zero dimension.\n");
119     DALI_ASSERT_DEBUG("Cannot create orthographic projection matrix with a zero dimension.");
120     return;
121   }
122
123   float deltaX = right - left;
124   float deltaY = invertYAxis ? bottom - top : top - bottom;
125   float deltaZ = farPlane - nearPlane;
126
127   float* m = result.AsFloat();
128   m[0]     = -2.0f / deltaX;
129   m[1]     = 0.0f;
130   m[2]     = 0.0f;
131   m[3]     = 0.0f;
132
133   m[4] = 0.0f;
134   m[5] = -2.0f / deltaY;
135   m[6] = 0.0f;
136   m[7] = 0.0f;
137
138   m[8]  = 0.0f;
139   m[9]  = 0.0f;
140   m[10] = 2.0f / deltaZ;
141   m[11] = 0.0f;
142   m[12] = -(right + left) / deltaX;
143   m[13] = -(top + bottom) / deltaY;
144   m[14] = -(nearPlane + farPlane) / deltaZ;
145   m[15] = 1.0f;
146 }
147
148 } // namespace
149
150 ViewProjection CameraParameters::GetViewProjection() const
151 {
152   ViewProjection viewProjection;
153
154   // The projection matrix.
155   if(isPerspective)
156   {
157     Perspective(viewProjection.GetProjection(),
158                 Radian(yFovDegree),
159                 1.f,
160                 zNear,
161                 zFar,
162                 true);
163   }
164   else
165   {
166     Orthographic(viewProjection.GetProjection(),
167                  -orthographicSize * aspectRatio,
168                  orthographicSize * aspectRatio,
169                  orthographicSize,
170                  -orthographicSize,
171                  zNear,
172                  zFar,
173                  true);
174   }
175
176   // The view matrix.
177   const Quaternion viewQuaternion(ANGLE_180, Vector3::YAXIS);
178   Vector3          translation;
179   Quaternion       cameraOrientation;
180   Vector3          scale;
181   matrix.GetTransformComponents(translation, cameraOrientation, scale);
182   cameraOrientation *= viewQuaternion;
183
184   viewProjection.GetView().SetInverseTransformComponents(scale,
185                                                          cameraOrientation,
186                                                          translation);
187
188   viewProjection.Update();
189   return viewProjection;
190 }
191
192 void CameraParameters::CalculateTransformComponents(Vector3& position, Quaternion& orientation, Vector3& scale) const
193 {
194   matrix.GetTransformComponents(position, orientation, scale);
195
196   // The CameraActor is expected to look down the negative Z axis, towards the scene.
197   // Here we emulate the default direction of the camera in DALi.
198   Quaternion viewQuaternion(ANGLE_180, Vector3::YAXIS);
199   orientation *= viewQuaternion;
200 }
201
202 bool CameraParameters::ConfigureCamera(CameraActor& camera, bool invertY) const
203 {
204   if(isPerspective)
205   {
206     if(Dali::Equals(zNear, gltf2::UNDEFINED_FLOAT_VALUE) ||
207        Dali::Equals(yFovDegree.degree, gltf2::UNDEFINED_FLOAT_VALUE))
208     {
209       return false;
210     }
211
212     camera.SetProjectionMode(Camera::PERSPECTIVE_PROJECTION);
213     camera.SetNearClippingPlane(zNear);
214     camera.SetFieldOfView(Radian(yFovDegree));
215
216     if(!Dali::Equals(zFar, gltf2::UNDEFINED_FLOAT_VALUE))
217     {
218       camera.SetFarClippingPlane(zFar);
219     }
220     else
221     {
222       // TODO : Infinite perspective projection didn't support yet. Just set big enough value now
223       camera.SetFarClippingPlane(1000.0f);
224     }
225
226     if(!Dali::Equals(aspectRatio, gltf2::UNDEFINED_FLOAT_VALUE))
227     {
228       // TODO: By gltf 2.0 spec, we should not 'crop' and 'non-uniform scaling' by viewport.
229       // If we skip to setup this value, 'non-uniform scaling' problem fixed.
230       // But we need to resolve 'crop' case in future.
231       //camera.SetAspectRatio(aspectRatio);
232     }
233   }
234   else
235   {
236     if(Dali::Equals(zNear, gltf2::UNDEFINED_FLOAT_VALUE) ||
237        Dali::Equals(zFar, gltf2::UNDEFINED_FLOAT_VALUE) ||
238        Dali::Equals(orthographicSize, gltf2::UNDEFINED_FLOAT_VALUE))
239     {
240       return false;
241     }
242
243     camera.SetProjectionMode(Camera::ORTHOGRAPHIC_PROJECTION);
244     camera.SetNearClippingPlane(zNear);
245     camera.SetFarClippingPlane(zFar);
246     camera.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, orthographicSize);
247
248     if(!Dali::Equals(aspectRatio, gltf2::UNDEFINED_FLOAT_VALUE))
249     {
250       // TODO: By gltf 2.0 spec, we should not 'crop' and 'non-uniform scaling' by viewport.
251       // If we skip to setup this value, 'non-uniform scaling' problem fixed.
252       // But we need to resolve 'crop' case in future.
253       //camera.SetAspectRatio(aspectRatio);
254     }
255   }
256
257   SetActorCentered(camera);
258
259   // model
260   Vector3    camTranslation;
261   Vector3    camScale;
262   Quaternion camOrientation;
263   CalculateTransformComponents(camTranslation, camOrientation, camScale);
264
265   camera.SetInvertYAxis(invertY);
266   camera.SetProperty(Actor::Property::POSITION, camTranslation);
267   camera.SetProperty(Actor::Property::ORIENTATION, camOrientation);
268   camera.SetProperty(Actor::Property::SCALE, camScale);
269
270   return true;
271 }
272
273 } // namespace Loader
274 } // namespace Scene3D
275 } // namespace Dali