Implement SpringBoneSimulator3D to wiggle chained bones

Co-authored-by: lyuma <xn.lyuma@gmail.com>
Co-authored-by: fire <ernest.lee@chibifire.com>
Co-authored-by: SaracenOne <SaracenOne@gmail.com>
This commit is contained in:
Silc Lizard (Tokage) Renew 2025-01-11 12:58:22 +09:00
parent 21a6bd8dca
commit 5472558a98
28 changed files with 3853 additions and 11 deletions

View File

@ -480,6 +480,15 @@
<member name="editors/3d_gizmos/gizmo_colors/skeleton" type="Color" setter="" getter="">
The 3D editor gizmo color used for [Skeleton3D] nodes.
</member>
<member name="editors/3d_gizmos/gizmo_colors/spring_bone_collision" type="Color" setter="" getter="">
The 3D editor gizmo color used for [SpringBoneCollision3D] nodes.
</member>
<member name="editors/3d_gizmos/gizmo_colors/spring_bone_inside_collision" type="Color" setter="" getter="">
The 3D editor gizmo color used for [SpringBoneCollision3D] nodes with inside mode.
</member>
<member name="editors/3d_gizmos/gizmo_colors/spring_bone_joint" type="Color" setter="" getter="">
The 3D editor gizmo color used for [SpringBoneSimulator3D] nodes.
</member>
<member name="editors/3d_gizmos/gizmo_colors/stream_player_3d" type="Color" setter="" getter="">
The 3D editor gizmo color used for [AudioStreamPlayer3D]'s emission angle.
</member>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SpringBoneCollision3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A base class of the collision that interacts with [SpringBoneSimulator3D].
</brief_description>
<description>
A collision can be a child of [SpringBoneSimulator3D]. If it is not a child of [SpringBoneSimulator3D], it has no effect.
The colliding and sliding are done in the [SpringBoneSimulator3D]'s modification process in order of its collision list which is set by [method SpringBoneSimulator3D.set_collision_path]. If [method SpringBoneSimulator3D.are_all_child_collisions_enabled] is [code]true[/code], the order matches [SceneTree].
If [member bone] is set, it synchronizes with the bone pose of the ancestor [Skeleton3D], which is done in before the [SpringBoneSimulator3D]'s modification process as the pre-process.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_skeleton" qualifiers="const">
<return type="Skeleton3D" />
<description>
Get parent [Skeleton3D] node of the parent [SpringBoneSimulator3D] if found.
</description>
</method>
</methods>
<members>
<member name="bone" type="int" setter="set_bone" getter="get_bone" default="-1">
The index of the attached bone.
</member>
<member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default="&quot;&quot;">
The name of the attached bone.
</member>
<member name="position_offset" type="Vector3" setter="set_position_offset" getter="get_position_offset">
The offset of the position from [Skeleton3D]'s [member bone] pose position.
</member>
<member name="rotation_offset" type="Quaternion" setter="set_rotation_offset" getter="get_rotation_offset">
The offset of the rotation from [Skeleton3D]'s [member bone] pose rotation.
</member>
</members>
</class>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SpringBoneCollisionCapsule3D" inherits="SpringBoneCollision3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A capsule shape collision that interacts with [SpringBoneSimulator3D].
</brief_description>
<description>
A capsule shape collision that interacts with [SpringBoneSimulator3D].
</description>
<tutorials>
</tutorials>
<members>
<member name="height" type="float" setter="set_height" getter="get_height" default="0.5">
The capsule's height.
</member>
<member name="inside" type="bool" setter="set_inside" getter="is_inside" default="false">
If [code]true[/code], the collision acts to trap the joint within the collision.
</member>
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.1">
The capsule's radius.
</member>
</members>
</class>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SpringBoneCollisionPlane3D" inherits="SpringBoneCollision3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A infinite plane collision that interacts with [SpringBoneSimulator3D].
</brief_description>
<description>
A infinite plane collision that interacts with [SpringBoneSimulator3D]. It is an infinite size XZ plane, and the +Y direction is treated as normal.
</description>
<tutorials>
</tutorials>
</class>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SpringBoneCollisionSphere3D" inherits="SpringBoneCollision3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A sphere shape collision that interacts with [SpringBoneSimulator3D].
</brief_description>
<description>
A sphere shape collision that interacts with [SpringBoneSimulator3D].
</description>
<tutorials>
</tutorials>
<members>
<member name="inside" type="bool" setter="set_inside" getter="is_inside" default="false">
If [code]true[/code], the collision acts to trap the joint within the collision.
</member>
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.1">
The sphere's radius.
</member>
</members>
</class>

View File

@ -0,0 +1,658 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SpringBoneSimulator3D" inherits="SkeletonModifier3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A [SkeletonModifier3D] to apply inertial wavering to bone chains.
</brief_description>
<description>
This [SkeletonModifier3D] can be used to wiggle hair, cloth, and tails. This modifier behaves differently from [PhysicalBoneSimulator3D] as it attempts to return the original pose after modification.
If you setup [method set_root_bone] and [method set_end_bone], it is treated as one bone chain. Note that it does not support a branched chain like Y-shaped chains.
When a bone chain is created, an array is generated from the bones that exist in between and listed in the joint list.
Several properties can be applied to each joint, such as [method set_joint_stiffness], [method set_joint_drag], and [method set_joint_gravity].
For simplicity, you can set values to all joints at the same time by using a [Curve]. If you want to specify detailed values individually, set [method set_individual_config] to [code]true[/code].
For physical simulation, [SpringBoneSimulator3D] can have children as self-standing collisions that are not related to [PhysicsServer3D], see also [SpringBoneCollision3D].
</description>
<tutorials>
</tutorials>
<methods>
<method name="are_all_child_collisions_enabled" qualifiers="const">
<return type="bool" />
<param index="0" name="index" type="int" />
<description>
Returns [code]true[/code] if the all child [SpringBoneCollision3D]s are contained in the collision list at [param index] in the settings.
</description>
</method>
<method name="clear_collisions">
<return type="void" />
<param index="0" name="index" type="int" />
<description>
Clears all collisions from the collision list at [param index] in the settings when [method are_all_child_collisions_enabled] is [code]false[/code].
</description>
</method>
<method name="clear_exclude_collisions">
<return type="void" />
<param index="0" name="index" type="int" />
<description>
Clears all exclude collisions from the collision list at [param index] in the settings when [method are_all_child_collisions_enabled] is [code]true[/code].
</description>
</method>
<method name="clear_settings">
<return type="void" />
<description>
Clears all settings.
</description>
</method>
<method name="get_center_bone" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the center bone index of the bone chain.
</description>
</method>
<method name="get_center_bone_name" qualifiers="const">
<return type="String" />
<param index="0" name="index" type="int" />
<description>
Returns the center bone name of the bone chain.
</description>
</method>
<method name="get_center_from" qualifiers="const">
<return type="int" enum="SpringBoneSimulator3D.CenterFrom" />
<param index="0" name="index" type="int" />
<description>
Returns what the center originates from in the bone chain.
</description>
</method>
<method name="get_center_node" qualifiers="const">
<return type="NodePath" />
<param index="0" name="index" type="int" />
<description>
Returns the center node path of the bone chain.
</description>
</method>
<method name="get_collision_count" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the collision count of the bone chain's collision list when [method are_all_child_collisions_enabled] is [code]false[/code].
</description>
</method>
<method name="get_collision_path" qualifiers="const">
<return type="NodePath" />
<param index="0" name="index" type="int" />
<param index="1" name="collision" type="int" />
<description>
Returns the node path of the [SpringBoneCollision3D] at [param collision] in the bone chain's collision list when [method are_all_child_collisions_enabled] is [code]false[/code].
</description>
</method>
<method name="get_drag" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<description>
Returns the drag force damping curve of the bone chain.
</description>
</method>
<method name="get_drag_damping_curve" qualifiers="const">
<return type="Curve" />
<param index="0" name="index" type="int" />
<description>
Returns the drag force damping curve of the bone chain.
</description>
</method>
<method name="get_end_bone" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the end bone index of the bone chain.
</description>
</method>
<method name="get_end_bone_direction" qualifiers="const">
<return type="int" enum="SpringBoneSimulator3D.BoneDirection" />
<param index="0" name="index" type="int" />
<description>
Returns the end bone's tail direction of the bone chain when [method is_end_bone_extended] is [code]true[/code].
</description>
</method>
<method name="get_end_bone_length" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<description>
Returns the end bone's tail length of the bone chain when [method is_end_bone_extended] is [code]true[/code].
</description>
</method>
<method name="get_end_bone_name" qualifiers="const">
<return type="String" />
<param index="0" name="index" type="int" />
<description>
Returns the end bone name of the bone chain.
</description>
</method>
<method name="get_end_bone_tip_radius" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<description>
Returns the end bone tip radius of the bone chain when [method is_end_bone_extended] is [code]true[/code].
</description>
</method>
<method name="get_exclude_collision_count" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the exclude collision count of the bone chain's exclude collision list when [method are_all_child_collisions_enabled] is [code]true[/code].
</description>
</method>
<method name="get_exclude_collision_path" qualifiers="const">
<return type="NodePath" />
<param index="0" name="index" type="int" />
<param index="1" name="collision" type="int" />
<description>
Returns the node path of the [SpringBoneCollision3D] at [param collision] in the bone chain's exclude collision list when [method are_all_child_collisions_enabled] is [code]true[/code].
</description>
</method>
<method name="get_gravity" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<description>
Returns the gravity amount of the bone chain.
</description>
</method>
<method name="get_gravity_damping_curve" qualifiers="const">
<return type="Curve" />
<param index="0" name="index" type="int" />
<description>
Returns the gravity amount damping curve of the bone chain.
</description>
</method>
<method name="get_gravity_direction" qualifiers="const">
<return type="Vector3" />
<param index="0" name="index" type="int" />
<description>
Returns the gravity direction of the bone chain.
</description>
</method>
<method name="get_joint_bone" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<description>
Returns the bone index at [param joint] in the bone chain's joint list.
</description>
</method>
<method name="get_joint_bone_name" qualifiers="const">
<return type="String" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<description>
Returns the bone name at [param joint] in the bone chain's joint list.
</description>
</method>
<method name="get_joint_count" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the joint count of the bone chain's joint list.
</description>
</method>
<method name="get_joint_drag" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<description>
Returns the drag force at [param joint] in the bone chain's joint list.
</description>
</method>
<method name="get_joint_gravity" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<description>
Returns the gravity amount at [param joint] in the bone chain's joint list.
</description>
</method>
<method name="get_joint_gravity_direction" qualifiers="const">
<return type="Vector3" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<description>
Returns the gravity direction at [param joint] in the bone chain's joint list.
</description>
</method>
<method name="get_joint_radius" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<description>
Returns the radius at [param joint] in the bone chain's joint list.
</description>
</method>
<method name="get_joint_rotation_axis" qualifiers="const">
<return type="int" enum="SpringBoneSimulator3D.RotationAxis" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<description>
Returns the rotation axis at [param joint] in the bone chain's joint list.
</description>
</method>
<method name="get_joint_stiffness" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<description>
Returns the stiffness force at [param joint] in the bone chain's joint list.
</description>
</method>
<method name="get_radius" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<description>
Returns the joint radius of the bone chain.
</description>
</method>
<method name="get_radius_damping_curve" qualifiers="const">
<return type="Curve" />
<param index="0" name="index" type="int" />
<description>
Returns the joint radius damping curve of the bone chain.
</description>
</method>
<method name="get_root_bone" qualifiers="const">
<return type="int" />
<param index="0" name="index" type="int" />
<description>
Returns the root bone index of the bone chain.
</description>
</method>
<method name="get_root_bone_name" qualifiers="const">
<return type="String" />
<param index="0" name="index" type="int" />
<description>
Returns the root bone name of the bone chain.
</description>
</method>
<method name="get_rotation_axis" qualifiers="const">
<return type="int" enum="SpringBoneSimulator3D.RotationAxis" />
<param index="0" name="index" type="int" />
<description>
Returns the rotation axis of the bone chain.
</description>
</method>
<method name="get_stiffness" qualifiers="const">
<return type="float" />
<param index="0" name="index" type="int" />
<description>
Returns the stiffness force of the bone chain.
</description>
</method>
<method name="get_stiffness_damping_curve" qualifiers="const">
<return type="Curve" />
<param index="0" name="index" type="int" />
<description>
Returns the stiffness force damping curve of the bone chain.
</description>
</method>
<method name="is_config_individual" qualifiers="const">
<return type="bool" />
<param index="0" name="index" type="int" />
<description>
Returns [code]true[/code] if the config can be edited individually for each joint.
</description>
</method>
<method name="is_end_bone_extended" qualifiers="const">
<return type="bool" />
<param index="0" name="index" type="int" />
<description>
Returns [code]true[/code] if the end bone is extended to have the tail.
</description>
</method>
<method name="reset">
<return type="void" />
<description>
Resets a simulating state with respect to the current bone pose.
It is useful to prevent the simulation result getting violent. For example, calling this immediately after a call to [method AnimationPlayer.play] without a fading, or within the previous [signal SkeletonModifier3D.modification_processed] signal if it's condition changes significantly.
</description>
</method>
<method name="set_center_bone">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="bone" type="int" />
<description>
Sets the center bone index of the bone chain.
</description>
</method>
<method name="set_center_bone_name">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="bone_name" type="String" />
<description>
Sets the center bone name of the bone chain.
</description>
</method>
<method name="set_center_from">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="center_from" type="int" enum="SpringBoneSimulator3D.CenterFrom" />
<description>
Sets what the center originates from in the bone chain.
Bone movement is calculated based on the difference in relative distance between center and bone in the previous and next frames.
For example, if the parent [Skeleton3D] is used as the center, the bones are considered to have not moved if the [Skeleton3D] moves in the world.
In this case, only a change in the bone pose is considered to be a bone movement.
</description>
</method>
<method name="set_center_node">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="node_path" type="NodePath" />
<description>
Sets the center node path of the bone chain.
</description>
</method>
<method name="set_collision_count">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="count" type="int" />
<description>
Sets the number of collisions in the collision list at [param index] in the settings when [method are_all_child_collisions_enabled] is [code]false[/code].
</description>
</method>
<method name="set_collision_path">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="collision" type="int" />
<param index="2" name="node_path" type="NodePath" />
<description>
Sets the node path of the [SpringBoneCollision3D] at [param collision] in the bone chain's collision list when [method are_all_child_collisions_enabled] is [code]false[/code].
</description>
</method>
<method name="set_drag">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="drag" type="float" />
<description>
Sets the drag force of the bone chain. The greater the value, the more suppressed the wiggling.
The value is scaled by [method set_drag_damping_curve] and cached in each joint setting in the joint list.
</description>
</method>
<method name="set_drag_damping_curve">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="curve" type="Curve" />
<description>
Sets the drag force damping curve of the bone chain.
</description>
</method>
<method name="set_enable_all_child_collisions">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="enabled" type="bool" />
<description>
If sets [param enabled] to [code]true[/code], the all child [SpringBoneCollision3D]s are collided and [method set_exclude_collision_path] is enabled as an exclusion list at [param index] in the settings.
If sets [param enabled] to [code]false[/code], you need to manually register all valid collisions with [method set_collision_path].
</description>
</method>
<method name="set_end_bone">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="bone" type="int" />
<description>
Sets the end bone index of the bone chain.
</description>
</method>
<method name="set_end_bone_direction">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="bone_direction" type="int" enum="SpringBoneSimulator3D.BoneDirection" />
<description>
Sets the end bone tail direction of the bone chain when [method is_end_bone_extended] is [code]true[/code].
</description>
</method>
<method name="set_end_bone_length">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="length" type="float" />
<description>
Sets the end bone tail length of the bone chain when [method is_end_bone_extended] is [code]true[/code].
</description>
</method>
<method name="set_end_bone_name">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="bone_name" type="String" />
<description>
Sets the end bone name of the bone chain.
[b]Note:[/b] End bone must be the root bone or a child of the root bone. If they are the same, the tail must be extended by [method set_extend_end_bone] to jiggle the bone.
</description>
</method>
<method name="set_end_bone_tip_radius">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="radius" type="float" />
<description>
Sets the end bone tip radius of the bone chain when [method is_end_bone_extended] is [code]true[/code].
</description>
</method>
<method name="set_exclude_collision_count">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="count" type="int" />
<description>
Sets the number of exclude collisions in the exclude collision list at [param index] in the settings when [method are_all_child_collisions_enabled] is [code]true[/code].
</description>
</method>
<method name="set_exclude_collision_path">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="collision" type="int" />
<param index="2" name="node_path" type="NodePath" />
<description>
Sets the node path of the [SpringBoneCollision3D] at [param collision] in the bone chain's exclude collision list when [method are_all_child_collisions_enabled] is [code]true[/code].
</description>
</method>
<method name="set_extend_end_bone">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="enabled" type="bool" />
<description>
If [param enabled] is [code]true[/code], the end bone is extended to have the tail.
</description>
</method>
<method name="set_gravity">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="gravity" type="float" />
<description>
Sets the gravity amount of the bone chain.
If [param gravity] is not [code]0[/code], the modified pose will not return to the original pose since it is always affected by gravity.
The value is scaled by [method set_gravity_damping_curve] and cached in each joint setting in the joint list.
</description>
</method>
<method name="set_gravity_damping_curve">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="curve" type="Curve" />
<description>
Sets the gravity amount damping curve of the bone chain.
</description>
</method>
<method name="set_gravity_direction">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="gravity_direction" type="Vector3" />
<description>
Sets the gravity direction of the bone chain.
The value is cached in each joint setting in the joint list.
</description>
</method>
<method name="set_individual_config">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="enabled" type="bool" />
<description>
If [param enabled] is [code]true[/code], the config can be edited individually for each joint.
</description>
</method>
<method name="set_joint_drag">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<param index="2" name="drag" type="float" />
<description>
Sets the drag force at [param joint] in the bone chain's joint list when [method is_config_individual] is [code]true[/code].
</description>
</method>
<method name="set_joint_gravity">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<param index="2" name="gravity" type="float" />
<description>
Sets the gravity amount at [param joint] in the bone chain's joint list when [method is_config_individual] is [code]true[/code].
</description>
</method>
<method name="set_joint_gravity_direction">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<param index="2" name="gravity_direction" type="Vector3" />
<description>
Sets the gravity direction at [param joint] in the bone chain's joint list when [method is_config_individual] is [code]true[/code].
</description>
</method>
<method name="set_joint_radius">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<param index="2" name="radius" type="float" />
<description>
Sets the joint radius at [param joint] in the bone chain's joint list when [method is_config_individual] is [code]true[/code].
</description>
</method>
<method name="set_joint_rotation_axis">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<param index="2" name="axis" type="int" enum="SpringBoneSimulator3D.RotationAxis" />
<description>
Sets the rotation axis at [param joint] in the bone chain's joint list when [method is_config_individual] is [code]true[/code].
</description>
</method>
<method name="set_joint_stiffness">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="joint" type="int" />
<param index="2" name="stiffness" type="float" />
<description>
Sets the stiffness force at [param joint] in the bone chain's joint list when [method is_config_individual] is [code]true[/code].
</description>
</method>
<method name="set_radius">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="radius" type="float" />
<description>
Sets the joint radius of the bone chain. It is used to move and slide with the [SpringBoneCollision3D] in the collision list.
The value is scaled by [method set_radius_damping_curve] and cached in each joint setting in the joint list.
</description>
</method>
<method name="set_radius_damping_curve">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="curve" type="Curve" />
<description>
Sets the joint radius damping curve of the bone chain.
</description>
</method>
<method name="set_root_bone">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="bone" type="int" />
<description>
Sets the root bone index of the bone chain.
</description>
</method>
<method name="set_root_bone_name">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="bone_name" type="String" />
<description>
Sets the root bone name of the bone chain.
</description>
</method>
<method name="set_rotation_axis">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="axis" type="int" enum="SpringBoneSimulator3D.RotationAxis" />
<description>
Sets the rotation axis of the bone chain. If sets a specific axis, it acts like a hinge joint.
The value is cached in each joint setting in the joint list.
</description>
</method>
<method name="set_stiffness">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="stiffness" type="float" />
<description>
Sets the stiffness force of the bone chain. The greater the value, the faster it recovers to its initial pose.
If [param stiffness] is [code]0[/code], the modified pose will not return to the original pose.
The value is scaled by [method set_stiffness_damping_curve] and cached in each joint setting in the joint list.
</description>
</method>
<method name="set_stiffness_damping_curve">
<return type="void" />
<param index="0" name="index" type="int" />
<param index="1" name="curve" type="Curve" />
<description>
Sets the stiffness force damping curve of the bone chain.
</description>
</method>
</methods>
<members>
<member name="setting_count" type="int" setter="set_setting_count" getter="get_setting_count" default="0">
The number of settings.
</member>
</members>
<constants>
<constant name="BONE_DIRECTION_PLUS_X" value="0" enum="BoneDirection">
Enumerated value for the +X axis.
</constant>
<constant name="BONE_DIRECTION_MINUS_X" value="1" enum="BoneDirection">
Enumerated value for the -X axis.
</constant>
<constant name="BONE_DIRECTION_PLUS_Y" value="2" enum="BoneDirection">
Enumerated value for the +Y axis.
</constant>
<constant name="BONE_DIRECTION_MINUS_Y" value="3" enum="BoneDirection">
Enumerated value for the -Y axis.
</constant>
<constant name="BONE_DIRECTION_PLUS_Z" value="4" enum="BoneDirection">
Enumerated value for the +Z axis.
</constant>
<constant name="BONE_DIRECTION_MINUS_Z" value="5" enum="BoneDirection">
Enumerated value for the -Z axis.
</constant>
<constant name="BONE_DIRECTION_FROM_PARENT" value="6" enum="BoneDirection">
Enumerated value for the axis from a parent bone to the child bone.
</constant>
<constant name="CENTER_FROM_WORLD_ORIGIN" value="0" enum="CenterFrom">
The world origin is defined as center.
</constant>
<constant name="CENTER_FROM_NODE" value="1" enum="CenterFrom">
The [Node3D] specified by [method set_center_node] is defined as center.
If [Node3D] is not found, the parent [Skeleton3D] is treated as center.
</constant>
<constant name="CENTER_FROM_BONE" value="2" enum="CenterFrom">
The bone pose origin of the parent [Skeleton3D] specified by [method set_center_bone] is defined as center.
If [Node3D] is not found, the parent [Skeleton3D] is treated as center.
</constant>
<constant name="ROTATION_AXIS_X" value="0" enum="RotationAxis">
Enumerated value for the rotation of the X axis.
</constant>
<constant name="ROTATION_AXIS_Y" value="1" enum="RotationAxis">
Enumerated value for the rotation of the Y axis.
</constant>
<constant name="ROTATION_AXIS_Z" value="2" enum="RotationAxis">
Enumerated value for the rotation of the Z axis.
</constant>
<constant name="ROTATION_AXIS_ALL" value="3" enum="RotationAxis">
Enumerated value for the unconstrained rotation.
</constant>
</constants>
</class>

View File

@ -2365,6 +2365,7 @@ void EditorInspectorArray::_setup() {
Ref<Font> numbers_font;
int numbers_min_w = 0;
bool unresizable = is_const || read_only;
if (numbered) {
numbers_font = get_theme_font(SNAME("bold"), EditorStringName(EditorFonts));
@ -2461,15 +2462,17 @@ void EditorInspectorArray::_setup() {
ae.vbox->set_v_size_flags(SIZE_EXPAND_FILL);
ae.hbox->add_child(ae.vbox);
ae.erase = memnew(Button);
ae.erase->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
ae.erase->set_v_size_flags(SIZE_SHRINK_CENTER);
ae.erase->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorArray::_remove_item).bind(element_position));
ae.hbox->add_child(ae.erase);
if (!unresizable) {
ae.erase = memnew(Button);
ae.erase->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
ae.erase->set_v_size_flags(SIZE_SHRINK_CENTER);
ae.erase->connect(SceneStringName(pressed), callable_mp(this, &EditorInspectorArray::_remove_item).bind(element_position));
ae.hbox->add_child(ae.erase);
}
}
// Hide/show the add button.
add_button->set_visible(page == max_page);
add_button->set_visible(page == max_page && !unresizable);
// Add paginator if there's more than 1 page.
if (max_page > 0) {
@ -2587,12 +2590,13 @@ void EditorInspectorArray::_bind_methods() {
ADD_SIGNAL(MethodInfo("page_change_request"));
}
void EditorInspectorArray::setup_with_move_element_function(Object *p_object, const String &p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text) {
void EditorInspectorArray::setup_with_move_element_function(Object *p_object, const String &p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_is_const, bool p_numbered, int p_page_length, const String &p_add_item_text) {
count_property = "";
mode = MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION;
array_element_prefix = p_array_element_prefix;
page = p_page;
movable = p_movable;
is_const = p_is_const;
page_length = p_page_length;
numbered = p_numbered;
@ -2601,12 +2605,13 @@ void EditorInspectorArray::setup_with_move_element_function(Object *p_object, co
_setup();
}
void EditorInspectorArray::setup_with_count_property(Object *p_object, const String &p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text, const String &p_swap_method) {
void EditorInspectorArray::setup_with_count_property(Object *p_object, const String &p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_is_const, bool p_numbered, int p_page_length, const String &p_add_item_text, const String &p_swap_method) {
count_property = p_count_property;
mode = MODE_USE_COUNT_PROPERTY;
array_element_prefix = p_array_element_prefix;
page = p_page;
movable = p_movable;
is_const = p_is_const;
page_length = p_page_length;
numbered = p_numbered;
swap_method = p_swap_method;
@ -3442,6 +3447,7 @@ void EditorInspector::update_tree() {
int page_size = 5;
bool movable = true;
bool is_const = false;
bool numbered = false;
bool foldable = use_folding;
String add_button_text = TTR("Add Element");
@ -3453,6 +3459,8 @@ void EditorInspector::update_tree() {
add_button_text = class_name_components[i].get_slice("=", 1).strip_edges();
} else if (class_name_components[i] == "static") {
movable = false;
} else if (class_name_components[i] == "const") {
is_const = true;
} else if (class_name_components[i] == "numbered") {
numbered = true;
} else if (class_name_components[i] == "unfoldable") {
@ -3479,7 +3487,7 @@ void EditorInspector::update_tree() {
editor_inspector_array = memnew(EditorInspectorArray(all_read_only));
int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0;
editor_inspector_array->setup_with_count_property(object, class_name_components[0], p.name, array_element_prefix, page, c, foldable, movable, numbered, page_size, add_button_text, swap_method);
editor_inspector_array->setup_with_count_property(object, class_name_components[0], p.name, array_element_prefix, page, c, foldable, movable, is_const, numbered, page_size, add_button_text, swap_method);
editor_inspector_array->connect("page_change_request", callable_mp(this, &EditorInspector::_page_change_request).bind(array_element_prefix));
}
}

View File

@ -391,6 +391,7 @@ class EditorInspectorArray : public EditorInspectorSection {
bool read_only = false;
bool movable = true;
bool is_const = false;
bool numbered = false;
enum MenuOptions {
@ -457,8 +458,8 @@ protected:
static void _bind_methods();
public:
void setup_with_move_element_function(Object *p_object, const String &p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "");
void setup_with_count_property(Object *p_object, const String &p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = "");
void setup_with_move_element_function(Object *p_object, const String &p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_is_const = false, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "");
void setup_with_count_property(Object *p_object, const String &p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_is_const = false, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = "");
VBoxContainer *get_vbox(int p_index);
EditorInspectorArray(bool p_read_only);

View File

@ -795,6 +795,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/selected_bone", Color(0.8, 0.3, 0.0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/gridmap_grid", Color(0.8, 0.5, 0.1), "")
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/spring_bone_joint", Color(0.8, 0.9, 0.6), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/spring_bone_collision", Color(0.6, 0.8, 0.9), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/spring_bone_inside_collision", Color(0.9, 0.6, 0.8), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
_initial_set("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.1);
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d_gizmos/gizmo_settings/bone_shape", 1, "Wire,Octahedron");
EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size", 0.8, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#b56d6d" d="M7.375 5.053c-.488.733-.289 1.724.445 2.213.2.133.426.219.664.252.122.873.927 1.481 1.8 1.36.874-.121 1.483-.928 1.36-1.801-.033-.238-.119-.464-.25-.664l1.373-1.372c.733.486 1.724.288 2.211-.445.488-.734.291-1.725-.444-2.213-.199-.132-.427-.219-.664-.251-.121-.874-.927-1.483-1.8-1.362s-1.482.928-1.361 1.803c.033.236.119.465.251.664l-1.372 1.37c-.734-.488-1.725-.289-2.213.446zM8.625 10.949c.488-.734.289-1.727-.444-2.215-.2-.131-.427-.217-.665-.25-.122-.873-.927-1.482-1.8-1.361s-1.482.928-1.36 1.802c.033.236.119.464.252.663l-1.373 1.373c-.734-.488-1.724-.289-2.212.445s-.289 1.724.445 2.212c.199.132.426.219.664.252.121.873.927 1.481 1.8 1.36.874-.123 1.482-.926 1.36-1.801-.033-.236-.118-.465-.252-.664l1.374-1.373c.732.49 1.723.292 2.211-.443z"/><circle cx="12" cy="12" r="3" fill="#5c7d8e"/><circle cx="11.143" cy="10.714" r=".856" fill="#728387"/></svg>

After

Width:  |  Height:  |  Size: 948 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fc7f7f" d="M7.375 5.053c-.488.733-.289 1.724.445 2.213.2.133.426.219.664.252.122.873.927 1.481 1.8 1.36.874-.121 1.483-.928 1.36-1.801-.033-.238-.119-.464-.25-.664l1.373-1.372c.733.486 1.724.288 2.211-.445.488-.734.291-1.725-.444-2.213-.199-.132-.427-.219-.664-.251-.121-.874-.927-1.483-1.8-1.362s-1.482.928-1.361 1.803c.033.236.119.465.251.664l-1.372 1.37c-.734-.488-1.725-.289-2.213.446zM8.625 10.949c.488-.734.289-1.727-.444-2.215-.2-.131-.427-.217-.665-.25-.122-.873-.927-1.482-1.8-1.361s-1.482.928-1.36 1.802c.033.236.119.464.252.663l-1.373 1.373c-.734-.488-1.724-.289-2.212.445s-.289 1.724.445 2.212c.199.132.426.219.664.252.121.873.927 1.481 1.8 1.36.874-.123 1.482-.926 1.36-1.801-.033-.236-.118-.465-.252-.664l1.374-1.373c.732.49 1.723.292 2.211-.443z"/><path fill="#5fb2ff" d="m10.286 10.857v2.285c0 1.578 1.278 2.856 2.856 2.856s2.858-1.277 2.858-2.855v-2.285c0-1.579-1.279-2.858-2.857-2.858s-2.857 1.279-2.857 2.857z"/><circle cx="12.286" cy="10" r=".857" fill="#a2d2ff"/></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-399.5 200.5 16 16"><path fill="#fc7f7f" d="M-392.125 205.553c-.488.733-.289 1.725.445 2.213.2.132.426.218.664.252.121.872.927 1.481 1.8 1.36.874-.121 1.483-.928 1.361-1.801-.033-.238-.119-.464-.251-.664l1.373-1.372c.734.487 1.724.288 2.212-.445.488-.734.29-1.725-.445-2.213-.199-.132-.426-.219-.664-.251-.121-.874-.927-1.483-1.8-1.362s-1.482.928-1.361 1.802c.033.236.119.465.251.664l-1.372 1.371c-.734-.488-1.725-.289-2.213.446zM-390.875 211.449c.488-.734.289-1.726-.444-2.214-.2-.132-.427-.218-.665-.251-.122-.873-.927-1.482-1.8-1.361s-1.482.928-1.36 1.802c.033.236.119.463.252.663l-1.373 1.373c-.734-.488-1.724-.289-2.212.445s-.289 1.724.445 2.212c.199.132.426.219.664.252.121.873.927 1.482 1.8 1.36.874-.122 1.482-.926 1.36-1.8-.033-.237-.118-.465-.252-.664l1.374-1.373c.732.489 1.723.29 2.211-.444z"/><path fill="#5fb2ff" d="m-389.5 216.5 6-.5v-5.5l-6-.5z"/></svg>

After

Width:  |  Height:  |  Size: 941 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#fc7f7f" d="M7.375 5.053c-.488.733-.289 1.724.445 2.213.2.133.426.219.664.252.122.873.927 1.481 1.8 1.36.874-.121 1.483-.928 1.36-1.801-.033-.238-.119-.464-.25-.664l1.373-1.372c.733.486 1.724.288 2.211-.445.488-.734.291-1.725-.444-2.213-.199-.132-.427-.219-.664-.251-.121-.874-.927-1.483-1.8-1.362s-1.482.928-1.361 1.803c.033.236.119.465.251.664l-1.372 1.37c-.734-.488-1.725-.289-2.213.446zM8.625 10.949c.488-.734.289-1.727-.444-2.215-.2-.131-.427-.217-.665-.25-.122-.873-.927-1.482-1.8-1.361s-1.482.928-1.36 1.802c.033.236.119.464.252.663l-1.373 1.373c-.734-.488-1.724-.289-2.212.445s-.289 1.724.445 2.212c.199.132.426.219.664.252.121.873.927 1.481 1.8 1.36.874-.123 1.482-.926 1.36-1.801-.033-.236-.118-.465-.252-.664l1.374-1.373c.732.49 1.723.292 2.211-.443z"/><circle cx="12" cy="12" r="3" fill="#5fb2ff"/><circle cx="11.143" cy="10.714" r=".856" fill="#a2d2ff"/></svg>

After

Width:  |  Height:  |  Size: 948 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="-399.5 200.5 16 16"><g fill="#fc7f7f"><path d="M-392.125 205.553c-.488.733-.289 1.725.445 2.213.2.132.426.218.664.252.121.872.927 1.481 1.8 1.36.874-.121 1.483-.928 1.361-1.801-.033-.238-.119-.464-.251-.664l1.373-1.372c.734.487 1.724.288 2.212-.445.488-.734.29-1.725-.445-2.213-.199-.132-.426-.219-.664-.251-.121-.874-.927-1.483-1.8-1.362s-1.482.928-1.361 1.802c.033.236.119.465.251.664l-1.372 1.371c-.734-.488-1.725-.289-2.213.446zM-390.875 211.449c.488-.734.289-1.726-.444-2.214-.2-.132-.427-.218-.665-.251-.122-.873-.927-1.482-1.8-1.361s-1.482.928-1.36 1.802c.033.236.119.463.252.663l-1.373 1.373c-.734-.488-1.724-.289-2.212.445s-.289 1.724.445 2.212c.199.132.426.219.664.252.121.873.927 1.482 1.8 1.36.874-.122 1.482-.926 1.36-1.8-.033-.237-.118-.465-.252-.664l1.374-1.373c.732.489 1.723.29 2.211-.444z"/><path d="m-397.222 209.5c0 .276.224.5.5.5s.5-.224.5-.5c0-3.263 2.46-5.723 5.722-5.723.276 0 .5-.224.5-.5s-.224-.5-.5-.5c-3.832 0-6.722 2.89-6.722 6.723z"/><path d="M-398 207.723c0-3.263 2.46-5.723 5.722-5.723.276 0 .5-.224.5-.5s-.224-.5-.5-.5c-3.832 0-6.722 2.89-6.722 6.723 0 .276.224.5.5.5s.5-.224.5-.5zM-385.778 207.5c0-.276-.224-.5-.5-.5s-.5.224-.5.5c0 3.263-2.46 5.723-5.722 5.723-.276 0-.5.224-.5.5s.224.5.5.5c3.832 0 6.722-2.89 6.722-6.723z"/><path d="m-384.5 208.777c-.276 0-.5.224-.5.5 0 3.263-2.46 5.723-5.722 5.723-.276 0-.5.224-.5.5s.224.5.5.5c3.832 0 6.722-2.89 6.722-6.723 0-.276-.224-.5-.5-.5z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,424 @@
/**************************************************************************/
/* spring_bone_3d_gizmo_plugin.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "spring_bone_3d_gizmo_plugin.h"
#include "editor/editor_settings.h"
#include "scene/3d/spring_bone_collision_capsule_3d.h"
#include "scene/3d/spring_bone_collision_plane_3d.h"
#include "scene/3d/spring_bone_collision_sphere_3d.h"
// SpringBoneSimulator3D
SpringBoneSimulator3DGizmoPlugin::SelectionMaterials SpringBoneSimulator3DGizmoPlugin::selection_materials;
SpringBoneSimulator3DGizmoPlugin::SpringBoneSimulator3DGizmoPlugin() {
selection_materials.unselected_mat.instantiate();
selection_materials.unselected_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
selection_materials.unselected_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
selection_materials.selected_mat.instantiate();
Ref<Shader> sh;
sh.instantiate();
sh->set_code(R"(
// Skeleton 3D gizmo bones shader.
shader_type spatial;
render_mode unshaded, shadows_disabled;
void vertex() {
if (!OUTPUT_IS_SRGB) {
COLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );
}
VERTEX = VERTEX;
POSITION = PROJECTION_MATRIX * VIEW_MATRIX * MODEL_MATRIX * vec4(VERTEX.xyz, 1.0);
POSITION.z = mix(POSITION.z, POSITION.w, 0.998);
}
void fragment() {
ALBEDO = COLOR.rgb;
ALPHA = COLOR.a;
}
)");
selection_materials.selected_mat->set_shader(sh);
}
SpringBoneSimulator3DGizmoPlugin::~SpringBoneSimulator3DGizmoPlugin() {
selection_materials.unselected_mat.unref();
selection_materials.selected_mat.unref();
}
bool SpringBoneSimulator3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<SpringBoneSimulator3D>(p_spatial) != nullptr;
}
String SpringBoneSimulator3DGizmoPlugin::get_gizmo_name() const {
return "SpringBoneSimulator3D";
}
int SpringBoneSimulator3DGizmoPlugin::get_priority() const {
return -1;
}
void SpringBoneSimulator3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
SpringBoneSimulator3D *simulator = Object::cast_to<SpringBoneSimulator3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
if (!simulator->get_setting_count()) {
return;
}
Skeleton3D *skeleton = simulator->get_skeleton();
if (!skeleton) {
return;
}
Ref<ArrayMesh> mesh = get_joints_mesh(skeleton, simulator, p_gizmo->is_selected());
Transform3D skel_tr = simulator->get_global_transform().inverse() * skeleton->get_global_transform();
p_gizmo->add_mesh(mesh, Ref<Material>(), skel_tr, skeleton->register_skin(skeleton->create_skin_from_rest_transforms()));
}
Ref<ArrayMesh> SpringBoneSimulator3DGizmoPlugin::get_joints_mesh(Skeleton3D *p_skeleton, SpringBoneSimulator3D *p_simulator, bool p_is_selected) {
Color bone_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/spring_bone_joint");
Ref<SurfaceTool> surface_tool;
surface_tool.instantiate();
surface_tool->begin(Mesh::PRIMITIVE_LINES);
if (p_is_selected) {
surface_tool->set_material(selection_materials.selected_mat);
} else {
selection_materials.unselected_mat->set_albedo(bone_color);
surface_tool->set_material(selection_materials.unselected_mat);
}
LocalVector<int> bones;
LocalVector<float> weights;
bones.resize(4);
weights.resize(4);
for (int i = 0; i < 4; i++) {
bones[i] = 0;
weights[i] = 0;
}
weights[0] = 1;
for (int i = 0; i < p_simulator->get_setting_count(); i++) {
int current_bone = -1;
int prev_bone = -1;
int joint_end = p_simulator->get_joint_count(i) - 1;
for (int j = 0; j <= joint_end; j++) {
current_bone = p_simulator->get_joint_bone(i, j);
if (j > 0) {
Transform3D parent_global_pose = p_skeleton->get_bone_global_rest(prev_bone);
Transform3D global_pose = p_skeleton->get_bone_global_rest(current_bone);
draw_line(surface_tool, parent_global_pose.origin, global_pose.origin, bone_color);
draw_sphere(surface_tool, global_pose.basis, global_pose.origin, p_simulator->get_joint_radius(i, j), bone_color);
}
if (j == joint_end && p_simulator->is_end_bone_extended(i) && p_simulator->get_end_bone_length(i) > 0) {
Vector3 axis = p_simulator->get_end_bone_axis(current_bone, p_simulator->get_end_bone_direction(i));
if (axis.is_zero_approx()) {
continue;
}
bones[0] = current_bone;
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
Transform3D global_pose = p_skeleton->get_bone_global_rest(current_bone);
axis = global_pose.xform(axis * p_simulator->get_end_bone_length(i));
draw_line(surface_tool, global_pose.origin, axis, bone_color);
draw_sphere(surface_tool, global_pose.basis, axis, p_simulator->get_end_bone_tip_radius(i), bone_color);
} else {
bones[0] = current_bone;
surface_tool->set_bones(bones);
surface_tool->set_weights(weights);
}
prev_bone = current_bone;
}
}
return surface_tool->commit();
}
void SpringBoneSimulator3DGizmoPlugin::draw_sphere(Ref<SurfaceTool> &p_surface_tool, const Basis &p_basis, const Vector3 &p_center, float p_radius, const Color &p_color) {
static const Vector3 VECTOR3_RIGHT = Vector3(1, 0, 0);
static const Vector3 VECTOR3_UP = Vector3(0, 1, 0);
static const Vector3 VECTOR3_FORWARD = Vector3(0, 0, 1);
static const int STEP = 16;
static const float SPPI = Math_TAU / (float)STEP;
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(p_center + ((p_basis.xform(VECTOR3_UP * p_radius)).rotated(p_basis.xform(VECTOR3_RIGHT), SPPI * ((i - 1) % STEP))));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(p_center + ((p_basis.xform(VECTOR3_UP * p_radius)).rotated(p_basis.xform(VECTOR3_RIGHT), SPPI * (i % STEP))));
}
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(p_center + ((p_basis.xform(VECTOR3_RIGHT * p_radius)).rotated(p_basis.xform(VECTOR3_FORWARD), SPPI * ((i - 1) % STEP))));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(p_center + ((p_basis.xform(VECTOR3_RIGHT * p_radius)).rotated(p_basis.xform(VECTOR3_FORWARD), SPPI * (i % STEP))));
}
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(p_center + ((p_basis.xform(VECTOR3_FORWARD * p_radius)).rotated(p_basis.xform(VECTOR3_UP), SPPI * ((i - 1) % STEP))));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(p_center + ((p_basis.xform(VECTOR3_FORWARD * p_radius)).rotated(p_basis.xform(VECTOR3_UP), SPPI * (i % STEP))));
}
}
void SpringBoneSimulator3DGizmoPlugin::draw_line(Ref<SurfaceTool> &p_surface_tool, const Vector3 &p_begin_pos, const Vector3 &p_end_pos, const Color &p_color) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(p_begin_pos);
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(p_end_pos);
}
// SpringBoneCollision3D
SpringBoneCollision3DGizmoPlugin::SelectionMaterials SpringBoneCollision3DGizmoPlugin::selection_materials;
SpringBoneCollision3DGizmoPlugin::SpringBoneCollision3DGizmoPlugin() {
selection_materials.unselected_mat.instantiate();
selection_materials.unselected_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
selection_materials.unselected_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
selection_materials.unselected_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
selection_materials.selected_mat.instantiate();
Ref<Shader> sh;
sh.instantiate();
sh->set_code(R"(
// Skeleton 3D gizmo bones shader.
shader_type spatial;
render_mode unshaded, shadows_disabled;
void vertex() {
if (!OUTPUT_IS_SRGB) {
COLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );
}
VERTEX = VERTEX;
POSITION = PROJECTION_MATRIX * VIEW_MATRIX * MODEL_MATRIX * vec4(VERTEX.xyz, 1.0);
POSITION.z = mix(POSITION.z, POSITION.w, 0.998);
}
void fragment() {
ALBEDO = COLOR.rgb;
ALPHA = COLOR.a;
}
)");
selection_materials.selected_mat->set_shader(sh);
}
SpringBoneCollision3DGizmoPlugin::~SpringBoneCollision3DGizmoPlugin() {
selection_materials.unselected_mat.unref();
selection_materials.selected_mat.unref();
}
bool SpringBoneCollision3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<SpringBoneCollision3D>(p_spatial) != nullptr;
}
String SpringBoneCollision3DGizmoPlugin::get_gizmo_name() const {
return "SpringBoneCollision3D";
}
int SpringBoneCollision3DGizmoPlugin::get_priority() const {
return -1;
}
void SpringBoneCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
SpringBoneCollision3D *collision = Object::cast_to<SpringBoneCollision3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
Ref<ArrayMesh> mesh = get_collision_mesh(collision, p_gizmo->is_selected());
p_gizmo->add_mesh(mesh);
}
Ref<ArrayMesh> SpringBoneCollision3DGizmoPlugin::get_collision_mesh(SpringBoneCollision3D *p_collision, bool p_is_selected) {
Color collision_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/spring_bone_collision");
Color inside_collision_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/spring_bone_inside_collision");
Ref<SurfaceTool> surface_tool;
surface_tool.instantiate();
surface_tool->begin(Mesh::PRIMITIVE_LINES);
if (p_is_selected) {
surface_tool->set_material(selection_materials.selected_mat);
} else {
selection_materials.unselected_mat->set_albedo(collision_color);
surface_tool->set_material(selection_materials.unselected_mat);
}
SpringBoneCollisionSphere3D *sphere = Object::cast_to<SpringBoneCollisionSphere3D>(p_collision);
if (sphere) {
draw_sphere(surface_tool, sphere->get_radius(), sphere->is_inside() ? inside_collision_color : collision_color);
return surface_tool->commit();
}
SpringBoneCollisionCapsule3D *capsule = Object::cast_to<SpringBoneCollisionCapsule3D>(p_collision);
if (capsule) {
draw_capsule(surface_tool, capsule->get_radius(), capsule->get_height(), capsule->is_inside() ? inside_collision_color : collision_color);
return surface_tool->commit();
}
SpringBoneCollisionPlane3D *plane = Object::cast_to<SpringBoneCollisionPlane3D>(p_collision);
if (plane) {
draw_plane(surface_tool, collision_color);
return surface_tool->commit();
}
return surface_tool->commit();
}
void SpringBoneCollision3DGizmoPlugin::draw_sphere(Ref<SurfaceTool> &p_surface_tool, float p_radius, const Color &p_color) {
static const Vector3 VECTOR3_RIGHT = Vector3(1, 0, 0);
static const Vector3 VECTOR3_UP = Vector3(0, 1, 0);
static const Vector3 VECTOR3_FORWARD = Vector3(0, 0, 1);
static const int STEP = 16;
static const float SPPI = Math_TAU / (float)STEP;
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((VECTOR3_UP * p_radius).rotated(VECTOR3_RIGHT, SPPI * ((i - 1) % STEP)));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((VECTOR3_UP * p_radius).rotated(VECTOR3_RIGHT, SPPI * (i % STEP)));
}
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((VECTOR3_RIGHT * p_radius).rotated(VECTOR3_FORWARD, SPPI * ((i - 1) % STEP)));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((VECTOR3_RIGHT * p_radius).rotated(VECTOR3_FORWARD, SPPI * (i % STEP)));
}
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((VECTOR3_FORWARD * p_radius).rotated(VECTOR3_UP, SPPI * ((i - 1) % STEP)));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((VECTOR3_FORWARD * p_radius).rotated(VECTOR3_UP, SPPI * (i % STEP)));
}
}
void SpringBoneCollision3DGizmoPlugin::draw_capsule(Ref<SurfaceTool> &p_surface_tool, float p_radius, float p_height, const Color &p_color) {
static const Vector3 VECTOR3_RIGHT = Vector3(1, 0, 0);
static const Vector3 VECTOR3_UP = Vector3(0, 1, 0);
static const Vector3 VECTOR3_FORWARD = Vector3(0, 0, 1);
static const int STEP = 16;
static const int HALF_STEP = 8;
static const float SPPI = Math_TAU / (float)STEP;
static const float HALF_PI = Math_PI * 0.5;
Vector3 top = VECTOR3_UP * (p_height * 0.5 - p_radius);
Vector3 bottom = -top;
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((i - 1 < HALF_STEP ? top : bottom) + (VECTOR3_UP * p_radius).rotated(VECTOR3_RIGHT, -HALF_PI + SPPI * ((i - 1) % STEP)));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((i - 1 < HALF_STEP ? top : bottom) + (VECTOR3_UP * p_radius).rotated(VECTOR3_RIGHT, -HALF_PI + SPPI * (i % STEP)));
}
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((i - 1 < HALF_STEP ? top : bottom) + (VECTOR3_RIGHT * p_radius).rotated(VECTOR3_FORWARD, SPPI * ((i - 1) % STEP)));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex((i - 1 < HALF_STEP ? top : bottom) + (VECTOR3_RIGHT * p_radius).rotated(VECTOR3_FORWARD, SPPI * (i % STEP)));
}
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(top + (VECTOR3_FORWARD * p_radius).rotated(VECTOR3_UP, SPPI * ((i - 1) % STEP)));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(top + (VECTOR3_FORWARD * p_radius).rotated(VECTOR3_UP, SPPI * (i % STEP)));
}
for (int i = 1; i <= STEP; i++) {
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(bottom + (VECTOR3_FORWARD * p_radius).rotated(VECTOR3_UP, SPPI * ((i - 1) % STEP)));
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(bottom + (VECTOR3_FORWARD * p_radius).rotated(VECTOR3_UP, SPPI * (i % STEP)));
}
LocalVector<Vector3> directions;
directions.resize(4);
directions[0] = VECTOR3_RIGHT;
directions[1] = -VECTOR3_RIGHT;
directions[2] = VECTOR3_FORWARD;
directions[3] = -VECTOR3_FORWARD;
for (int i = 0; i < 4; i++) {
Vector3 dir = directions[i] * p_radius;
p_surface_tool->set_color(p_color);
p_surface_tool->add_vertex(top + dir);
p_surface_tool->add_vertex(bottom + dir);
}
}
void SpringBoneCollision3DGizmoPlugin::draw_plane(Ref<SurfaceTool> &p_surface_tool, const Color &p_color) {
static const Vector3 VECTOR3_UP = Vector3(0, 1, 0);
static const float HALF_PI = Math_PI * 0.5;
static const float ARROW_LENGTH = 0.3;
static const float ARROW_HALF_WIDTH = 0.05;
static const float ARROW_TOP_HALF_WIDTH = 0.1;
static const float ARROW_TOP = 0.5;
static const float RECT_SIZE = 1.0;
static const int RECT_STEP_COUNT = 9;
static const float RECT_HALF_SIZE = RECT_SIZE * 0.5;
static const float RECT_STEP = RECT_SIZE / (float)RECT_STEP_COUNT;
p_surface_tool->set_color(p_color);
// Draw arrow of the normal.
LocalVector<Vector3> arrow;
arrow.resize(7);
arrow[0] = Vector3(0, ARROW_TOP, 0);
arrow[1] = Vector3(-ARROW_TOP_HALF_WIDTH, ARROW_LENGTH, 0);
arrow[2] = Vector3(-ARROW_HALF_WIDTH, ARROW_LENGTH, 0);
arrow[3] = Vector3(-ARROW_HALF_WIDTH, 0, 0);
arrow[4] = Vector3(ARROW_HALF_WIDTH, 0, 0);
arrow[5] = Vector3(ARROW_HALF_WIDTH, ARROW_LENGTH, 0);
arrow[6] = Vector3(ARROW_TOP_HALF_WIDTH, ARROW_LENGTH, 0);
for (int i = 0; i < 2; i++) {
Basis ma(VECTOR3_UP, HALF_PI * i);
for (uint32_t j = 0; j < arrow.size(); j++) {
Vector3 v1 = arrow[j];
Vector3 v2 = arrow[(j + 1) % arrow.size()];
p_surface_tool->add_vertex(ma.xform(v1));
p_surface_tool->add_vertex(ma.xform(v2));
}
}
// Draw dashed line of the rect.
for (int i = 0; i < 4; i++) {
Basis ma(VECTOR3_UP, HALF_PI * i);
for (int j = 0; j < RECT_STEP_COUNT; j++) {
if (j % 2 == 1) {
continue;
}
Vector3 v1 = Vector3(RECT_HALF_SIZE, 0, RECT_HALF_SIZE - RECT_STEP * j);
Vector3 v2 = Vector3(RECT_HALF_SIZE, 0, RECT_HALF_SIZE - RECT_STEP * (j + 1));
p_surface_tool->add_vertex(ma.xform(v1));
p_surface_tool->add_vertex(ma.xform(v2));
}
}
}

View File

@ -0,0 +1,89 @@
/**************************************************************************/
/* spring_bone_3d_gizmo_plugin.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SPRING_BONE_3D_GIZMO_PLUGIN_H
#define SPRING_BONE_3D_GIZMO_PLUGIN_H
#include "editor/plugins/editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/spring_bone_collision_3d.h"
#include "scene/3d/spring_bone_simulator_3d.h"
#include "scene/resources/surface_tool.h"
class SpringBoneSimulator3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(SpringBoneSimulator3DGizmoPlugin, EditorNode3DGizmoPlugin);
struct SelectionMaterials {
Ref<StandardMaterial3D> unselected_mat;
Ref<ShaderMaterial> selected_mat;
};
static SelectionMaterials selection_materials;
public:
static Ref<ArrayMesh> get_joints_mesh(Skeleton3D *p_skeleton, SpringBoneSimulator3D *p_simulator, bool p_is_selected);
static void draw_sphere(Ref<SurfaceTool> &p_surface_tool, const Basis &p_basis, const Vector3 &p_center, float p_radius, const Color &p_color);
static void draw_line(Ref<SurfaceTool> &p_surface_tool, const Vector3 &p_begin_pos, const Vector3 &p_end_pos, const Color &p_color);
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
SpringBoneSimulator3DGizmoPlugin();
~SpringBoneSimulator3DGizmoPlugin();
};
class SpringBoneCollision3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(SpringBoneCollision3DGizmoPlugin, EditorNode3DGizmoPlugin);
struct SelectionMaterials {
Ref<StandardMaterial3D> unselected_mat;
Ref<ShaderMaterial> selected_mat;
};
static SelectionMaterials selection_materials;
public:
static Ref<ArrayMesh> get_collision_mesh(SpringBoneCollision3D *p_collision, bool p_is_selected);
static void draw_sphere(Ref<SurfaceTool> &p_surface_tool, float p_radius, const Color &p_color);
static void draw_capsule(Ref<SurfaceTool> &p_surface_tool, float p_radius, float p_height, const Color &p_color);
static void draw_plane(Ref<SurfaceTool> &p_surface_tool, const Color &p_color);
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
SpringBoneCollision3DGizmoPlugin();
~SpringBoneCollision3DGizmoPlugin();
};
#endif // SPRING_BONE_3D_GIZMO_PLUGIN_H

View File

@ -74,6 +74,7 @@
#include "editor/plugins/gizmos/shape_cast_3d_gizmo_plugin.h"
#include "editor/plugins/gizmos/soft_body_3d_gizmo_plugin.h"
#include "editor/plugins/gizmos/spring_arm_3d_gizmo_plugin.h"
#include "editor/plugins/gizmos/spring_bone_3d_gizmo_plugin.h"
#include "editor/plugins/gizmos/sprite_base_3d_gizmo_plugin.h"
#include "editor/plugins/gizmos/vehicle_body_3d_gizmo_plugin.h"
#include "editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.h"
@ -8555,6 +8556,8 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<RayCast3DGizmoPlugin>(memnew(RayCast3DGizmoPlugin)));
add_gizmo_plugin(Ref<ShapeCast3DGizmoPlugin>(memnew(ShapeCast3DGizmoPlugin)));
add_gizmo_plugin(Ref<SpringArm3DGizmoPlugin>(memnew(SpringArm3DGizmoPlugin)));
add_gizmo_plugin(Ref<SpringBoneCollision3DGizmoPlugin>(memnew(SpringBoneCollision3DGizmoPlugin)));
add_gizmo_plugin(Ref<SpringBoneSimulator3DGizmoPlugin>(memnew(SpringBoneSimulator3DGizmoPlugin)));
add_gizmo_plugin(Ref<VehicleWheel3DGizmoPlugin>(memnew(VehicleWheel3DGizmoPlugin)));
add_gizmo_plugin(Ref<VisibleOnScreenNotifier3DGizmoPlugin>(memnew(VisibleOnScreenNotifier3DGizmoPlugin)));
add_gizmo_plugin(Ref<GPUParticles3DGizmoPlugin>(memnew(GPUParticles3DGizmoPlugin)));

View File

@ -0,0 +1,192 @@
/**************************************************************************/
/* spring_bone_collision_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "spring_bone_collision_3d.h"
#include "scene/3d/spring_bone_simulator_3d.h"
PackedStringArray SpringBoneCollision3D::get_configuration_warnings() const {
PackedStringArray warnings = Node3D::get_configuration_warnings();
SpringBoneSimulator3D *parent = Object::cast_to<SpringBoneSimulator3D>(get_parent());
if (!parent) {
warnings.push_back(RTR("Parent node should be a SpringBoneSimulator3D node."));
}
return warnings;
}
void SpringBoneCollision3D::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "bone_name") {
Skeleton3D *sk = get_skeleton();
if (sk) {
p_property.hint = PROPERTY_HINT_ENUM_SUGGESTION;
p_property.hint_string = sk->get_concatenated_bone_names();
} else {
p_property.hint = PROPERTY_HINT_NONE;
p_property.hint_string = "";
}
} else if (bone < 0 && (p_property.name == "position_offset" || p_property.name == "rotation_offset")) {
p_property.usage = PROPERTY_USAGE_NONE;
}
}
Skeleton3D *SpringBoneCollision3D::get_skeleton() const {
SpringBoneSimulator3D *parent = Object::cast_to<SpringBoneSimulator3D>(get_parent());
if (!parent) {
return nullptr;
}
return parent->get_skeleton();
}
void SpringBoneCollision3D::set_bone_name(const String &p_name) {
bone_name = p_name;
Skeleton3D *sk = get_skeleton();
if (sk) {
set_bone(sk->find_bone(bone_name));
}
}
String SpringBoneCollision3D::get_bone_name() const {
return bone_name;
}
void SpringBoneCollision3D::set_bone(int p_bone) {
bone = p_bone;
Skeleton3D *sk = get_skeleton();
if (sk) {
if (bone <= -1 || bone >= sk->get_bone_count()) {
WARN_PRINT("Bone index out of range! Cannot connect BoneAttachment to node!");
bone = -1;
} else {
bone_name = sk->get_bone_name(bone);
}
}
notify_property_list_changed();
}
int SpringBoneCollision3D::get_bone() const {
return bone;
}
void SpringBoneCollision3D::set_position_offset(const Vector3 &p_offset) {
if (position_offset == p_offset) {
return;
}
position_offset = p_offset;
sync_pose();
#ifdef TOOLS_ENABLED
update_gizmos();
#endif // TOOLS_ENABLED
}
Vector3 SpringBoneCollision3D::get_position_offset() const {
return position_offset;
}
void SpringBoneCollision3D::set_rotation_offset(const Quaternion &p_offset) {
if (rotation_offset == p_offset) {
return;
}
rotation_offset = p_offset;
sync_pose();
#ifdef TOOLS_ENABLED
update_gizmos();
#endif // TOOLS_ENABLED
}
Quaternion SpringBoneCollision3D::get_rotation_offset() const {
return rotation_offset;
}
void SpringBoneCollision3D::sync_pose() {
if (bone >= 0) {
Skeleton3D *sk = get_skeleton();
if (sk) {
Transform3D tr = sk->get_global_transform() * sk->get_bone_global_pose(bone);
tr.origin += tr.basis.get_rotation_quaternion().xform(position_offset);
tr.basis *= Basis(rotation_offset);
set_global_transform(tr);
}
}
}
Transform3D SpringBoneCollision3D::get_transform_from_skeleton(const Transform3D &p_center) const {
Transform3D gtr = get_global_transform();
Skeleton3D *sk = get_skeleton();
if (sk) {
Transform3D tr = sk->get_global_transform();
gtr = tr.affine_inverse() * p_center * gtr;
}
return gtr;
}
void SpringBoneCollision3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_skeleton"), &SpringBoneCollision3D::get_skeleton);
ClassDB::bind_method(D_METHOD("set_bone_name", "bone_name"), &SpringBoneCollision3D::set_bone_name);
ClassDB::bind_method(D_METHOD("get_bone_name"), &SpringBoneCollision3D::get_bone_name);
ClassDB::bind_method(D_METHOD("set_bone", "bone"), &SpringBoneCollision3D::set_bone);
ClassDB::bind_method(D_METHOD("get_bone"), &SpringBoneCollision3D::get_bone);
ClassDB::bind_method(D_METHOD("set_position_offset", "offset"), &SpringBoneCollision3D::set_position_offset);
ClassDB::bind_method(D_METHOD("get_position_offset"), &SpringBoneCollision3D::get_position_offset);
ClassDB::bind_method(D_METHOD("set_rotation_offset", "offset"), &SpringBoneCollision3D::set_rotation_offset);
ClassDB::bind_method(D_METHOD("get_rotation_offset"), &SpringBoneCollision3D::get_rotation_offset);
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_bone", "get_bone");
ADD_GROUP("Offset", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position_offset"), "set_position_offset", "get_position_offset");
ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "rotation_offset"), "set_rotation_offset", "get_rotation_offset");
}
Vector3 SpringBoneCollision3D::collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const {
return _collide(p_center, p_bone_radius, p_bone_length, p_current);
}
Vector3 SpringBoneCollision3D::_collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const {
return Vector3(0, 0, 0);
}
#ifdef TOOLS_ENABLED
void SpringBoneCollision3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_EDITOR_PRE_SAVE: {
sync_pose();
} break;
}
}
#endif // TOOLS_ENABLED

View File

@ -0,0 +1,75 @@
/**************************************************************************/
/* spring_bone_collision_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SPRING_BONE_COLLISION_3D_H
#define SPRING_BONE_COLLISION_3D_H
#include "scene/3d/skeleton_3d.h"
class SpringBoneCollision3D : public Node3D {
GDCLASS(SpringBoneCollision3D, Node3D);
String bone_name;
int bone = -1;
Vector3 position_offset;
Quaternion rotation_offset;
protected:
PackedStringArray get_configuration_warnings() const override;
void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
#ifdef TOOLS_ENABLED
virtual void _notification(int p_what);
#endif // TOOLS_ENABLED
virtual Vector3 _collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const;
public:
Skeleton3D *get_skeleton() const;
void set_bone_name(const String &p_name);
String get_bone_name() const;
void set_bone(int p_bone);
int get_bone() const;
void set_position_offset(const Vector3 &p_offset);
Vector3 get_position_offset() const;
void set_rotation_offset(const Quaternion &p_offset);
Quaternion get_rotation_offset() const;
void sync_pose();
Transform3D get_transform_from_skeleton(const Transform3D &p_center) const;
Vector3 collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const;
};
#endif // SPRING_BONE_COLLISION_3D_H

View File

@ -0,0 +1,112 @@
/**************************************************************************/
/* spring_bone_collision_capsule_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "spring_bone_collision_capsule_3d.h"
#include "scene/3d/spring_bone_collision_sphere_3d.h"
void SpringBoneCollisionCapsule3D::set_radius(float p_radius) {
radius = p_radius;
if (radius > height * 0.5) {
height = radius * 2.0;
}
#ifdef TOOLS_ENABLED
update_gizmos();
#endif // TOOLS_ENABLED
}
float SpringBoneCollisionCapsule3D::get_radius() const {
return radius;
}
void SpringBoneCollisionCapsule3D::set_height(float p_height) {
height = p_height;
if (radius > height * 0.5) {
radius = height * 0.5;
}
#ifdef TOOLS_ENABLED
update_gizmos();
#endif // TOOLS_ENABLED
}
float SpringBoneCollisionCapsule3D::get_height() const {
return height;
}
void SpringBoneCollisionCapsule3D::set_inside(bool p_enabled) {
inside = p_enabled;
#ifdef TOOLS_ENABLED
update_gizmos();
#endif // TOOLS_ENABLED
}
bool SpringBoneCollisionCapsule3D::is_inside() const {
return inside;
}
Pair<Vector3, Vector3> SpringBoneCollisionCapsule3D::get_head_and_tail(const Transform3D &p_center) const {
static const Vector3 VECTOR3_UP = Vector3(0, 1, 0);
static const Vector3 VECTOR3_DOWN = Vector3(0, -1, 0);
Transform3D tr = get_transform_from_skeleton(p_center);
return Pair<Vector3, Vector3>(tr.origin + tr.basis.xform(VECTOR3_UP * (height * 0.5 - radius)), tr.origin + tr.basis.xform(VECTOR3_DOWN * (height * 0.5 - radius)));
}
void SpringBoneCollisionCapsule3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SpringBoneCollisionCapsule3D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &SpringBoneCollisionCapsule3D::get_radius);
ClassDB::bind_method(D_METHOD("set_height", "height"), &SpringBoneCollisionCapsule3D::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &SpringBoneCollisionCapsule3D::get_height);
ClassDB::bind_method(D_METHOD("set_inside", "enabled"), &SpringBoneCollisionCapsule3D::set_inside);
ClassDB::bind_method(D_METHOD("is_inside"), &SpringBoneCollisionCapsule3D::is_inside);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "inside"), "set_inside", "is_inside");
}
Vector3 SpringBoneCollisionCapsule3D::_collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const {
Pair<Vector3, Vector3> head_tail = get_head_and_tail(p_center);
Vector3 head = head_tail.first;
Vector3 tail = head_tail.second;
Vector3 p = tail - head;
Vector3 q = p_current - head;
float dot = p.dot(q);
if (dot <= 0) {
return SpringBoneCollisionSphere3D::_collide_sphere(head, radius, inside, p_bone_radius, p_bone_length, p_current);
}
float pls = p.length_squared();
if (Math::is_zero_approx(pls)) {
return p_current;
}
if (pls <= dot) {
return SpringBoneCollisionSphere3D::_collide_sphere(head + p, radius, inside, p_bone_radius, p_bone_length, p_current);
}
return SpringBoneCollisionSphere3D::_collide_sphere(head + p * (dot / pls), radius, inside, p_bone_radius, p_bone_length, p_current);
}

View File

@ -0,0 +1,60 @@
/**************************************************************************/
/* spring_bone_collision_capsule_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SPRING_BONE_COLLISION_CAPSULE_3D_H
#define SPRING_BONE_COLLISION_CAPSULE_3D_H
#include "scene/3d/spring_bone_collision_3d.h"
class SpringBoneCollisionCapsule3D : public SpringBoneCollision3D {
GDCLASS(SpringBoneCollisionCapsule3D, SpringBoneCollision3D);
float radius = 0.1;
float height = 0.5;
bool inside = false;
protected:
static void _bind_methods();
virtual Vector3 _collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const override;
public:
void set_radius(float p_radius);
float get_radius() const;
void set_height(float p_height);
float get_height() const;
void set_inside(bool p_enabled);
bool is_inside() const;
// Helper.
Pair<Vector3, Vector3> get_head_and_tail(const Transform3D &p_center) const;
};
#endif // SPRING_BONE_COLLISION_CAPSULE_3D_H

View File

@ -0,0 +1,44 @@
/**************************************************************************/
/* spring_bone_collision_plane_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "spring_bone_collision_plane_3d.h"
Vector3 SpringBoneCollisionPlane3D::_collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const {
static const Vector3 VECTOR3_UP = Vector3(0, 1, 0);
Transform3D tr = get_transform_from_skeleton(p_center);
Vector3 pos = tr.origin;
Vector3 normal = tr.basis.get_rotation_quaternion().xform(VECTOR3_UP);
Vector3 to_vec = p_current - pos;
float distance = to_vec.dot(normal) - p_bone_radius;
if (distance > 0) {
return p_current;
}
return p_current + normal * -distance;
}

View File

@ -0,0 +1,43 @@
/**************************************************************************/
/* spring_bone_collision_plane_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SPRING_BONE_COLLISION_PLANE_3D_H
#define SPRING_BONE_COLLISION_PLANE_3D_H
#include "scene/3d/spring_bone_collision_3d.h"
class SpringBoneCollisionPlane3D : public SpringBoneCollision3D {
GDCLASS(SpringBoneCollisionPlane3D, SpringBoneCollision3D);
protected:
virtual Vector3 _collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const override;
};
#endif // SPRING_BONE_COLLISION_PLANE_3D_H

View File

@ -0,0 +1,78 @@
/**************************************************************************/
/* spring_bone_collision_sphere_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "spring_bone_collision_sphere_3d.h"
void SpringBoneCollisionSphere3D::set_radius(float p_radius) {
radius = p_radius;
#ifdef TOOLS_ENABLED
update_gizmos();
#endif // TOOLS_ENABLED
}
float SpringBoneCollisionSphere3D::get_radius() const {
return radius;
}
void SpringBoneCollisionSphere3D::set_inside(bool p_enabled) {
inside = p_enabled;
#ifdef TOOLS_ENABLED
update_gizmos();
#endif // TOOLS_ENABLED
}
bool SpringBoneCollisionSphere3D::is_inside() const {
return inside;
}
void SpringBoneCollisionSphere3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &SpringBoneCollisionSphere3D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &SpringBoneCollisionSphere3D::get_radius);
ClassDB::bind_method(D_METHOD("set_inside", "enabled"), &SpringBoneCollisionSphere3D::set_inside);
ClassDB::bind_method(D_METHOD("is_inside"), &SpringBoneCollisionSphere3D::is_inside);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:m"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "inside"), "set_inside", "is_inside");
}
Vector3 SpringBoneCollisionSphere3D::_collide_sphere(const Vector3 &p_origin, float p_radius, bool p_inside, float p_bone_radius, float p_bone_length, const Vector3 &p_current) {
Vector3 diff = p_current - p_origin;
float length = diff.length();
float r = p_inside ? p_radius - p_bone_radius : p_bone_radius + p_radius;
float distance = p_inside ? r - length : length - r;
if (distance > 0) {
return p_current;
}
return p_origin + diff.normalized() * r;
}
Vector3 SpringBoneCollisionSphere3D::_collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const {
return _collide_sphere(get_transform_from_skeleton(p_center).origin, radius, inside, p_bone_radius, p_bone_length, p_current);
}

View File

@ -0,0 +1,59 @@
/**************************************************************************/
/* spring_bone_collision_sphere_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SPRING_BONE_COLLISION_SPHERE_3D_H
#define SPRING_BONE_COLLISION_SPHERE_3D_H
#include "scene/3d/spring_bone_collision_3d.h"
class SpringBoneCollisionCapsule3D;
class SpringBoneCollisionSphere3D : public SpringBoneCollision3D {
GDCLASS(SpringBoneCollisionSphere3D, SpringBoneCollision3D);
friend class SpringBoneCollisionCapsule3D;
float radius = 0.1;
bool inside = false;
protected:
static void _bind_methods();
static Vector3 _collide_sphere(const Vector3 &p_origin, float p_radius, bool p_inside, float p_bone_radius, float p_bone_length, const Vector3 &p_current);
virtual Vector3 _collide(const Transform3D &p_center, float p_bone_radius, float p_bone_length, const Vector3 &p_current) const override;
public:
void set_radius(float p_radius);
float get_radius() const;
void set_inside(bool p_enabled);
bool is_inside() const;
};
#endif // SPRING_BONE_COLLISION_SPHERE_3D_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,281 @@
/**************************************************************************/
/* spring_bone_simulator_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SPRING_BONE_SIMULATOR_3D_H
#define SPRING_BONE_SIMULATOR_3D_H
#include "scene/3d/skeleton_modifier_3d.h"
class SpringBoneSimulator3D : public SkeletonModifier3D {
GDCLASS(SpringBoneSimulator3D, SkeletonModifier3D);
bool joints_dirty = false;
LocalVector<ObjectID> collisions; // To process collisions for sync position with skeleton.
bool collisions_dirty = false;
void _find_collisions();
void _process_collisions();
void _make_collisions_dirty();
public:
enum BoneDirection {
BONE_DIRECTION_PLUS_X,
BONE_DIRECTION_MINUS_X,
BONE_DIRECTION_PLUS_Y,
BONE_DIRECTION_MINUS_Y,
BONE_DIRECTION_PLUS_Z,
BONE_DIRECTION_MINUS_Z,
BONE_DIRECTION_FROM_PARENT,
};
enum CenterFrom {
CENTER_FROM_WORLD_ORIGIN,
CENTER_FROM_NODE,
CENTER_FROM_BONE,
};
enum RotationAxis {
ROTATION_AXIS_X,
ROTATION_AXIS_Y,
ROTATION_AXIS_Z,
ROTATION_AXIS_ALL,
};
struct SpringBone3DVerletInfo {
Vector3 prev_tail;
Vector3 current_tail;
Vector3 forward_vector;
float length = 0.0;
};
struct SpringBone3DJointSetting {
String bone_name;
int bone = -1;
RotationAxis rotation_axis = ROTATION_AXIS_ALL;
float radius = 0.1;
float stiffness = 1.0;
float drag = 0.0;
float gravity = 0.0;
Vector3 gravity_direction = Vector3(0, -1, 0);
// To process.
SpringBone3DVerletInfo *verlet = nullptr;
};
struct SpringBone3DSetting {
bool joints_dirty = false;
String root_bone_name;
int root_bone = -1;
String end_bone_name;
int end_bone = -1;
// To make virtual end joint.
bool extend_end_bone = false;
BoneDirection end_bone_direction = BONE_DIRECTION_FROM_PARENT;
float end_bone_length = 0.0;
float end_bone_tip_radius = 0.02;
CenterFrom center_from = CENTER_FROM_WORLD_ORIGIN;
NodePath center_node;
String center_bone_name;
int center_bone = -1;
// Cache into joints.
bool individual_config = false;
float radius = 0.02;
Ref<Curve> radius_damping_curve;
float stiffness = 1.0;
Ref<Curve> stiffness_damping_curve;
float drag = 0.4;
Ref<Curve> drag_damping_curve;
float gravity = 0.0;
Ref<Curve> gravity_damping_curve;
Vector3 gravity_direction = Vector3(0, -1, 0);
RotationAxis rotation_axis = ROTATION_AXIS_ALL;
Vector<SpringBone3DJointSetting *> joints;
// Cache into collisions.
bool enable_all_child_collisions = true;
Vector<NodePath> collisions;
Vector<NodePath> exclude_collisions;
LocalVector<ObjectID> cached_collisions;
// To process.
bool simulation_dirty = false;
Transform3D cached_center;
Transform3D cached_inverted_center;
};
protected:
Vector<SpringBone3DSetting *> settings;
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_list) const;
void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
virtual void _set_active(bool p_active) override;
virtual void _process_modification() override;
void _init_joints(Skeleton3D *p_skeleton, SpringBone3DSetting *p_setting);
void _process_joints(double p_delta, Skeleton3D *p_skeleton, Vector<SpringBone3DJointSetting *> &p_joints, const LocalVector<ObjectID> &p_collisions, const Transform3D &p_center_transform, const Transform3D &p_inverted_center_transform, const Quaternion &p_inverted_center_rotation);
void _make_joints_dirty(int p_index);
void _make_all_joints_dirty();
void _update_joint_array(int p_index);
void _update_joints();
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
public:
// Setting.
void set_root_bone_name(int p_index, const String &p_bone_name);
String get_root_bone_name(int p_index) const;
void set_root_bone(int p_index, int p_bone);
int get_root_bone(int p_index) const;
void set_end_bone_name(int p_index, const String &p_bone_name);
String get_end_bone_name(int p_index) const;
void set_end_bone(int p_index, int p_bone);
int get_end_bone(int p_index) const;
void set_extend_end_bone(int p_index, bool p_enabled);
bool is_end_bone_extended(int p_index) const;
void set_end_bone_direction(int p_index, BoneDirection p_bone_direction);
BoneDirection get_end_bone_direction(int p_index) const;
void set_end_bone_length(int p_index, float p_length);
float get_end_bone_length(int p_index) const;
void set_end_bone_tip_radius(int p_index, float p_radius);
float get_end_bone_tip_radius(int p_index) const;
Vector3 get_end_bone_axis(int p_end_bone, BoneDirection p_direction) const; // Helper.
void set_center_from(int p_index, CenterFrom p_center_from);
CenterFrom get_center_from(int p_index) const;
void set_center_node(int p_index, const NodePath &p_node_path);
NodePath get_center_node(int p_index) const;
void set_center_bone_name(int p_index, const String &p_bone_name);
String get_center_bone_name(int p_index) const;
void set_center_bone(int p_index, int p_bone);
int get_center_bone(int p_index) const;
void set_rotation_axis(int p_index, RotationAxis p_axis);
RotationAxis get_rotation_axis(int p_index) const;
void set_radius(int p_index, float p_radius);
float get_radius(int p_index) const;
void set_radius_damping_curve(int p_index, const Ref<Curve> &p_damping_curve);
Ref<Curve> get_radius_damping_curve(int p_index) const;
void set_stiffness(int p_index, float p_stiffness);
float get_stiffness(int p_index) const;
void set_stiffness_damping_curve(int p_index, const Ref<Curve> &p_damping_curve);
Ref<Curve> get_stiffness_damping_curve(int p_index) const;
void set_drag(int p_index, float p_drag);
float get_drag(int p_index) const;
void set_drag_damping_curve(int p_index, const Ref<Curve> &p_damping_curve);
Ref<Curve> get_drag_damping_curve(int p_index) const;
void set_gravity(int p_index, float p_gravity);
float get_gravity(int p_index) const;
void set_gravity_damping_curve(int p_index, const Ref<Curve> &p_damping_curve);
Ref<Curve> get_gravity_damping_curve(int p_index) const;
void set_gravity_direction(int p_index, const Vector3 &p_gravity_direction);
Vector3 get_gravity_direction(int p_index) const;
void set_setting_count(int p_count);
int get_setting_count() const;
void clear_settings();
// Individual joints.
void set_individual_config(int p_index, bool p_enabled);
bool is_config_individual(int p_index) const;
void set_joint_bone_name(int p_index, int p_joint, const String &p_bone_name);
String get_joint_bone_name(int p_index, int p_joint) const;
void set_joint_bone(int p_index, int p_joint, int p_bone);
int get_joint_bone(int p_index, int p_joint) const;
void set_joint_rotation_axis(int p_index, int p_joint, RotationAxis p_axis);
RotationAxis get_joint_rotation_axis(int p_index, int p_joint) const;
void set_joint_radius(int p_index, int p_joint, float p_radius);
float get_joint_radius(int p_index, int p_joint) const;
void set_joint_stiffness(int p_index, int p_joint, float p_stiffness);
float get_joint_stiffness(int p_index, int p_joint) const;
void set_joint_drag(int p_index, int p_joint, float p_drag);
float get_joint_drag(int p_index, int p_joint) const;
void set_joint_gravity(int p_index, int p_joint, float p_gravity);
float get_joint_gravity(int p_index, int p_joint) const;
void set_joint_gravity_direction(int p_index, int p_joint, const Vector3 &p_gravity_direction);
Vector3 get_joint_gravity_direction(int p_index, int p_joint) const;
void set_joint_count(int p_index, int p_count);
int get_joint_count(int p_index) const;
// Individual collisions.
void set_enable_all_child_collisions(int p_index, bool p_enabled);
bool are_all_child_collisions_enabled(int p_index) const;
void set_exclude_collision_path(int p_index, int p_collision, const NodePath &p_node_path);
NodePath get_exclude_collision_path(int p_index, int p_collision) const;
void set_exclude_collision_count(int p_index, int p_count);
int get_exclude_collision_count(int p_index) const;
void clear_exclude_collisions(int p_index);
void set_collision_path(int p_index, int p_collision, const NodePath &p_node_path);
NodePath get_collision_path(int p_index, int p_collision) const;
void set_collision_count(int p_index, int p_count);
int get_collision_count(int p_index) const;
void clear_collisions(int p_index);
LocalVector<ObjectID> get_valid_collision_instance_ids(int p_index);
// Helper.
static Quaternion get_local_pose_rotation(Skeleton3D *p_skeleton, int p_bone, const Quaternion &p_global_pose_rotation);
static Quaternion get_from_to_rotation(const Vector3 &p_from, const Vector3 &p_to);
static Vector3 snap_position_to_plane(const Transform3D &p_rest, RotationAxis p_axis, const Vector3 &p_position);
static Vector3 limit_length(const Vector3 &p_origin, const Vector3 &p_destination, float p_length);
// To process manually.
void reset();
};
VARIANT_ENUM_CAST(SpringBoneSimulator3D::BoneDirection);
VARIANT_ENUM_CAST(SpringBoneSimulator3D::CenterFrom);
VARIANT_ENUM_CAST(SpringBoneSimulator3D::RotationAxis);
#endif // SPRING_BONE_SIMULATOR_3D_H

View File

@ -284,6 +284,11 @@
#include "scene/3d/skeleton_ik_3d.h"
#include "scene/3d/skeleton_modifier_3d.h"
#include "scene/3d/soft_body_3d.h"
#include "scene/3d/spring_bone_collision_3d.h"
#include "scene/3d/spring_bone_collision_capsule_3d.h"
#include "scene/3d/spring_bone_collision_plane_3d.h"
#include "scene/3d/spring_bone_collision_sphere_3d.h"
#include "scene/3d/spring_bone_simulator_3d.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/visible_on_screen_notifier_3d.h"
#include "scene/3d/voxel_gi.h"
@ -600,6 +605,11 @@ void register_scene_types() {
GDREGISTER_CLASS(RootMotionView);
GDREGISTER_VIRTUAL_CLASS(SkeletonModifier3D);
GDREGISTER_CLASS(RetargetModifier3D);
GDREGISTER_CLASS(SpringBoneSimulator3D);
GDREGISTER_VIRTUAL_CLASS(SpringBoneCollision3D);
GDREGISTER_CLASS(SpringBoneCollisionSphere3D);
GDREGISTER_CLASS(SpringBoneCollisionCapsule3D);
GDREGISTER_CLASS(SpringBoneCollisionPlane3D);
OS::get_singleton()->yield(); // may take time to init