Jump to content

Recommended Posts

Posted

I wanted to make a character's feet align to the ground when standing on a slope or on stairs. This was very easy to get a basic version set up.

The code here only handles the feet, so the legs currently will get stretched out. Each model may require a little bit different final rotation.

The next step is to adjust the knee bones. The hip, knee, and foot form a triangle. One of the constructors for the Plane class accepts three points in space, so those three bones can be used to find a plane. Then you transform their positions to a matrix facing in the direction of the plane normal, solve the triangle, transform back, and that's how IK works.

void MyComponent::UpdateFeet()
{
    auto entity = GetEntity();
    auto world = entity->GetWorld();
    if (not world) return;
    for (int n = 0; n < footbones.size(); ++n)
    {
        if (not footbones[n]) continue;
        auto pos = footbones[n]->GetPosition(true);
        pos.y = 0;
        pos = TransformPoint(pos, entity, NULL);
        auto pickmode = entity->GetPickMode();
        entity->SetPickMode(PICK_NONE);
        auto pickinfo = world->Pick(pos + Vec3(0, footradius + 0.75, 0), pos - Vec3(0, footreach, 0), footradius, true);
        entity->SetPickMode(pickmode);
        if (pickinfo.entity)
        {
            pos = TransformPoint(pickinfo.position, NULL, entity);
            footbones[n]->SetPosition(pos, true);
            Vec3 normal = TransformNormal(pickinfo.normal, NULL, entity);
            footbones[n]->AlignToVector(-normal, 1);
            footbones[n]->Turn(0, 180, 0);
        }
    }
}

 

  • Like 2

Let's build cool stuff and have fun. :)

  • 10 months later...
Posted

Hi! I translated this script by @Josh to Lua, but I don't have enough experience to finish it to do the real IK behaviour (to get rid of the stretching).

Someone can to do it? ;)

function Script:UpdateFeet()
    local entity = self.entity
    local world = entity:GetWorld()
    if world == nil then return end

    for n = 1, #Script.footbones do
        local bone = Script.footbones[n]
        if bone ~= nil then

            local pos = bone:GetPosition(true)
            pos.y = 0

            pos = TransformPoint(pos, entity, nil)

            local pickmode = entity:GetPickMode()
            entity:SetPickMode(PICK_NONE)

            local pickinfo = world:Pick(
                pos + Vec3(0, self.footradius + 0.75, 0),
                pos - Vec3(0, self.footreach, 0),
                self.footradius,
                true
            )

            entity:SetPickMode(pickmode)

            if pickinfo.entity ~= nil then

                local newpos = TransformPoint(pickinfo.position, nil, entity)
                bone:SetPosition(newpos, true)

                local normal = TransformNormal(pickinfo.normal, nil, entity)
                bone:AlignToVector(-normal, 1)
                bone:Turn(-45, 0, 0)
            end
        end
    end
end


image.png.dd629f932530d4d93fe9e4d55de77422.png

  • Like 2

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...