garrysmod-requests icon indicating copy to clipboard operation
garrysmod-requests copied to clipboard

IK controls for lua

Open Vuthakral opened this issue 1 year ago • 1 comments

Details

I won't pretend to have even a beginning understanding on how the Inverse Kinematics system in Source actually works under the hood, but I do know that natively they're just controlled by sequences of a model which tells them how to behave. Even something as simple as being able to target an IK by name and direct it to a given position would be a huge game changer for all kinds of systems.

I specifically want it to just be able to add left hand markers to my weapon worldmodels so that I can have players gripping weapons properly instead of their hand/arm clipping through the weapon with the hl2 smg/ar2 IK position, but it has potential for a lot of other uses as well.

Vuthakral avatar Sep 18 '24 14:09 Vuthakral

Create a model of a weapon with an attachment indicating the point of grip, make animation with ikrule attachment. Maybe it will work. Similar effects can be achieved with pose parameters. But all this requires new animations to be made. I doubt that there is an alternative. And i can't even imagine that something like this can be implemented in lua

Goldermor avatar Sep 21 '24 01:09 Goldermor

To this end, I've been poking around random Lua IK libraries online and found this one I yoinked from a Roblox forum post. I've translated it to GLua and it works nicely.

local IK = {}
IK.__index = IK

function IK.new(bones, solverIterations, targetPosition)
    local bonesLenght = {}

    for i = 1, #bones do
        if i >= #bones then
            bonesLenght[i] = 0
        else
            bonesLenght[i] = (bones[i]:GetPos() - bones[i + 1]:GetPos()):Length()
        end
    end

    return setmetatable(
        {
            bones = bones;
            solverIterations = solverIterations;
            targetPosition = targetPosition;
            bonesLenght = bonesLenght;
        },
        IK
    )
end

function IK:backward(forwardPosition)
    local inversePosition = {}

    for i = #forwardPosition, 1, -1 do
        if i == #forwardPosition then
            inversePosition[i] = self.targetPosition
        else
            local positionNext = inversePosition[i + 1]
            inversePosition[i] = positionNext + ((forwardPosition[i] - positionNext):GetNormalized() * self.bonesLenght[i])
        end
    end

    return inversePosition
end

function IK:forward(inversePosition)
    local forwardPosition = {}

    for i = 1, #inversePosition do
        if i == 1 then
            forwardPosition[i] = self.bones[1]:GetPos()
        else
            local positionPrevious = forwardPosition[i - 1]
            forwardPosition[i] = positionPrevious + ((inversePosition[i] - positionPrevious):GetNormalized() * self.bonesLenght[i - 1])
        end
    end

    return forwardPosition
end

function IK:solve()
    local finalBonesPosition = {}

    for i = 1, #self.bones do
        finalBonesPosition[i] = self.bones[i]:GetPos()
    end

    for i = 1, self.solverIterations do
        finalBonesPosition = self:forward(self:backward(finalBonesPosition))
    end

    for i = 1, #self.bones do
        self.bones[i]:SetPos(finalBonesPosition[i])
    end
end

Theoretically we should be able to do IK for players with this and SetBonePosition, alas I am not really sure what the math should be to make the player bones face the proper angles.

ZH-Hristov avatar Dec 04 '24 14:12 ZH-Hristov

There's also a super jank alternative of using a ragdoll (at least for first person IK) lol

https://github.com/user-attachments/assets/0c5b2d82-4574-4c7e-ab19-225f65b3e498

ZH-Hristov avatar Dec 04 '24 17:12 ZH-Hristov

To this end, I've been poking around random Lua IK libraries online and found this one I yoinked from a Roblox forum post. I've translated it to GLua and it works nicely.

Permission to steal & experiment with this?

Vuthakral avatar Dec 04 '24 21:12 Vuthakral

To this end, I've been poking around random Lua IK libraries online and found this one I yoinked from a Roblox forum post. I've translated it to GLua and it works nicely.

Permission to steal & experiment with this?

Go right ahead, it was posted on a public Roblox forum thread and I just converted it to GLua in like 5 minutes.

ZH-Hristov avatar Dec 05 '24 14:12 ZH-Hristov

@ZH-Hristov If you remove the local from the local IK = {} then you could actually turn that into a proper library that can be called globally. Maybe post that as its own repo, under accreditation of course.

LillyWho avatar May 04 '25 11:05 LillyWho

Not really interested. Not my thing and I can't exactly do what I want to do with it.

ZH-Hristov avatar May 07 '25 14:05 ZH-Hristov