Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IK and Physical Bone Improvements #750

Open
Tracked by #1
NHodgesVFX opened this issue Apr 25, 2020 · 10 comments
Open
Tracked by #1

IK and Physical Bone Improvements #750

NHodgesVFX opened this issue Apr 25, 2020 · 10 comments

Comments

@NHodgesVFX
Copy link

Describe the project you are working on:
3D game that makes use IK and PhysicalBones

Describe the problem or limitation you are having in your project:
IK in Godot is standalone and as such doesn't really integrate with the animation tree. In addition its missing some features such as full body IK and constraints.

Physical Bones also suffer from not being integrated into the animation tree. In addition it would be great for physical bones to work while the animation is playing.

Describe the feature / enhancement and how it helps to overcome the problem or limitation:

IK in godot uses the Fabric algorithm, an extension to the base paper extends the algorithm for support of constraints. So, it shouldn't be to much work to add constraints or full body IK.

Full body support basically just needs constraints and a method to specify multiple targets per IK systems. There might be more needed but it seems the current IK solver can solve an arbitrary amount of bones.

The other issue is that IK needs to work with the animation tree somehow. Maybe IK could have its own node in the animation tree that can then be blended with other animations. For blending it should support a Mix Mode and a Add mode at least.

A Minor improvement to the IK system would be to support directly using a node for the magnet position.

Physical Bones should be able to calculate physics on top of an animation. This way if you punch a character the physics system can respond to the impact. In UE4 this is accomplished by converting animation data to physics motors.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:

I sorta explained this above so, Ill use this to show other implementations of IK

Full Body IK and Additive Blending: https://www.youtube.com/watch?v=mNvtZCboy7w
Full Body IK: https://www.youtube.com/watch?v=n6iLQSbnUyA

Physical Animation: https://youtu.be/r40PJ6r_P4c?t=2134

If this enhancement will not be used often, can it be worked around with a few lines of script?:
Animation blending for IK is used frequently in games and full body IK is very popular for VR games. Physical Animation is useful to add more interactivity and realism to characters. It can not be worked around with a few lines of script.

Is there a reason why this should be core and not an add-on in the asset library?:
IK, PhysicalBone, and the animation tree are in core already.

@fire
Copy link
Member

fire commented Jul 14, 2020

@NHodgesVFX are you on Discord, was wondering if we can chat about what is possible in Godot Engine?

@NHodgesVFX
Copy link
Author

NHodgesVFX commented Jul 14, 2020

@NHodgesVFX are you on Discord, was wondering if we can chat about what is possible in Godot Engine?

Yes i am on discord, i also messaged you back in irc :)

@GeorgeS2019
Copy link

@NHodgesVFX

2021 update

@ywmaa
Copy link

ywmaa commented Jan 11, 2022

For anyone working on this feature, here is my code for FABRIK Constraints (Ball And Socket type)

`private Vector3 chain_ball_constraint(int i){

	
	// Get the inner-to-outer direction of this bone as well as the previous bone to use as a baseline
	// Direction for the line L1 "Godot has a good function (DirectionTo) which does (B - A).Normalized  : A.DirectionTo(B)"
	Vector3 thisBoneInnerToOuterdirection = fabrik_transfroms[i-1].origin.DirectionTo(fabrik_transfroms[i].origin);
	Vector3 prevBoneInnerToOuterdirection = fabrik_transfroms[i+1].origin.DirectionTo(fabrik_transfroms[i].origin);
	
	float angleBetweeninDegs = getAngleBetweenDegs(thisBoneInnerToOuterdirection,prevBoneInnerToOuterdirection);
	float constraintAngleinDegs = fabrik_joints[i].RotorConstraintDegs;


	if (angleBetweeninDegs > constraintAngleinDegs){
		return getAngleLimitedUnitVectorDegs(thisBoneInnerToOuterdirection,prevBoneInnerToOuterdirection,constraintAngleinDegs);
	}else{
		return Vector3.Zero;
	}

}
private Vector3 getAngleLimitedUnitVectorDegs(Vector3 vecToLimit, Vector3 vecBaseline, float angleLimitDegs)
{
	// Get the angle between the two vectors
	// Note: This will ALWAYS be a positive value between 0 and 180 degrees.
    float angleBetweenVectorsDegs = getAngleBetweenDegs(vecBaseline, vecToLimit);
    
    if (angleBetweenVectorsDegs > angleLimitDegs)
    {        	
    	// The axis which we need to rotate around is the one perpendicular to the two vectors - so we're
        // rotating around the vector which is the cross-product of our two vectors.
    	// Note: We do not have to worry about both vectors being the same or pointing in opposite directions
    	// because if they bones are the same direction they will not have an angle greater than the angle limit,
    	// and if they point opposite directions we will approach but not quite reach the precise max angle
    	// limit of 180.0f (I believe).
        Vector3	correctionAxis = (vecBaseline.Normalized().Cross(vecToLimit.Normalized())).Normalized();
        
        // Our new vector is the baseline vector rotated by the max allowable angle about the correction axis
        return vecBaseline.Rotated(correctionAxis,Mathf.Deg2Rad(angleLimitDegs)).Normalized();
    }
    else // Angle not greater than limit? Just return a normalised version of the vecToLimit
    {
    	// This may already BE normalised, but we have no way of knowing without calcing the length, so best be safe and normalise.
    	// TODO: If performance is an issue, then I could get the length, and if it's not approx. 1.0f THEN normalise otherwise just return as is.
        return vecToLimit.Normalized();
    }
}
private float getAngleBetweenDegs(Vector3 vec1,Vector3 vec2){
	return Mathf.Rad2Deg(Mathf.Acos(vec1.Normalized().Dot(vec2.Normalized())));
}` 

this work is done by reading its implementation from this repo

it is in c# so someone will need to translate it to cpp and do it directly in Godot and he will probably need to add bone type feature so user can choose if they want (Ball And Socket Constraints) or hinge constraints, though I didn't do hinge constraints

here is how it is integrated in FABRIK iteration :

`private void chain_backwards() {
	// Set the position of the final joint to the target position
	int final_bone_index = fabrik_joints.Length-1;
	Transform final_joint_trans = fabrik_transfroms[final_bone_index];
	float final_joint_length = fabrik_joints[final_bone_index].twisted_bone.get_global_pose_length();
	final_joint_trans.origin = target_transform.origin - (-final_joint_trans.basis.z.Normalized() * final_joint_length);
	fabrik_transfroms[final_bone_index] = final_joint_trans;

	// For all other bones, move them towards the target
	for (int i = final_bone_index; i >= 1; i--) {
		Transform next_bone_trans = fabrik_transfroms[i];
		Transform current_bone_trans = fabrik_transfroms[i-1];

		float length = fabrik_joints[i-1].twisted_bone.get_global_pose_length() / (next_bone_trans.origin -current_bone_trans.origin).Length();
		

		Vector3 NewPoint = Vector3.Zero;
		if (limit_rotation == true & i < final_bone_index)
		{
			NewPoint = chain_ball_constraint(i);
		}
		
		current_bone_trans.origin = next_bone_trans.origin.LinearInterpolate(current_bone_trans.origin + NewPoint, length );
		fabrik_transfroms[i-1] = current_bone_trans;
	}
}`

yes it should be in Backward iteration and no it doesn't need to be added to forward iteration (For this type of constraints only Ball And Socket)

this work was tested using the TwistedIK Plugin for Godot 3.x

Here is the Result :
https://youtu.be/uiKnYmT2XOM

@KaruroChori
Copy link

Was this integrated in any branch of 4.0 at some point? Otherwise I will try and give a go since I need it.

@Calinou
Copy link
Member

Calinou commented Jun 13, 2022

Was this integrated in any branch of 4.0 at some point? Otherwise I will try and give a go since I need it.

This was implemented by godotengine/godot#51368 to an extent, but PhysicalBone hasn't changed much in 4.0 to my knowledge.

@KaruroChori
Copy link

I added the code proposed by @ywmaa in a new branch here: https://github.com/KaruroChori/godot/tree/ballhead-ik
I still have to test it to any extent.

@GeorgeS2019
Copy link

@KaruroChori When U test it, it would be great if others can too if you provide a simple example to test

@KaruroChori
Copy link

godotengine/godot#61994

@GeorgeS2019
Copy link

@NHodgesVFX
@Calinou
godotengine/godot#61994 closed, perhaps we could close this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants