Skip to documentation
SLOP

tiny.rig.blend

Reference tiny.rig blend

Defined in tiny.rig.

Blending two poses, and crossfading from one clip to another.

API (5)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callstiny.rigblend
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callstest; no linkfun.rig.src.blendtest: blend endpoints return their po...blendposes
Static calls · unresolved targets: 0 · external targets: 2.

Source: fun/rig/src/blend.zig

zig
//! Blending two poses, and crossfading from one clip to another.//!//! A blend takes the shortest-arc spherical interpolation of each joint's//! rotation and the linear interpolation of its translation. Weights at or//! below zero return the first pose and weights at or above one return the//! second, exactly.const std = @import("std");const transform = @import("transform.zig");const assert = std.debug.assert;const Transform = transform.Transform;/// `out` may alias `from` or `to`.pub fn poses(from: []const Transform, to: []const Transform, weight: f32, out: []Transform) void {    assert(to.len == from.len);    assert(out.len == from.len);    assert(!std.math.isNan(weight));    if (weight <= 0) {        if (out.ptr != from.ptr) @memcpy(out, from);        return;    }    if (weight >= 1) {        if (out.ptr != to.ptr) @memcpy(out, to);        return;    }    for (from, to, out) |a, b, *mixed| {        mixed.* = .{            .translation = a.translation.lerp(b.translation, weight),            .rotation = a.rotation.slerp(b.rotation, weight),        };    }}/// A linear crossfade: the weight of the incoming pose rises from zero to/// one over `duration` seconds.pub const Crossfade = struct {    duration: f32,    elapsed: f32 = 0,    pub fn advance(crossfade: *Crossfade, seconds: f32) void {        assert(std.math.isFinite(seconds));        crossfade.elapsed += seconds;    }    pub fn weight(crossfade: Crossfade) f32 {        assert(!std.math.isNan(crossfade.duration));        if (!(crossfade.duration > 0)) return 1;        return std.math.clamp(crossfade.elapsed / crossfade.duration, 0, 1);    }    pub fn done(crossfade: Crossfade) bool {        return crossfade.weight() >= 1;    }};test "blend endpoints return their poses and the middle interpolates" {    const from = [_]Transform{.{ .translation = .{ .x = 0 } }};    const to = [_]Transform{.{        .translation = .{ .x = 2 },        .rotation = transform.quatFromAxisAngle(.{ .z = 1 }, 1),    }};    var out: [1]Transform = undefined;    poses(&from, &to, 0, &out);    try std.testing.expectEqual(from[0], out[0]);    poses(&from, &to, 1, &out);    try std.testing.expectEqual(to[0], out[0]);    poses(&from, &to, 0.5, &out);    try std.testing.expectApproxEqAbs(@as(f32, 1), out[0].translation.x, 1e-6);    const half = transform.quatFromAxisAngle(.{ .z = 1 }, 0.5);    try std.testing.expectApproxEqAbs(half.z, out[0].rotation.z, 1e-6);}test "a crossfade reaches its target and a zero duration cuts" {    var crossfade = Crossfade{ .duration = 0.2 };    crossfade.advance(0.1);    try std.testing.expectApproxEqAbs(@as(f32, 0.5), crossfade.weight(), 1e-6);    crossfade.advance(0.2);    try std.testing.expect(crossfade.done());    try std.testing.expectEqual(@as(f32, 1), (Crossfade{ .duration = 0 }).weight());}

Source: fun/rig/src/root.zig:22

zig
pub const blend = @import("blend.zig");

Audit

Definitions6
Public names6
Members2
Version26.7.0
Revisiondaab053ee433