Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/math/basis.h
20943 views
1
/**************************************************************************/
2
/* basis.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "core/math/quaternion.h"
34
#include "core/math/vector3.h"
35
36
struct [[nodiscard]] Basis {
37
static const Basis FLIP_X;
38
static const Basis FLIP_Y;
39
static const Basis FLIP_Z;
40
41
Vector3 rows[3] = {
42
Vector3(1, 0, 0),
43
Vector3(0, 1, 0),
44
Vector3(0, 0, 1)
45
};
46
47
constexpr const Vector3 &operator[](int p_row) const {
48
return rows[p_row];
49
}
50
constexpr Vector3 &operator[](int p_row) {
51
return rows[p_row];
52
}
53
54
void invert();
55
void transpose();
56
57
Basis inverse() const;
58
Basis transposed() const;
59
60
_FORCE_INLINE_ real_t determinant() const;
61
62
void rotate(const Vector3 &p_axis, real_t p_angle);
63
Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
64
65
void rotate_local(const Vector3 &p_axis, real_t p_angle);
66
Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
67
68
void rotate(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ);
69
Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ) const;
70
71
void rotate(const Quaternion &p_quaternion);
72
Basis rotated(const Quaternion &p_quaternion) const;
73
74
Vector3 get_euler_normalized(EulerOrder p_order = EulerOrder::YXZ) const;
75
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
76
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
77
Quaternion get_rotation_quaternion() const;
78
79
void rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction);
80
81
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
82
83
Vector3 get_euler(EulerOrder p_order = EulerOrder::YXZ) const;
84
void set_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ);
85
static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ) {
86
Basis b;
87
b.set_euler(p_euler, p_order);
88
return b;
89
}
90
91
Quaternion get_quaternion() const;
92
void set_quaternion(const Quaternion &p_quaternion);
93
94
void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const;
95
void set_axis_angle(const Vector3 &p_axis, real_t p_angle);
96
97
void scale(const Vector3 &p_scale);
98
Basis scaled(const Vector3 &p_scale) const;
99
100
void scale_local(const Vector3 &p_scale);
101
Basis scaled_local(const Vector3 &p_scale) const;
102
103
void scale_orthogonal(const Vector3 &p_scale);
104
Basis scaled_orthogonal(const Vector3 &p_scale) const;
105
real_t get_uniform_scale() const;
106
107
Vector3 get_scale() const;
108
Vector3 get_scale_abs() const;
109
Vector3 get_scale_global() const;
110
111
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
112
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EulerOrder::YXZ);
113
void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
114
115
// transposed dot products
116
_FORCE_INLINE_ real_t tdotx(const Vector3 &p_v) const {
117
return rows[0][0] * p_v[0] + rows[1][0] * p_v[1] + rows[2][0] * p_v[2];
118
}
119
_FORCE_INLINE_ real_t tdoty(const Vector3 &p_v) const {
120
return rows[0][1] * p_v[0] + rows[1][1] * p_v[1] + rows[2][1] * p_v[2];
121
}
122
_FORCE_INLINE_ real_t tdotz(const Vector3 &p_v) const {
123
return rows[0][2] * p_v[0] + rows[1][2] * p_v[1] + rows[2][2] * p_v[2];
124
}
125
126
bool is_equal_approx(const Basis &p_basis) const;
127
bool is_same(const Basis &p_basis) const;
128
bool is_finite() const;
129
130
constexpr bool operator==(const Basis &p_matrix) const;
131
constexpr bool operator!=(const Basis &p_matrix) const;
132
133
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const;
134
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const;
135
_FORCE_INLINE_ void operator*=(const Basis &p_matrix);
136
_FORCE_INLINE_ Basis operator*(const Basis &p_matrix) const;
137
constexpr void operator+=(const Basis &p_matrix);
138
constexpr Basis operator+(const Basis &p_matrix) const;
139
constexpr void operator-=(const Basis &p_matrix);
140
constexpr Basis operator-(const Basis &p_matrix) const;
141
constexpr void operator*=(real_t p_val);
142
constexpr Basis operator*(real_t p_val) const;
143
constexpr void operator/=(real_t p_val);
144
constexpr Basis operator/(real_t p_val) const;
145
146
bool is_orthogonal() const;
147
bool is_orthonormal() const;
148
bool is_conformal() const;
149
bool is_diagonal() const;
150
bool is_rotation() const;
151
152
Basis lerp(const Basis &p_to, real_t p_weight) const;
153
Basis slerp(const Basis &p_to, real_t p_weight) const;
154
void rotate_sh(real_t *p_values);
155
156
explicit operator String() const;
157
158
/* create / set */
159
160
_FORCE_INLINE_ void set(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) {
161
rows[0][0] = p_xx;
162
rows[0][1] = p_xy;
163
rows[0][2] = p_xz;
164
rows[1][0] = p_yx;
165
rows[1][1] = p_yy;
166
rows[1][2] = p_yz;
167
rows[2][0] = p_zx;
168
rows[2][1] = p_zy;
169
rows[2][2] = p_zz;
170
}
171
_FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) {
172
set_column(0, p_x);
173
set_column(1, p_y);
174
set_column(2, p_z);
175
}
176
177
_FORCE_INLINE_ Vector3 get_column(int p_index) const {
178
// Get actual basis axis column (we store transposed as rows for performance).
179
return Vector3(rows[0][p_index], rows[1][p_index], rows[2][p_index]);
180
}
181
182
_FORCE_INLINE_ void set_column(int p_index, const Vector3 &p_value) {
183
// Set actual basis axis column (we store transposed as rows for performance).
184
rows[0][p_index] = p_value.x;
185
rows[1][p_index] = p_value.y;
186
rows[2][p_index] = p_value.z;
187
}
188
189
_FORCE_INLINE_ Vector3 get_main_diagonal() const {
190
return Vector3(rows[0][0], rows[1][1], rows[2][2]);
191
}
192
193
_FORCE_INLINE_ void set_zero() {
194
rows[0].zero();
195
rows[1].zero();
196
rows[2].zero();
197
}
198
199
_FORCE_INLINE_ Basis transpose_xform(const Basis &p_m) const {
200
return Basis(
201
rows[0].x * p_m[0].x + rows[1].x * p_m[1].x + rows[2].x * p_m[2].x,
202
rows[0].x * p_m[0].y + rows[1].x * p_m[1].y + rows[2].x * p_m[2].y,
203
rows[0].x * p_m[0].z + rows[1].x * p_m[1].z + rows[2].x * p_m[2].z,
204
rows[0].y * p_m[0].x + rows[1].y * p_m[1].x + rows[2].y * p_m[2].x,
205
rows[0].y * p_m[0].y + rows[1].y * p_m[1].y + rows[2].y * p_m[2].y,
206
rows[0].y * p_m[0].z + rows[1].y * p_m[1].z + rows[2].y * p_m[2].z,
207
rows[0].z * p_m[0].x + rows[1].z * p_m[1].x + rows[2].z * p_m[2].x,
208
rows[0].z * p_m[0].y + rows[1].z * p_m[1].y + rows[2].z * p_m[2].y,
209
rows[0].z * p_m[0].z + rows[1].z * p_m[1].z + rows[2].z * p_m[2].z);
210
}
211
constexpr Basis(real_t p_xx, real_t p_xy, real_t p_xz, real_t p_yx, real_t p_yy, real_t p_yz, real_t p_zx, real_t p_zy, real_t p_zz) :
212
rows{
213
{ p_xx, p_xy, p_xz },
214
{ p_yx, p_yy, p_yz },
215
{ p_zx, p_zy, p_zz },
216
} {}
217
218
void orthonormalize();
219
Basis orthonormalized() const;
220
221
void orthogonalize();
222
Basis orthogonalized() const;
223
224
#ifdef MATH_CHECKS
225
bool is_symmetric() const;
226
#endif
227
Basis diagonalize();
228
229
operator Quaternion() const { return get_quaternion(); }
230
231
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3::UP, bool p_use_model_front = false);
232
233
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }
234
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
235
236
Basis(const Vector3 &p_axis, real_t p_angle) { set_axis_angle(p_axis, p_angle); }
237
Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); }
238
static Basis from_scale(const Vector3 &p_scale);
239
240
constexpr Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) :
241
rows{
242
{ p_x_axis.x, p_y_axis.x, p_z_axis.x },
243
{ p_x_axis.y, p_y_axis.y, p_z_axis.y },
244
{ p_x_axis.z, p_y_axis.z, p_z_axis.z },
245
} {}
246
247
Basis() = default;
248
249
private:
250
// Helper method.
251
void _set_diagonal(const Vector3 &p_diag);
252
};
253
254
inline constexpr Basis Basis::FLIP_X = { { -1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
255
inline constexpr Basis Basis::FLIP_Y = { { 1, 0, 0 }, { 0, -1, 0 }, { 0, 0, 1 } };
256
inline constexpr Basis Basis::FLIP_Z = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, -1 } };
257
258
constexpr bool Basis::operator==(const Basis &p_matrix) const {
259
for (int i = 0; i < 3; i++) {
260
for (int j = 0; j < 3; j++) {
261
if (rows[i][j] != p_matrix.rows[i][j]) {
262
return false;
263
}
264
}
265
}
266
267
return true;
268
}
269
270
constexpr bool Basis::operator!=(const Basis &p_matrix) const {
271
return (!(*this == p_matrix));
272
}
273
274
_FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) {
275
set(
276
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
277
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
278
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
279
}
280
281
_FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const {
282
return Basis(
283
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
284
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
285
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
286
}
287
288
constexpr void Basis::operator+=(const Basis &p_matrix) {
289
rows[0] += p_matrix.rows[0];
290
rows[1] += p_matrix.rows[1];
291
rows[2] += p_matrix.rows[2];
292
}
293
294
constexpr Basis Basis::operator+(const Basis &p_matrix) const {
295
Basis ret(*this);
296
ret += p_matrix;
297
return ret;
298
}
299
300
constexpr void Basis::operator-=(const Basis &p_matrix) {
301
rows[0] -= p_matrix.rows[0];
302
rows[1] -= p_matrix.rows[1];
303
rows[2] -= p_matrix.rows[2];
304
}
305
306
constexpr Basis Basis::operator-(const Basis &p_matrix) const {
307
Basis ret(*this);
308
ret -= p_matrix;
309
return ret;
310
}
311
312
constexpr void Basis::operator*=(real_t p_val) {
313
rows[0] *= p_val;
314
rows[1] *= p_val;
315
rows[2] *= p_val;
316
}
317
318
constexpr Basis Basis::operator*(real_t p_val) const {
319
Basis ret(*this);
320
ret *= p_val;
321
return ret;
322
}
323
324
constexpr void Basis::operator/=(real_t p_val) {
325
rows[0] /= p_val;
326
rows[1] /= p_val;
327
rows[2] /= p_val;
328
}
329
330
constexpr Basis Basis::operator/(real_t p_val) const {
331
Basis ret(*this);
332
ret /= p_val;
333
return ret;
334
}
335
336
Vector3 Basis::xform(const Vector3 &p_vector) const {
337
return Vector3(
338
rows[0].dot(p_vector),
339
rows[1].dot(p_vector),
340
rows[2].dot(p_vector));
341
}
342
343
Vector3 Basis::xform_inv(const Vector3 &p_vector) const {
344
return Vector3(
345
(rows[0][0] * p_vector.x) + (rows[1][0] * p_vector.y) + (rows[2][0] * p_vector.z),
346
(rows[0][1] * p_vector.x) + (rows[1][1] * p_vector.y) + (rows[2][1] * p_vector.z),
347
(rows[0][2] * p_vector.x) + (rows[1][2] * p_vector.y) + (rows[2][2] * p_vector.z));
348
}
349
350
real_t Basis::determinant() const {
351
return rows[0][0] * (rows[1][1] * rows[2][2] - rows[2][1] * rows[1][2]) -
352
rows[1][0] * (rows[0][1] * rows[2][2] - rows[2][1] * rows[0][2]) +
353
rows[2][0] * (rows[0][1] * rows[1][2] - rows[1][1] * rows[0][2]);
354
}
355
356