local transform = lovr.math.newMat4()
local function solve(root, target, control, lengths)
local T = target - root
local C = control - root
local R = vector(0)
-- Basis
local bx = T:normalize()
local by = (C - bx * C:dot(bx)):normalize()
local bz = bx:cross(by)
-- Matrix from basis
transform:set(
bx.x, bx.y, bx.z, 0,
by.x, by.y, by.z, 0,
bz.x, bz.y, bz.z, 0,
0, 0, 0, 1
)
local distance = T:length()
local x = (distance + (lengths[1] ^ 2 - lengths[2] ^ 2) / distance) / 2
local y = math.sqrt(lengths[1] ^ 2 - x ^ 2)
local solution = vector(x, y, 0)
return root + transform * solution
end
function lovr.load()
boneLengths = { .3, .3 }
points = {
root = vector(-.2, 1.5, -.5),
target = vector(.2, 1.5, -.7),
control = vector(0, 1.8, -.6)
}
pointSize = .04
drags = {}
end
function lovr.update(dt)
-- Allow hands to drag any of the points
for i, hand in ipairs(lovr.headset.getHands()) do
local handPosition = vector(lovr.headset.getPosition(hand .. '/point'))
if lovr.headset.wasPressed(hand, 'trigger') then
for k, point in pairs(points) do
if handPosition:distance(point) < pointSize then
drags[hand] = k
end
end
elseif lovr.headset.wasReleased(hand, 'trigger') then
drags[hand] = nil
end
if drags[hand] then
points[drags[hand]] = handPosition
end
end
end
function lovr.draw(pass)
local root, target, control = points.root, points.target, points.control
-- Draw the joints and the control point
pass:setColor(0xff80ff)
pass:sphere(root, pointSize / 2)
pass:sphere(target, pointSize / 2)
pass:setColor(0x80ffff)
pass:sphere(control, pointSize / 2)
-- Draw the hand
pass:setColor(0xffffff)
for _, hand in ipairs(lovr.headset.getHands()) do
local x, y, z, angle, ax, ay, az = lovr.headset.getPose(hand .. '/point')
pass:cube(x, y, z, .01, angle, ax, ay, az)
end
-- Draw a line from the root to the result from the IK solver, then to the target
pass:line(root, solve(root, target, control, boneLengths), target)
end