fix(puppet): store all bone angles in radians for render consistency

The pipeline now stores radians uniformly in bone_state, matching the
look-at branch's math.atan output and the render path's draw_rect_rotated
expectations. JSON degrees are converted at the boundary (build_animation,
write_bone). sample_animation returns radians.
This commit is contained in:
Axel Meyer
2026-05-17 20:17:06 +02:00
parent 34c53f9980
commit 475f60da21

View File

@@ -162,7 +162,7 @@ function M.build_animation(anim_table, rig)
.. "' which is not in animation's track '" .. anim_table.track .. "'") .. "' which is not in animation's track '" .. anim_table.track .. "'")
end end
cooked.bones[k] = { cooked.bones[k] = {
angle = v.angle or 0, -- keep in degrees; interpolation stays in degrees angle = math.rad(v.angle or 0), -- JSON degrees → radians for internal storage
} }
end end
end end
@@ -220,7 +220,6 @@ function M.sample_animation(anim, t)
local next_v = next_kf.bones[bid] local next_v = next_kf.bones[bid]
if prev_v and next_v then if prev_v and next_v then
frame[bid] = { frame[bid] = {
-- keyframe angles are stored in degrees; interpolate in degrees.
angle = prev_v.angle * (1 - alpha) + next_v.angle * alpha, angle = prev_v.angle * (1 - alpha) + next_v.angle * alpha,
} }
elseif prev_v then elseif prev_v then
@@ -334,8 +333,7 @@ function M.clear_look_target(handle)
end end
function M.bone_angle(handle, bone_id) function M.bone_angle(handle, bone_id)
-- Returns the raw stored angle: radians for look_at-driven bones, -- Returns the stored angle in radians (uniform across all channels).
-- degrees for keyframe- and procedural-driven bones.
return all_puppets[handle].bone_state[bone_id].angle return all_puppets[handle].bone_state[bone_id].angle
end end
@@ -370,9 +368,7 @@ function M.write_bone(handle, bone_id, values)
end end
end end
if values.angle ~= nil then if values.angle ~= nil then
-- Store the caller-supplied value directly; write_bone accepts degrees p.bone_state[bone_id].angle = math.rad(values.angle) -- caller passes degrees
-- (same units as rest-pose angles and keyframe angles).
p.bone_state[bone_id].angle = values.angle
end end
end end
@@ -411,9 +407,6 @@ function M.update(dt)
end end
local frame = M.sample_animation(anim, play_state.t) local frame = M.sample_animation(anim, play_state.t)
for bid, bone_kf in pairs(frame) do for bid, bone_kf in pairs(frame) do
-- sample_animation returns degrees; store directly (bone_state
-- uses degrees for keyframe/procedural channels, radians for
-- look_at which writes via math.atan).
p.bone_state[bid].angle = bone_kf.angle p.bone_state[bid].angle = bone_kf.angle
end end
end end