godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.14k stars 96 forks source link

Make the length and tip location of 3D bones for skeletons accesible via a method in script #5877

Open Ali32bit opened 1 year ago

Ali32bit commented 1 year ago

Describe the project you are working on

an open world 3D adventure game featuring procedurally generated content and animated characters that realistically react to their environment by physically simulated or calculated procedrual motion for their skeletal animations.

basically a game where your character and NPCs can realistically move their limbs and body to pick up objects, cross gaps or fit tight crevices or climb oddly shaped obstacles using animations that generate in real time in the game based on the situation at hand and many variables such as their body type and shape and the number of limbs

Describe the problem or limitation you are having in your project

currently there is no way for me to access the length or tip location of 3d bones in 3d skeletons in code or the editor window .
this makes it impossible for me to do the calculations necessary to generate animations or construct skeletons in code or simulate inverse kinematics or rotate and position bones and bone attachments with precision based on the shape of my characters. adding to those problems : most if not all algorithms for inverse kinematics and muscle simulation require knowing the length of the bones in the skeleton as well .

so something like detecting the forearm and attaching an accessory model to its middle is not possible and i will only be able to add such accessory to the root location of the bone which is where the elbow would be. i would need to manually pre define the location for every character model which is not possible if the characters change shape dynamically

drawing or generating meshes or based on skeleton data may also require the bone lengths

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

the ability to access the length and tip position of bones for 3d skeletons within GD script via simple method and potentially the editor window. this data is already internally used by godot engine for various tasks so it already exists internally and simply needs to be exposed to the user . if there is no length data for bones it can simply be calculated by comparing the position of root and tip of the bones. this also means that if only one of the two requested variables is added, the other one will become accessible by a simple calculation

for editor window adjusting the length or tip location would automatically rotate and scale or edit the bone in question to place the tip at the new position. adjusting the length would edit the other variables accordingly as well , this is somewhat possible already for 2d skeletons and it could be translated to 3d as well.

this feature opens many possibilities to users to adjust skeletons and their poses via code only in the running instance of their games . one such example would be custom implementations of inverse and forward kinematics algorithms which usually require the bone lengths for calculations . other examples would be procedural animations or dynamic poses , generating models out of skeletons or generating skeletons for models with much better precision and in real time in the running game , adding nodes as bone attachments to the skeletons exactly where you need them to be in the running game , much better control of physics simulations for skeletons as well as muscle simulation , the ability to fracture skeletons on demand via code, the ability to edit aspects of a skeleton in the running game in real time ( for example extending the arms in a character creator screen )

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

will output the length of the bone as a vector 3 , the vector would start from the origin of the bone and end at the tip

get_bone_length(bone_id)

output vector 3 for the tip position of the bone

get_bone_tip()

an example of getting the bone length for adding bone attachments ( might not be totally syntax accurate ) func -ready ()

    _ add_accessory ( wristwatch ,"forearm" , 0.8 )

func _add_accessory (node , bone_name,offset) :

var bone = get_bone (bone_name) var position = lerp(bone.transform.origin , bone.transform.origin + get_bone_length (bone) ,offset )

later in the function this position is combined with the orientation of the bone and the node is added to the scene and attached to the bone in question as a bone attachment at the correct position and orientation

a and example to change the walk cycle animation speed if the legs are longer or shorter

func _ready()

set_walkcycle_speed()

func set_walkcycle_speed()

var leg = get_bone ("left leg") var bone_length = get_bone_length (leg) bone_length = convert_to_float( bone_length )

$Animation_player.speed = 10 * ( bone_length / 5)

naturally this would also mean we would have setters

set bone length with a vector 3 set_bone_length ()

set tip position by a vector 3

set_bone_tip()

If this enhancement will not be used often, can it be worked around with a few lines of script?

currently only the length for bones with children can be obtained by comparing the child bone location to the parent bone location. this also only works if you pre define the child bone name as well and if the child bone is attached at the tip of the parent bone and nowhere else. if the bone has no children or the above conditions are not met there is no other way to get that information that i know about.

Is there a reason why this should be core and not an add-on in the asset library?

those variables are very helpful to users and they seem like something that should be included out of the box and add_on developers would use themselves for extending functionality

TokageItLab commented 1 year ago

In the Node (glTF) format, there is no "length" or "tips" parameter for bones. It is unique props in Blender's Head-Tail format.

For example, the "length" of a bone with two children obviously cannot be defined, because in Node format it is only the distance between each Node. The same can be said for "tips".

I don't really see the need to make the Skeleton system itself more complex by adding a "child" parameter to the bones for this purpose. There should be some validation to prevent bones that are not actually children from being assigned as children. And it will have to affect Gizmo as well.

Therefore, if you want this feature, I think the right way is to create a class that extended Skeleton on the user side, not on the core side.

Ali32bit commented 1 year ago

okay. if thats really a problem then i can do the extension on my end , but GD script does not expose that kind of low level information so how would i go about doing that sort of thing ? i know GD extension is a thing but i dont have a clue where to begin with that one . is the internal functionality of the engine documented anywhere?

TokageItLab commented 1 year ago

The equivalent of EditBone in Blender is BoneRest in Godot, and you can get the Transfrom3D value with get_bone_rest().

Blender directs the +Y axis from the parent to the child bones and defines the XZ axis with the roll value. So, Blender EditBone has a Transform3D value internally, but we can only check it on python. Here is my addon for checking that value. https://github.com/TokageItLab/blender-addons/tree/main/bone_rest_info

In other words, when exporting to glTF, the bone tip(tail) in Blender only exists to determine the direction of the Y axis in glTF and the length parameter will be lost.

You should also be aware that PoseBone in Blender has no length, only direction. Blender's PoseBone is equivalent to Godot's bone_pose_rotation, which does not affect Rest.

If you want to change the length of the bone in Godot like Blender's Edit bone, you need to use set_bone_rest(). Also, if you want the Skin to be independent, you need to get the bound MeshInstance and change its bound Transform value as well.