local function solve(root, target, control, lengths) local T = vec3(target - root) local C = vec3(control - root) local R = vec3(0) -- Basis local bx = vec3(T):normalize() local by = (C - bx * (C:dot(bx))):normalize() local bz = vec3(bx):cross(by) -- Matrix from basis local transform = mat4( bx.x, by.x, bz.x, 0, bx.y, by.y, bz.y, 0, bx.z, by.z, bz.z, 0, 0, 0, 0, 1 ):transpose() local distance = #T local x = (distance + (lengths[1] ^ 2 - lengths[2] ^ 2) / distance) / 2 local y = math.sqrt(lengths[1] ^ 2 - x ^ 2) local solution = vec4(x, y, 0, 1) return root + (transform * solution).xyz end function lovr.load() boneLengths = { .3, .3 } root = lovr.math.newVec3(-.2, 1.5, -.5) target = lovr.math.newVec3(.2, 1.5, -.7) control = lovr.math.newVec3(0, 1.8, -.6) pointSize = .04 drags = {} end function lovr.update(dt) -- Allow hands to drag any of the points local points = { root, target, control } for i, hand in ipairs(lovr.headset.getHands()) do local handPosition = vec3(lovr.headset.getPosition(hand .. '/point')) if lovr.headset.wasPressed(hand, 'trigger') then for j, point in ipairs(points) do if handPosition:distance(point) < pointSize then drags[hand] = point end end elseif lovr.headset.wasReleased(hand, 'trigger') then drags[hand] = nil end if drags[hand] then drags[hand]:set(handPosition) end end end function lovr.draw(pass) -- 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 pass:cube(mat4(lovr.headset.getPose(hand .. '/point')):scale(.01)) 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