quatLerp: Spherical Quaternion Interpolation
Spherical Linear Interpolation Algorithm
The quatLerp function implements spherical linear interpolation (SLERP) between two quaternions. This algorithm provides smooth rotation blending by interpolating along the shortest path on the 4D unit sphere, maintaining constant angular velocity.
Mathematical Definition: For quaternions and with interpolation parameter :
Where represents the angular separation between quaternions.
Algorithm Steps:
- Calculate dot product to determine angular separation
- Handle quaternion sign to choose shortest path
- Apply trigonometric ratios for spherical interpolation
- Normalize result to maintain unit quaternion properties
This function ensures smooth rotation transitions without gimbal lock or unwanted rotation artifacts.
ライブエディター
const fragment = () => { const t = iTime.mul(0.5) const phase = t.mod(2) const lerpT = phase.select(float(2).sub(phase), phase.lessThan(1)) const qa = vec4(0, 0, 0, 1) const qb = vec4(float(1.57).sin(), 0, 0, float(1.57).cos()).normalize() const interpolated = quatLerp(qa, qb, lerpT) const rotMatrix = quat2mat3(interpolated) const coords = uv.sub(0.5).mul(4) const rotated = rotMatrix.mul(vec3(coords, 0)) const pattern = rotated.x.mul(rotated.y).mul(6).sin().abs() const color = vec3(pattern.mul(0.8), pattern, pattern.mul(0.6)) return vec4(color, 1) }
Multi-Point Rotation Sequence
This example demonstrates quaternion interpolation across multiple rotation targets, creating smooth animation sequences through spherical linear interpolation chains.
ライブエディター
const fragment = () => { const cellPos = uv.mul(6) const cell = cellPos.floor() const local = cellPos.fract().sub(0.5) const hash = cell.x.mul(127.1).add(cell.y.mul(311.7)).sin().mul(43758.5).fract() const timeOffset = hash.mul(6.28) const phase = iTime.add(timeOffset).mul(0.3).mod(4) const segmentT = phase.fract() const q1 = quatIdentity() const q2 = vec4(hash.mul(3.14).sin(), 0, 0, hash.mul(3.14).cos()).normalize() const q3 = vec4(0, hash.mul(1.57).sin(), 0, hash.mul(1.57).cos()).normalize() const q4 = vec4(0, 0, hash.mul(2.35).sin(), hash.mul(2.35).cos()).normalize() const segment = phase.floor() const qa = q1.select(q2.select(q3.select(q4, segment.lessThan(3)), segment.lessThan(2)), segment.lessThan(1)) const qb = q2.select(q3.select(q4.select(q1, segment.lessThan(3)), segment.lessThan(2)), segment.lessThan(1)) const blended = quatLerp(qa, qb, segmentT) const transform = quat2mat3(blended).mul(vec3(local, hash)) const field = transform.length().mul(8).sin().abs() const color = vec3(field.mul(0.9), field.mul(0.7), field) return vec4(color, 1) }