Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/math/basis.h
9903 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
Vector3 rows[3] = {
38
Vector3(1, 0, 0),
39
Vector3(0, 1, 0),
40
Vector3(0, 0, 1)
41
};
42
43
constexpr const Vector3 &operator[](int p_row) const {
44
return rows[p_row];
45
}
46
constexpr Vector3 &operator[](int p_row) {
47
return rows[p_row];
48
}
49
50
void invert();
51
void transpose();
52
53
Basis inverse() const;
54
Basis transposed() const;
55
56
_FORCE_INLINE_ real_t determinant() const;
57
58
void rotate(const Vector3 &p_axis, real_t p_angle);
59
Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
60
61
void rotate_local(const Vector3 &p_axis, real_t p_angle);
62
Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
63
64
void rotate(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ);
65
Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ) const;
66
67
void rotate(const Quaternion &p_quaternion);
68
Basis rotated(const Quaternion &p_quaternion) const;
69
70
Vector3 get_euler_normalized(EulerOrder p_order = EulerOrder::YXZ) const;
71
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
72
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
73
Quaternion get_rotation_quaternion() const;
74
75
void rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction);
76
77
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
78
79
Vector3 get_euler(EulerOrder p_order = EulerOrder::YXZ) const;
80
void set_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ);
81
static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ) {
82
Basis b;
83
b.set_euler(p_euler, p_order);
84
return b;
85
}
86
87
Quaternion get_quaternion() const;
88
void set_quaternion(const Quaternion &p_quaternion);
89
90
void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const;
91
void set_axis_angle(const Vector3 &p_axis, real_t p_angle);
92
93
void scale(const Vector3 &p_scale);
94
Basis scaled(const Vector3 &p_scale) const;
95
96
void scale_local(const Vector3 &p_scale);
97
Basis scaled_local(const Vector3 &p_scale) const;
98
99
void scale_orthogonal(const Vector3 &p_scale);
100
Basis scaled_orthogonal(const Vector3 &p_scale) const;
101
real_t get_uniform_scale() const;
102
103
Vector3 get_scale() const;
104
Vector3 get_scale_abs() const;
105
Vector3 get_scale_global() const;
106
107
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
108
void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EulerOrder::YXZ);
109
void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
110
111
// transposed dot products
112
_FORCE_INLINE_ real_t tdotx(const Vector3 &p_v) const {
113
return rows[0][0] * p_v[0] + rows[1][0] * p_v[1] + rows[2][0] * p_v[2];
114
}
115
_FORCE_INLINE_ real_t tdoty(const Vector3 &p_v) const {
116
return rows[0][1] * p_v[0] + rows[1][1] * p_v[1] + rows[2][1] * p_v[2];
117
}
118
_FORCE_INLINE_ real_t tdotz(const Vector3 &p_v) const {
119
return rows[0][2] * p_v[0] + rows[1][2] * p_v[1] + rows[2][2] * p_v[2];
120
}
121
122
bool is_equal_approx(const Basis &p_basis) const;
123
bool is_same(const Basis &p_basis) const;
124
bool is_finite() const;
125
126
constexpr bool operator==(const Basis &p_matrix) const;
127
constexpr bool operator!=(const Basis &p_matrix) const;
128
129
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const;
130
_FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const;
131
_FORCE_INLINE_ void operator*=(const Basis &p_matrix);
132
_FORCE_INLINE_ Basis operator*(const Basis &p_matrix) const;
133
constexpr void operator+=(const Basis &p_matrix);
134
constexpr Basis operator+(const Basis &p_matrix) const;
135
constexpr void operator-=(const Basis &p_matrix);
136
constexpr Basis operator-(const Basis &p_matrix) const;
137
constexpr void operator*=(real_t p_val);
138
constexpr Basis operator*(real_t p_val) const;
139
constexpr void operator/=(real_t p_val);
140
constexpr Basis operator/(real_t p_val) const;
141
142
bool is_orthogonal() const;
143
bool is_orthonormal() const;
144
bool is_conformal() const;
145
bool is_diagonal() const;
146
bool is_rotation() const;
147
148
Basis lerp(const Basis &p_to, real_t p_weight) const;
149
Basis slerp(const Basis &p_to, real_t p_weight) const;
150
void rotate_sh(real_t *p_values);
151
152
explicit operator String() const;
153
154
/* create / set */
155
156
_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) {
157
rows[0][0] = p_xx;
158
rows[0][1] = p_xy;
159
rows[0][2] = p_xz;
160
rows[1][0] = p_yx;
161
rows[1][1] = p_yy;
162
rows[1][2] = p_yz;
163
rows[2][0] = p_zx;
164
rows[2][1] = p_zy;
165
rows[2][2] = p_zz;
166
}
167
_FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) {
168
set_column(0, p_x);
169
set_column(1, p_y);
170
set_column(2, p_z);
171
}
172
173
_FORCE_INLINE_ Vector3 get_column(int p_index) const {
174
// Get actual basis axis column (we store transposed as rows for performance).
175
return Vector3(rows[0][p_index], rows[1][p_index], rows[2][p_index]);
176
}
177
178
_FORCE_INLINE_ void set_column(int p_index, const Vector3 &p_value) {
179
// Set actual basis axis column (we store transposed as rows for performance).
180
rows[0][p_index] = p_value.x;
181
rows[1][p_index] = p_value.y;
182
rows[2][p_index] = p_value.z;
183
}
184
185
_FORCE_INLINE_ Vector3 get_main_diagonal() const {
186
return Vector3(rows[0][0], rows[1][1], rows[2][2]);
187
}
188
189
_FORCE_INLINE_ void set_zero() {
190
rows[0].zero();
191
rows[1].zero();
192
rows[2].zero();
193
}
194
195
_FORCE_INLINE_ Basis transpose_xform(const Basis &p_m) const {
196
return Basis(
197
rows[0].x * p_m[0].x + rows[1].x * p_m[1].x + rows[2].x * p_m[2].x,
198
rows[0].x * p_m[0].y + rows[1].x * p_m[1].y + rows[2].x * p_m[2].y,
199
rows[0].x * p_m[0].z + rows[1].x * p_m[1].z + rows[2].x * p_m[2].z,
200
rows[0].y * p_m[0].x + rows[1].y * p_m[1].x + rows[2].y * p_m[2].x,
201
rows[0].y * p_m[0].y + rows[1].y * p_m[1].y + rows[2].y * p_m[2].y,
202
rows[0].y * p_m[0].z + rows[1].y * p_m[1].z + rows[2].y * p_m[2].z,
203
rows[0].z * p_m[0].x + rows[1].z * p_m[1].x + rows[2].z * p_m[2].x,
204
rows[0].z * p_m[0].y + rows[1].z * p_m[1].y + rows[2].z * p_m[2].y,
205
rows[0].z * p_m[0].z + rows[1].z * p_m[1].z + rows[2].z * p_m[2].z);
206
}
207
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) :
208
rows{
209
{ p_xx, p_xy, p_xz },
210
{ p_yx, p_yy, p_yz },
211
{ p_zx, p_zy, p_zz },
212
} {}
213
214
void orthonormalize();
215
Basis orthonormalized() const;
216
217
void orthogonalize();
218
Basis orthogonalized() const;
219
220
#ifdef MATH_CHECKS
221
bool is_symmetric() const;
222
#endif
223
Basis diagonalize();
224
225
operator Quaternion() const { return get_quaternion(); }
226
227
static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0), bool p_use_model_front = false);
228
229
Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }
230
Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); }
231
232
Basis(const Vector3 &p_axis, real_t p_angle) { set_axis_angle(p_axis, p_angle); }
233
Basis(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_angle, p_scale); }
234
static Basis from_scale(const Vector3 &p_scale);
235
236
constexpr Basis(const Vector3 &p_x_axis, const Vector3 &p_y_axis, const Vector3 &p_z_axis) :
237
rows{
238
{ p_x_axis.x, p_y_axis.x, p_z_axis.x },
239
{ p_x_axis.y, p_y_axis.y, p_z_axis.y },
240
{ p_x_axis.z, p_y_axis.z, p_z_axis.z },
241
} {}
242
243
Basis() = default;
244
245
private:
246
// Helper method.
247
void _set_diagonal(const Vector3 &p_diag);
248
};
249
250
constexpr bool Basis::operator==(const Basis &p_matrix) const {
251
for (int i = 0; i < 3; i++) {
252
for (int j = 0; j < 3; j++) {
253
if (rows[i][j] != p_matrix.rows[i][j]) {
254
return false;
255
}
256
}
257
}
258
259
return true;
260
}
261
262
constexpr bool Basis::operator!=(const Basis &p_matrix) const {
263
return (!(*this == p_matrix));
264
}
265
266
_FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) {
267
set(
268
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
269
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
270
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
271
}
272
273
_FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const {
274
return Basis(
275
p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]),
276
p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]),
277
p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2]));
278
}
279
280
constexpr void Basis::operator+=(const Basis &p_matrix) {
281
rows[0] += p_matrix.rows[0];
282
rows[1] += p_matrix.rows[1];
283
rows[2] += p_matrix.rows[2];
284
}
285
286
constexpr Basis Basis::operator+(const Basis &p_matrix) const {
287
Basis ret(*this);
288
ret += p_matrix;
289
return ret;
290
}
291
292
constexpr void Basis::operator-=(const Basis &p_matrix) {
293
rows[0] -= p_matrix.rows[0];
294
rows[1] -= p_matrix.rows[1];
295
rows[2] -= p_matrix.rows[2];
296
}
297
298
constexpr Basis Basis::operator-(const Basis &p_matrix) const {
299
Basis ret(*this);
300
ret -= p_matrix;
301
return ret;
302
}
303
304
constexpr void Basis::operator*=(real_t p_val) {
305
rows[0] *= p_val;
306
rows[1] *= p_val;
307
rows[2] *= p_val;
308
}
309
310
constexpr Basis Basis::operator*(real_t p_val) const {
311
Basis ret(*this);
312
ret *= p_val;
313
return ret;
314
}
315
316
constexpr void Basis::operator/=(real_t p_val) {
317
rows[0] /= p_val;
318
rows[1] /= p_val;
319
rows[2] /= p_val;
320
}
321
322
constexpr Basis Basis::operator/(real_t p_val) const {
323
Basis ret(*this);
324
ret /= p_val;
325
return ret;
326
}
327
328
Vector3 Basis::xform(const Vector3 &p_vector) const {
329
return Vector3(
330
rows[0].dot(p_vector),
331
rows[1].dot(p_vector),
332
rows[2].dot(p_vector));
333
}
334
335
Vector3 Basis::xform_inv(const Vector3 &p_vector) const {
336
return Vector3(
337
(rows[0][0] * p_vector.x) + (rows[1][0] * p_vector.y) + (rows[2][0] * p_vector.z),
338
(rows[0][1] * p_vector.x) + (rows[1][1] * p_vector.y) + (rows[2][1] * p_vector.z),
339
(rows[0][2] * p_vector.x) + (rows[1][2] * p_vector.y) + (rows[2][2] * p_vector.z));
340
}
341
342
real_t Basis::determinant() const {
343
return rows[0][0] * (rows[1][1] * rows[2][2] - rows[2][1] * rows[1][2]) -
344
rows[1][0] * (rows[0][1] * rows[2][2] - rows[2][1] * rows[0][2]) +
345
rows[2][0] * (rows[0][1] * rows[1][2] - rows[1][1] * rows[0][2]);
346
}
347
348