0
# Quaternion Operations
1
2
Efficient 3D rotation representation using quaternions. Quaternions provide smooth interpolation, avoid gimbal lock, and offer compact storage for rotations in 3D graphics and physics applications.
3
4
## Capabilities
5
6
### Quaternion Types
7
8
PyGLM provides quaternion types in different precisions for various performance and accuracy requirements.
9
10
```python { .api }
11
class quat:
12
"""
13
Single-precision quaternion for 3D rotations.
14
Components: w (scalar), x, y, z (vector)
15
"""
16
w: float # Scalar component
17
x: float # X vector component
18
y: float # Y vector component
19
z: float # Z vector component
20
21
def __init__(self): ... # Identity quaternion (0, 0, 0, 1)
22
def __init__(self, w: float, x: float, y: float, z: float): ... # From components
23
def __init__(self, v: vec3): ... # From Euler angles
24
def __init__(self, m: mat3): ... # From rotation matrix
25
def __init__(self, m: mat4): ... # From transformation matrix
26
27
class dquat:
28
"""
29
Double-precision quaternion for high-accuracy rotations.
30
Components: w (scalar), x, y, z (vector)
31
"""
32
w: float # Scalar component (double precision)
33
x: float # X vector component (double precision)
34
y: float # Y vector component (double precision)
35
z: float # Z vector component (double precision)
36
37
def __init__(self): ... # Identity quaternion
38
def __init__(self, w: float, x: float, y: float, z: float): ...
39
def __init__(self, v: vec3): ... # From Euler angles
40
def __init__(self, m: mat3): ... # From rotation matrix
41
def __init__(self, m: mat4): ... # From transformation matrix
42
```
43
44
### Quaternion Construction
45
46
Functions for creating quaternions from various rotation representations.
47
48
```python { .api }
49
def angleAxis(angle, axis):
50
"""
51
Create a quaternion from an angle and rotation axis.
52
53
Args:
54
angle: Rotation angle in radians
55
axis: Rotation axis vector (vec3, should be normalized)
56
57
Returns:
58
Quaternion representing the rotation
59
60
Example:
61
q = glm.angleAxis(glm.radians(45), glm.vec3(0, 1, 0)) # 45° around Y-axis
62
"""
63
64
def quatLookAt(direction, up):
65
"""
66
Create a quaternion that rotates to look in a specific direction.
67
68
Args:
69
direction: Direction to look toward (vec3, will be normalized)
70
up: Up vector (vec3, will be normalized)
71
72
Returns:
73
Quaternion representing the look-at rotation
74
"""
75
76
def euler(angles):
77
"""
78
Create a quaternion from Euler angles.
79
80
Args:
81
angles: Euler angles in radians (vec3: pitch, yaw, roll)
82
83
Returns:
84
Quaternion representing the combined rotation
85
86
Example:
87
q = glm.euler(glm.vec3(glm.radians(15), glm.radians(30), glm.radians(45)))
88
"""
89
```
90
91
### Quaternion Operations
92
93
Core quaternion mathematics including arithmetic, normalization, and conjugation.
94
95
```python { .api }
96
def normalize(q):
97
"""
98
Normalize a quaternion to unit length.
99
100
Args:
101
q: Quaternion to normalize
102
103
Returns:
104
Normalized quaternion (unit quaternion)
105
106
Note:
107
Unit quaternions represent pure rotations
108
"""
109
110
def conjugate(q):
111
"""
112
Calculate the conjugate of a quaternion.
113
114
Args:
115
q: Input quaternion
116
117
Returns:
118
Conjugate quaternion (negated vector part)
119
120
Note:
121
For unit quaternions, conjugate equals inverse
122
"""
123
124
def inverse(q):
125
"""
126
Calculate the inverse of a quaternion.
127
128
Args:
129
q: Input quaternion
130
131
Returns:
132
Inverse quaternion
133
"""
134
135
def length(q):
136
"""
137
Calculate the length (magnitude) of a quaternion.
138
139
Args:
140
q: Input quaternion
141
142
Returns:
143
Scalar length of the quaternion
144
"""
145
146
def dot(q1, q2):
147
"""
148
Calculate the dot product of two quaternions.
149
150
Args:
151
q1: First quaternion
152
q2: Second quaternion
153
154
Returns:
155
Scalar dot product
156
"""
157
```
158
159
### Quaternion Interpolation
160
161
Smooth interpolation functions for animation and smooth transitions between rotations.
162
163
```python { .api }
164
def slerp(x, y, a):
165
"""
166
Spherical linear interpolation between two quaternions.
167
168
Args:
169
x: Start quaternion
170
y: End quaternion
171
a: Interpolation factor (0.0 = x, 1.0 = y)
172
173
Returns:
174
Interpolated quaternion with constant angular velocity
175
176
Note:
177
SLERP provides the shortest rotation path between quaternions
178
"""
179
180
def lerp(x, y, a):
181
"""
182
Linear interpolation between two quaternions.
183
184
Args:
185
x: Start quaternion
186
y: End quaternion
187
a: Interpolation factor (0.0 = x, 1.0 = y)
188
189
Returns:
190
Linearly interpolated quaternion (requires normalization)
191
192
Note:
193
Faster than SLERP but doesn't maintain constant angular velocity
194
"""
195
196
def mix(x, y, a):
197
"""
198
Alias for lerp - linear interpolation between quaternions.
199
200
Args:
201
x: Start quaternion
202
y: End quaternion
203
a: Interpolation factor
204
205
Returns:
206
Linearly interpolated quaternion
207
"""
208
```
209
210
### Matrix Conversion
211
212
Functions for converting between quaternions and rotation matrices.
213
214
```python { .api }
215
def mat3_cast(q):
216
"""
217
Convert a quaternion to a 3×3 rotation matrix.
218
219
Args:
220
q: Quaternion to convert
221
222
Returns:
223
3×3 rotation matrix equivalent to the quaternion
224
225
Example:
226
rotation_matrix = glm.mat3_cast(quaternion)
227
"""
228
229
def mat4_cast(q):
230
"""
231
Convert a quaternion to a 4×4 transformation matrix.
232
233
Args:
234
q: Quaternion to convert
235
236
Returns:
237
4×4 transformation matrix with rotation and identity translation
238
239
Example:
240
transform_matrix = glm.mat4_cast(quaternion)
241
"""
242
243
def quat_cast(m):
244
"""
245
Convert a rotation matrix to a quaternion.
246
247
Args:
248
m: 3×3 or 4×4 rotation matrix
249
250
Returns:
251
Quaternion equivalent to the matrix rotation
252
253
Example:
254
quaternion = glm.quat_cast(rotation_matrix)
255
"""
256
```
257
258
### Euler Angle Conversion
259
260
Functions for converting between quaternions and Euler angle representations.
261
262
```python { .api }
263
def eulerAngles(q):
264
"""
265
Extract Euler angles from a quaternion.
266
267
Args:
268
q: Input quaternion
269
270
Returns:
271
vec3 containing Euler angles in radians (pitch, yaw, roll)
272
273
Example:
274
angles = glm.eulerAngles(quaternion)
275
pitch = angles.x
276
yaw = angles.y
277
roll = angles.z
278
"""
279
280
def pitch(q):
281
"""
282
Extract the pitch angle from a quaternion.
283
284
Args:
285
q: Input quaternion
286
287
Returns:
288
Pitch angle in radians (rotation around X-axis)
289
"""
290
291
def yaw(q):
292
"""
293
Extract the yaw angle from a quaternion.
294
295
Args:
296
q: Input quaternion
297
298
Returns:
299
Yaw angle in radians (rotation around Y-axis)
300
"""
301
302
def roll(q):
303
"""
304
Extract the roll angle from a quaternion.
305
306
Args:
307
q: Input quaternion
308
309
Returns:
310
Roll angle in radians (rotation around Z-axis)
311
"""
312
313
def angle(q):
314
"""
315
Extract the rotation angle from a quaternion.
316
317
Args:
318
q: Input quaternion
319
320
Returns:
321
Rotation angle in radians
322
"""
323
324
def axis(q):
325
"""
326
Extract the rotation axis from a quaternion.
327
328
Args:
329
q: Input quaternion
330
331
Returns:
332
vec3 representing the normalized rotation axis
333
"""
334
```
335
336
### Quaternion Arithmetic
337
338
All quaternion types support standard arithmetic operations through operator overloading:
339
340
- **Addition**: `q1 + q2` - Component-wise addition
341
- **Subtraction**: `q1 - q2` - Component-wise subtraction
342
- **Multiplication**: `q1 * q2` - Quaternion multiplication (composition of rotations)
343
- **Scalar Multiplication**: `q * scalar` - Scale quaternion components
344
- **Negation**: `-q` - Component-wise negation
345
- **Equality**: `q1 == q2`, `q1 != q2` - Component-wise equality
346
347
### Usage Examples
348
349
```python
350
from pyglm import glm
351
import math
352
353
# === Basic Quaternion Creation ===
354
355
# Identity quaternion (no rotation)
356
identity_quat = glm.quat()
357
358
# From explicit components (w, x, y, z)
359
explicit_quat = glm.quat(0.707, 0.0, 0.707, 0.0) # 90° around Y-axis
360
361
# From angle and axis
362
angle = glm.radians(45)
363
axis = glm.vec3(0, 1, 0) # Y-axis
364
angle_axis_quat = glm.angleAxis(angle, axis)
365
366
# From Euler angles (pitch, yaw, roll)
367
euler_angles = glm.vec3(glm.radians(15), glm.radians(30), glm.radians(45))
368
euler_quat = glm.euler(euler_angles)
369
370
# === Quaternion Operations ===
371
372
# Normalize quaternion (essential for rotations)
373
normalized_quat = glm.normalize(angle_axis_quat)
374
375
# Quaternion multiplication (combines rotations)
376
q1 = glm.angleAxis(glm.radians(30), glm.vec3(1, 0, 0)) # 30° around X
377
q2 = glm.angleAxis(glm.radians(45), glm.vec3(0, 1, 0)) # 45° around Y
378
combined_rotation = q2 * q1 # Apply q1 first, then q2
379
380
# Conjugate (inverse for unit quaternions)
381
inverse_rotation = glm.conjugate(normalized_quat)
382
383
# === Quaternion Interpolation for Animation ===
384
385
# SLERP for smooth rotation animation
386
start_quat = glm.angleAxis(glm.radians(0), glm.vec3(0, 1, 0))
387
end_quat = glm.angleAxis(glm.radians(90), glm.vec3(0, 1, 0))
388
389
# Animate from 0° to 90° over time
390
animation_time = 0.5 # 50% through animation
391
interpolated_quat = glm.slerp(start_quat, end_quat, animation_time)
392
393
# === Matrix Conversion ===
394
395
# Convert quaternion to rotation matrix
396
rotation_quat = glm.angleAxis(glm.radians(45), glm.vec3(0, 0, 1))
397
rotation_matrix_3x3 = glm.mat3_cast(rotation_quat)
398
rotation_matrix_4x4 = glm.mat4_cast(rotation_quat)
399
400
# Convert matrix back to quaternion
401
recovered_quat = glm.quat_cast(rotation_matrix_3x3)
402
403
# === Euler Angle Extraction ===
404
405
# Get Euler angles from quaternion
406
quaternion = glm.angleAxis(glm.radians(45), glm.vec3(1, 1, 0))
407
euler_angles = glm.eulerAngles(quaternion)
408
409
pitch_degrees = glm.degrees(euler_angles.x)
410
yaw_degrees = glm.degrees(euler_angles.y)
411
roll_degrees = glm.degrees(euler_angles.z)
412
413
# Extract individual components
414
pitch_rad = glm.pitch(quaternion)
415
yaw_rad = glm.yaw(quaternion)
416
roll_rad = glm.roll(quaternion)
417
418
# Extract angle and axis
419
rotation_angle = glm.angle(quaternion)
420
rotation_axis = glm.axis(quaternion)
421
422
# === Practical 3D Graphics Example ===
423
424
# Create a first-person camera rotation system
425
class FirstPersonCamera:
426
def __init__(self):
427
self.orientation = glm.quat() # Identity quaternion
428
self.sensitivity = 0.002 # Mouse sensitivity
429
430
def rotate(self, mouse_delta_x, mouse_delta_y):
431
# Yaw rotation (around world Y-axis)
432
yaw_rotation = glm.angleAxis(-mouse_delta_x * self.sensitivity, glm.vec3(0, 1, 0))
433
434
# Pitch rotation (around local X-axis)
435
pitch_rotation = glm.angleAxis(-mouse_delta_y * self.sensitivity, glm.vec3(1, 0, 0))
436
437
# Apply rotations: pitch first (local), then yaw (world)
438
self.orientation = yaw_rotation * self.orientation * pitch_rotation
439
self.orientation = glm.normalize(self.orientation)
440
441
def get_view_matrix(self, position):
442
# Convert quaternion to rotation matrix
443
rotation_matrix = glm.mat4_cast(glm.conjugate(self.orientation))
444
445
# Apply translation
446
view_matrix = glm.translate(rotation_matrix, -position)
447
return view_matrix
448
449
# Usage
450
camera = FirstPersonCamera()
451
camera.rotate(0.1, 0.05) # Simulate mouse movement
452
view_matrix = camera.get_view_matrix(glm.vec3(0, 2, 5))
453
454
# === Character Animation Example ===
455
456
# Smooth rotation between two orientations
457
old_facing = glm.angleAxis(glm.radians(0), glm.vec3(0, 1, 0)) # North
458
new_facing = glm.angleAxis(glm.radians(90), glm.vec3(0, 1, 0)) # East
459
460
# Smoothly rotate character over 2 seconds
461
animation_duration = 2.0
462
current_time = 0.75 # 0.75 seconds into animation
463
t = current_time / animation_duration
464
465
current_facing = glm.slerp(old_facing, new_facing, t)
466
character_transform = glm.mat4_cast(current_facing)
467
468
# === Look-At Quaternion ===
469
470
target_position = glm.vec3(10, 0, 0)
471
current_position = glm.vec3(0, 0, 0)
472
up_vector = glm.vec3(0, 1, 0)
473
474
look_direction = glm.normalize(target_position - current_position)
475
look_at_quat = glm.quatLookAt(look_direction, up_vector)
476
look_at_matrix = glm.mat4_cast(look_at_quat)
477
```
478
479
### Quaternion Best Practices
480
481
1. **Always normalize quaternions** used for rotations to ensure they remain unit quaternions
482
2. **Use SLERP for smooth animation** between rotations to maintain constant angular velocity
483
3. **Prefer quaternion multiplication** over Euler angle arithmetic to avoid gimbal lock
484
4. **Store orientations as quaternions** and convert to matrices only when needed for rendering
485
5. **Use conjugate instead of inverse** for unit quaternions (more efficient)
486
6. **Be consistent with rotation order** when converting between Euler angles and quaternions