diff options
60 files changed, 1384 insertions, 931 deletions
diff --git a/doc/classes/AnimatableBody2D.xml b/doc/classes/AnimatableBody2D.xml new file mode 100644 index 0000000000..731c702549 --- /dev/null +++ b/doc/classes/AnimatableBody2D.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimatableBody2D" inherits="StaticBody2D" version="4.0"> + <brief_description> + Physics body for 2D physics which moves only by script or animation. Useful for moving platforms and doors. + </brief_description> + <description> + Animatable body for 2D physics. + An animatable body can't be moved by external forces or contacts, but can be moved by script or animation to affect other bodies in its path. It is ideal for implementing moving objects in the environment, such as moving platforms or doors. + When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false"> + If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method PhysicsBody2D.move_and_collide]. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/AnimatableBody3D.xml b/doc/classes/AnimatableBody3D.xml new file mode 100644 index 0000000000..8192f26057 --- /dev/null +++ b/doc/classes/AnimatableBody3D.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimatableBody3D" inherits="StaticBody3D" version="4.0"> + <brief_description> + Physics body for 3D physics which moves only by script or animation. Useful for moving platforms and doors. + </brief_description> + <description> + Animatable body for 3D physics. + An animatable body can't be moved by external forces or contacts, but can be moved by script or animation to affect other bodies in its path. It is ideal for implementing moving objects in the environment, such as moving platforms or doors. + When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). + </description> + <tutorials> + <link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link> + <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link> + <link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link> + </tutorials> + <methods> + </methods> + <members> + <member name="sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false"> + If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method PhysicsBody3D.move_and_collide]. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml index 71e6eeab5a..f98c22a1e9 100644 --- a/doc/classes/CharacterBody2D.xml +++ b/doc/classes/CharacterBody2D.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="CharacterBody2D" inherits="PhysicsBody2D" version="4.0"> <brief_description> - Character body 2D node. + Specialized 2D physics body node for characters moved by script. </brief_description> <description> - Character bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a rigid body, these are the same as a static body. However, they have two main uses: - [b]Kinematic characters:[/b] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics. - [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [member StaticBody3D.kinematic_motion] when enabled), which allows them to be moved by code and push other bodies on their path. + Character bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a rigid body, these are the same as a [AnimatableBody2D]. However, they have two main uses: + [b]Kinematic characters:[/b] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody2D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics. + [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [AnimatableBody2D]), which allows them to be moved by code and push other bodies on their path. </description> <tutorials> <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link> diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml index 85135d5509..81ffbe01c1 100644 --- a/doc/classes/CharacterBody3D.xml +++ b/doc/classes/CharacterBody3D.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="CharacterBody3D" inherits="PhysicsBody3D" version="4.0"> <brief_description> - Character body 3D node. + Specialized 3D physics body node for characters moved by script. </brief_description> <description> - Character bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a rigid body, these are the same as a static body. However, they have two main uses: + Character bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a rigid body, these are the same as a [AnimatableBody3D]. However, they have two main uses: [b]Kinematic characters:[/b] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics. - [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [member StaticBody3D.kinematic_motion] when enabled), which allows them to be moved by code and push other bodies on their path. + [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [AnimatableBody3D]), which allows them to be moved by code and push other bodies on their path. </description> <tutorials> <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link> diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml index 4c6adfca32..8698fbec61 100644 --- a/doc/classes/PhysicsDirectBodyState2D.xml +++ b/doc/classes/PhysicsDirectBodyState2D.xml @@ -155,6 +155,9 @@ <member name="angular_velocity" type="float" setter="set_angular_velocity" getter="get_angular_velocity"> The body's rotational velocity. </member> + <member name="center_of_mass" type="Vector2" setter="" getter="get_center_of_mass"> + The body's center of mass. + </member> <member name="inverse_inertia" type="float" setter="" getter="get_inverse_inertia"> The inverse of the inertia of the body. </member> diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml index 271668e339..4599f86423 100644 --- a/doc/classes/PhysicsDirectBodyState3D.xml +++ b/doc/classes/PhysicsDirectBodyState3D.xml @@ -157,6 +157,7 @@ The body's rotational velocity. </member> <member name="center_of_mass" type="Vector3" setter="" getter="get_center_of_mass"> + The body's center of mass. </member> <member name="inverse_inertia" type="Vector3" setter="" getter="get_inverse_inertia"> The inverse of the inertia of the body. diff --git a/doc/classes/PhysicsDirectSpaceState2D.xml b/doc/classes/PhysicsDirectSpaceState2D.xml index e84b3e0e49..64e0fa4050 100644 --- a/doc/classes/PhysicsDirectSpaceState2D.xml +++ b/doc/classes/PhysicsDirectSpaceState2D.xml @@ -47,7 +47,7 @@ <argument index="0" name="point" type="Vector2" /> <argument index="1" name="max_results" type="int" default="32" /> <argument index="2" name="exclude" type="Array" default="[]" /> - <argument index="3" name="collision_mask" type="int" default="2147483647" /> + <argument index="3" name="collision_mask" type="int" default="4294967295" /> <argument index="4" name="collide_with_bodies" type="bool" default="true" /> <argument index="5" name="collide_with_areas" type="bool" default="false" /> <description> @@ -57,7 +57,7 @@ [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method PhysicsServer2D.shape_set_data]. [code]rid[/code]: The intersecting object's [RID]. [code]shape[/code]: The shape index of the colliding shape. - Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect, or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively. + Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect (all layers by default), or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively. [b]Note:[/b] [ConcavePolygonShape2D]s and [CollisionPolygon2D]s in [code]Segments[/code] build mode are not solid shapes. Therefore, they will not be detected. </description> </method> @@ -67,10 +67,18 @@ <argument index="1" name="canvas_instance_id" type="int" /> <argument index="2" name="max_results" type="int" default="32" /> <argument index="3" name="exclude" type="Array" default="[]" /> - <argument index="4" name="collision_mask" type="int" default="2147483647" /> + <argument index="4" name="collision_mask" type="int" default="4294967295" /> <argument index="5" name="collide_with_bodies" type="bool" default="true" /> <argument index="6" name="collide_with_areas" type="bool" default="false" /> <description> + Checks whether a point is inside any solid shape, in a specific canvas layer given by [code]canvas_instance_id[/code]. The shapes the point is inside of are returned in an array containing dictionaries with the following fields: + [code]collider[/code]: The colliding object. + [code]collider_id[/code]: The colliding object's ID. + [code]metadata[/code]: The intersecting shape's metadata. This metadata is different from [method Object.get_meta], and is set with [method PhysicsServer2D.shape_set_data]. + [code]rid[/code]: The intersecting object's [RID]. + [code]shape[/code]: The shape index of the colliding shape. + Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect (all layers by default), or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively. + [b]Note:[/b] [ConcavePolygonShape2D]s and [CollisionPolygon2D]s in [code]Segments[/code] build mode are not solid shapes. Therefore, they will not be detected. </description> </method> <method name="intersect_ray"> @@ -78,7 +86,7 @@ <argument index="0" name="from" type="Vector2" /> <argument index="1" name="to" type="Vector2" /> <argument index="2" name="exclude" type="Array" default="[]" /> - <argument index="3" name="collision_mask" type="int" default="2147483647" /> + <argument index="3" name="collision_mask" type="int" default="4294967295" /> <argument index="4" name="collide_with_bodies" type="bool" default="true" /> <argument index="5" name="collide_with_areas" type="bool" default="false" /> <description> @@ -91,7 +99,7 @@ [code]rid[/code]: The intersecting object's [RID]. [code]shape[/code]: The shape index of the colliding shape. If the ray did not intersect anything, then an empty dictionary is returned instead. - Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect, or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively. + Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect (all layers by default), or booleans to determine if the ray should collide with [PhysicsBody2D]s or [Area2D]s, respectively. </description> </method> <method name="intersect_shape"> diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml index 13db50a2c7..360d6e8e92 100644 --- a/doc/classes/PhysicsDirectSpaceState3D.xml +++ b/doc/classes/PhysicsDirectSpaceState3D.xml @@ -47,7 +47,7 @@ <argument index="0" name="from" type="Vector3" /> <argument index="1" name="to" type="Vector3" /> <argument index="2" name="exclude" type="Array" default="[]" /> - <argument index="3" name="collision_mask" type="int" default="2147483647" /> + <argument index="3" name="collision_mask" type="int" default="4294967295" /> <argument index="4" name="collide_with_bodies" type="bool" default="true" /> <argument index="5" name="collide_with_areas" type="bool" default="false" /> <description> @@ -59,7 +59,7 @@ [code]rid[/code]: The intersecting object's [RID]. [code]shape[/code]: The shape index of the colliding shape. If the ray did not intersect anything, then an empty dictionary is returned instead. - Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect, or booleans to determine if the ray should collide with [PhysicsBody3D]s or [Area3D]s, respectively. + Additionally, the method can take an [code]exclude[/code] array of objects or [RID]s that are to be excluded from collisions, a [code]collision_mask[/code] bitmask representing the physics layers to detect (all layers by default), or booleans to determine if the ray should collide with [PhysicsBody3D]s or [Area3D]s, respectively. </description> </method> <method name="intersect_shape"> diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml index 9867b98ae6..b3b7fcd956 100644 --- a/doc/classes/PhysicsServer2D.xml +++ b/doc/classes/PhysicsServer2D.xml @@ -373,7 +373,7 @@ </description> </method> <method name="body_get_param" qualifiers="const"> - <return type="float" /> + <return type="Variant" /> <argument index="0" name="body" type="RID" /> <argument index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" /> <description> @@ -449,6 +449,13 @@ Removes a shape from a body. The shape is not deleted, so it can be reused afterwards. </description> </method> + <method name="body_reset_mass_properties"> + <return type="void" /> + <argument index="0" name="body" type="RID" /> + <description> + Restores the default inertia and center of mass based on shapes to cancel any custom values previously set using [method body_set_param]. + </description> + </method> <method name="body_set_axis_velocity"> <return type="void" /> <argument index="0" name="body" type="RID" /> @@ -522,7 +529,7 @@ <return type="void" /> <argument index="0" name="body" type="RID" /> <argument index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" /> - <argument index="2" name="value" type="float" /> + <argument index="2" name="value" type="Variant" /> <description> Sets a body parameter. See [enum BodyParameter] for a list of available parameters. </description> @@ -913,7 +920,7 @@ This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one. </constant> <constant name="BODY_MODE_STATIC" value="0" enum="BodyMode"> - Constant for static bodies. In this mode, a body can be only moved by user code. + Constant for static bodies. In this mode, a body can be only moved by user code and doesn't collide with other bodies along its path when moved. </constant> <constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode"> Constant for kinematic bodies. In this mode, a body can be only moved by user code and collides with other bodies along its path. @@ -936,16 +943,19 @@ <constant name="BODY_PARAM_INERTIA" value="3" enum="BodyParameter"> Constant to set/get a body's inertia. </constant> - <constant name="BODY_PARAM_GRAVITY_SCALE" value="4" enum="BodyParameter"> + <constant name="BODY_PARAM_CENTER_OF_MASS" value="4" enum="BodyParameter"> + Constant to set/get a body's center of mass. + </constant> + <constant name="BODY_PARAM_GRAVITY_SCALE" value="5" enum="BodyParameter"> Constant to set/get a body's gravity multiplier. </constant> - <constant name="BODY_PARAM_LINEAR_DAMP" value="5" enum="BodyParameter"> + <constant name="BODY_PARAM_LINEAR_DAMP" value="6" enum="BodyParameter"> Constant to set/get a body's linear dampening factor. </constant> - <constant name="BODY_PARAM_ANGULAR_DAMP" value="6" enum="BodyParameter"> + <constant name="BODY_PARAM_ANGULAR_DAMP" value="7" enum="BodyParameter"> Constant to set/get a body's angular dampening factor. </constant> - <constant name="BODY_PARAM_MAX" value="7" enum="BodyParameter"> + <constant name="BODY_PARAM_MAX" value="8" enum="BodyParameter"> Represents the size of the [enum BodyParameter] enum. </constant> <constant name="BODY_STATE_TRANSFORM" value="0" enum="BodyState"> diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 46cbe48b28..2fbe84b8b1 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -347,7 +347,7 @@ </description> </method> <method name="body_get_param" qualifiers="const"> - <return type="float" /> + <return type="Variant" /> <argument index="0" name="body" type="RID" /> <argument index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" /> <description> @@ -430,6 +430,13 @@ Removes a shape from a body. The shape is not deleted, so it can be reused afterwards. </description> </method> + <method name="body_reset_mass_properties"> + <return type="void" /> + <argument index="0" name="body" type="RID" /> + <description> + Restores the default inertia and center of mass based on shapes to cancel any custom values previously set using [method body_set_param]. + </description> + </method> <method name="body_set_axis_lock"> <return type="void" /> <argument index="0" name="body" type="RID" /> @@ -511,7 +518,7 @@ <return type="void" /> <argument index="0" name="body" type="RID" /> <argument index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" /> - <argument index="2" name="value" type="float" /> + <argument index="2" name="value" type="Variant" /> <description> Sets a body parameter. A list of available parameters is on the [enum BodyParameter] constants. </description> @@ -1262,7 +1269,7 @@ This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one. </constant> <constant name="BODY_MODE_STATIC" value="0" enum="BodyMode"> - Constant for static bodies. In this mode, a body can be only moved by user code. + Constant for static bodies. In this mode, a body can be only moved by user code and doesn't collide with other bodies along its path when moved. </constant> <constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode"> Constant for kinematic bodies. In this mode, a body can be only moved by user code and collides with other bodies along its path. @@ -1282,16 +1289,22 @@ <constant name="BODY_PARAM_MASS" value="2" enum="BodyParameter"> Constant to set/get a body's mass. </constant> - <constant name="BODY_PARAM_GRAVITY_SCALE" value="3" enum="BodyParameter"> + <constant name="BODY_PARAM_INERTIA" value="3" enum="BodyParameter"> + Constant to set/get a body's inertia. + </constant> + <constant name="BODY_PARAM_CENTER_OF_MASS" value="4" enum="BodyParameter"> + Constant to set/get a body's center of mass. + </constant> + <constant name="BODY_PARAM_GRAVITY_SCALE" value="5" enum="BodyParameter"> Constant to set/get a body's gravity multiplier. </constant> - <constant name="BODY_PARAM_LINEAR_DAMP" value="4" enum="BodyParameter"> + <constant name="BODY_PARAM_LINEAR_DAMP" value="6" enum="BodyParameter"> Constant to set/get a body's linear dampening factor. </constant> - <constant name="BODY_PARAM_ANGULAR_DAMP" value="5" enum="BodyParameter"> + <constant name="BODY_PARAM_ANGULAR_DAMP" value="7" enum="BodyParameter"> Constant to set/get a body's angular dampening factor. </constant> - <constant name="BODY_PARAM_MAX" value="6" enum="BodyParameter"> + <constant name="BODY_PARAM_MAX" value="8" enum="BodyParameter"> Represents the size of the [enum BodyParameter] enum. </constant> <constant name="BODY_STATE_TRANSFORM" value="0" enum="BodyState"> diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml index 8b006c68e7..b54de15d15 100644 --- a/doc/classes/PhysicsShapeQueryParameters2D.xml +++ b/doc/classes/PhysicsShapeQueryParameters2D.xml @@ -17,7 +17,7 @@ <member name="collide_with_bodies" type="bool" setter="set_collide_with_bodies" getter="is_collide_with_bodies_enabled" default="true"> If [code]true[/code], the query will take [PhysicsBody2D]s into account. </member> - <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="2147483647"> + <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="4294967295"> The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]"> diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml index de9b623591..f74d1b5e48 100644 --- a/doc/classes/PhysicsShapeQueryParameters3D.xml +++ b/doc/classes/PhysicsShapeQueryParameters3D.xml @@ -17,7 +17,7 @@ <member name="collide_with_bodies" type="bool" setter="set_collide_with_bodies" getter="is_collide_with_bodies_enabled" default="true"> If [code]true[/code], the query will take [PhysicsBody3D]s into account. </member> - <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="2147483647"> + <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="4294967295"> The physics layers the query will detect (as a bitmask). By default, all collision layers are detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]"> diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml index db16552db3..0702955495 100644 --- a/doc/classes/RigidBody2D.xml +++ b/doc/classes/RigidBody2D.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="RigidBody2D" inherits="PhysicsBody2D" version="4.0"> <brief_description> - A body that is controlled by the 2D physics engine. + Physics Body which is moved by 2D physics simulation. Useful for objects that have gravity and can be pushed by other objects. </brief_description> <description> This node implements simulated 2D physics. You do not control a RigidBody2D directly. Instead, you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties. @@ -99,6 +99,13 @@ <member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true"> If [code]true[/code], the body can enter sleep mode when there is no movement. See [member sleeping]. </member> + <member name="center_of_mass" type="Vector2" setter="set_center_of_mass" getter="get_center_of_mass" default="Vector2(0, 0)"> + The body's custom center of mass, relative to the body's origin position, when [member center_of_mass_mode] is set to [constant CENTER_OF_MASS_MODE_CUSTOM]. This is the balanced point of the body, where applied forces only cause linear acceleration. Applying forces outside of the center of mass causes angular acceleration. + When [member center_of_mass_mode] is set to [constant CENTER_OF_MASS_MODE_AUTO] (default value), the center of mass is automatically computed. + </member> + <member name="center_of_mass_mode" type="int" setter="set_center_of_mass_mode" getter="get_center_of_mass_mode" enum="RigidBody2D.CenterOfMassMode" default="0"> + Defines the way the body's center of mass is set. See [enum CenterOfMassMode] for possible values. + </member> <member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false"> If [code]true[/code], the body will emit signals when it collides with another RigidBody2D. See also [member contacts_reported]. </member> @@ -116,8 +123,9 @@ <member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0"> Multiplies the gravity applied to the body. The body's gravity is calculated from the [b]Default Gravity[/b] value in [b]Project > Project Settings > Physics > 2d[/b] and/or any additional gravity vector applied by [Area2D]s. </member> - <member name="inertia" type="float" setter="set_inertia" getter="get_inertia"> - The body's moment of inertia. This is like mass, but for rotation: it determines how much torque it takes to rotate the body. The moment of inertia is usually computed automatically from the mass and the shapes, but this function allows you to set a custom value. Set 0 inertia to return to automatically computing it. + <member name="inertia" type="float" setter="set_inertia" getter="get_inertia" default="0.0"> + The body's moment of inertia. This is like mass, but for rotation: it determines how much torque it takes to rotate the body. The moment of inertia is usually computed automatically from the mass and the shapes, but this property allows you to set a custom value. + If set to [code]0[/code], inertia is automatically computed (default value). </member> <member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="-1.0"> Damps the body's [member linear_velocity]. If [code]-1[/code], the body will use the [b]Default Linear Damp[/b] in [b]Project > Project Settings > Physics > 2d[/b]. @@ -131,6 +139,7 @@ </member> <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="RigidBody2D.Mode" default="0"> The body's mode. See [enum Mode] for possible values. + For a body that uses only Static or Kinematic mode, use [StaticBody2D] or [AnimatableBody2D] instead. </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. @@ -199,7 +208,13 @@ Locked dynamic body mode. Similar to [constant MODE_DYNAMIC], but the body can not rotate. </constant> <constant name="MODE_KINEMATIC" value="3" enum="Mode"> - Kinematic body mode. The body behaves like a [StaticBody2D] with [member StaticBody2D.kinematic_motion] enabled, and must be moved by user code. + Kinematic body mode. The body behaves like a [AnimatableBody2D], and must be moved by code. + </constant> + <constant name="CENTER_OF_MASS_MODE_AUTO" value="0" enum="CenterOfMassMode"> + In this mode, the body's center of mass is calculated automatically based on its shapes. + </constant> + <constant name="CENTER_OF_MASS_MODE_CUSTOM" value="1" enum="CenterOfMassMode"> + In this mode, the body's center of mass is set through [member center_of_mass]. Defaults to the body's origin position. </constant> <constant name="CCD_MODE_DISABLED" value="0" enum="CCDMode"> Continuous collision detection disabled. This is the fastest way to detect body collisions, but can miss small, fast-moving objects. diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml index f4299335bf..1be35b0576 100644 --- a/doc/classes/RigidBody3D.xml +++ b/doc/classes/RigidBody3D.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="RigidBody3D" inherits="PhysicsBody3D" version="4.0"> <brief_description> - Physics Body whose position is determined through physics simulation in 3D space. + Physics Body which is moved by 3D physics simulation. Useful for objects that have gravity and can be pushed by other objects. </brief_description> <description> This is the node that implements full 3D physics. This means that you do not control a RigidBody3D directly. Instead, you can apply forces to it (gravity, impulses, etc.), and the physics simulation will calculate the resulting movement, collision, bouncing, rotating, etc. @@ -102,6 +102,13 @@ <member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true"> If [code]true[/code], the body can enter sleep mode when there is no movement. See [member sleeping]. </member> + <member name="center_of_mass" type="Vector3" setter="set_center_of_mass" getter="get_center_of_mass" default="Vector3(0, 0, 0)"> + The body's custom center of mass, relative to the body's origin position, when [member center_of_mass_mode] is set to [constant CENTER_OF_MASS_MODE_CUSTOM]. This is the balanced point of the body, where applied forces only cause linear acceleration. Applying forces outside of the center of mass causes angular acceleration. + When [member center_of_mass_mode] is set to [constant CENTER_OF_MASS_MODE_AUTO] (default value), the center of mass is automatically computed. + </member> + <member name="center_of_mass_mode" type="int" setter="set_center_of_mass_mode" getter="get_center_of_mass_mode" enum="RigidBody3D.CenterOfMassMode" default="0"> + Defines the way the body's center of mass is set. See [enum CenterOfMassMode] for possible values. + </member> <member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false"> If [code]true[/code], the RigidBody3D will emit signals when it collides with another RigidBody3D. See also [member contacts_reported]. </member> @@ -119,6 +126,10 @@ <member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0"> This is multiplied by the global 3D gravity setting found in [b]Project > Project Settings > Physics > 3d[/b] to produce RigidBody3D's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object. </member> + <member name="inertia" type="Vector3" setter="set_inertia" getter="get_inertia" default="Vector3(0, 0, 0)"> + The body's moment of inertia. This is like mass, but for rotation: it determines how much torque it takes to rotate the body on each axis. The moment of inertia is usually computed automatically from the mass and the shapes, but this property allows you to set a custom value. + If set to [code]Vector3.ZERO[/code], inertia is automatically computed (default value). + </member> <member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="-1.0"> The body's linear damp. Cannot be less than -1.0. If this value is different from -1.0, any linear damp derived from the world or areas will be overridden. See [member ProjectSettings.physics/3d/default_linear_damp] for more details about damping. @@ -130,7 +141,8 @@ The body's mass. </member> <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="RigidBody3D.Mode" default="0"> - The body mode. See [enum Mode] for possible values. + The body's mode. See [enum Mode] for possible values. + For a body that uses only Static or Kinematic mode, use [StaticBody3D] or [AnimatableBody3D] instead. </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. @@ -201,7 +213,13 @@ Locked dynamic body mode. Similar to [constant MODE_DYNAMIC], but the body can not rotate. </constant> <constant name="MODE_KINEMATIC" value="3" enum="Mode"> - Kinematic body mode. The body behaves like a [StaticBody3D] with [member StaticBody3D.kinematic_motion] enabled, and can only move by user code. + Kinematic body mode. The body behaves like a [AnimatableBody3D], and can only move by user code. + </constant> + <constant name="CENTER_OF_MASS_MODE_AUTO" value="0" enum="CenterOfMassMode"> + In this mode, the body's center of mass is calculated automatically based on its shapes. + </constant> + <constant name="CENTER_OF_MASS_MODE_CUSTOM" value="1" enum="CenterOfMassMode"> + In this mode, the body's center of mass is set through [member center_of_mass]. Defaults to the body's origin position. </constant> </constants> </class> diff --git a/doc/classes/StaticBody2D.xml b/doc/classes/StaticBody2D.xml index 326bf58e22..0344c3e0d1 100644 --- a/doc/classes/StaticBody2D.xml +++ b/doc/classes/StaticBody2D.xml @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="StaticBody2D" inherits="PhysicsBody2D" version="4.0"> <brief_description> - Static body for 2D physics. + Physics body for 2D physics which is static or moves only by script. Useful for floor and walls. </brief_description> <description> - Static body for 2D physics. A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody2D], they don't consume any CPU resources as long as they don't move. - They however have extra functionalities to move and affect other bodies: - [b]Constant velocity:[/b] [member constant_linear_velocity] and [member constant_angular_velocity] can be set for the static body, so even if it doesn't move, it affects other bodies as if it was moving (this is useful for simulating conveyor belts or conveyor wheels). - [b]Transform change:[/b] Static bodies can be also moved by code. Unless [member kinematic_motion] is enabled, they are just teleported in this case and don't affect other bodies on their path. - [b]Kinematic motion:[/b] Static bodies can have [member kinematic_motion] enabled to make them kinematic bodies that can be moved by code and push other bodies on their path. + Static body for 2D physics. + A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody2D], it doesn't consume any CPU resources as long as they don't move. + They have extra functionalities to move and affect other bodies: + [b]Static transform change:[/b] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path. + [b]Constant velocity:[/b] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels. </description> <tutorials> </tutorials> @@ -16,22 +16,15 @@ </methods> <members> <member name="constant_angular_velocity" type="float" setter="set_constant_angular_velocity" getter="get_constant_angular_velocity" default="0.0"> - The body's constant angular velocity. This does not rotate the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were rotating. + The body's constant angular velocity. This does not rotate the body, but affects touching bodies, as if it were rotating. </member> <member name="constant_linear_velocity" type="Vector2" setter="set_constant_linear_velocity" getter="get_constant_linear_velocity" default="Vector2(0, 0)"> - The body's constant linear velocity. This does not move the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were moving. - </member> - <member name="kinematic_motion" type="bool" setter="set_kinematic_motion_enabled" getter="is_kinematic_motion_enabled" default="false"> - If [code]true[/code], the body will act the same as a [RigidBody2D] in [constant RigidBody2D.MODE_KINEMATIC] mode. - When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). + The body's constant linear velocity. This does not move the body, but affects touching bodies, as if it were moving. </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. </member> - <member name="sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false"> - If [code]true[/code] and [member kinematic_motion] is enabled, the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method PhysicsBody2D.move_and_collide]. - </member> </members> <constants> </constants> diff --git a/doc/classes/StaticBody3D.xml b/doc/classes/StaticBody3D.xml index 69c123002f..4cb51b60ec 100644 --- a/doc/classes/StaticBody3D.xml +++ b/doc/classes/StaticBody3D.xml @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="StaticBody3D" inherits="PhysicsBody3D" version="4.0"> <brief_description> - Static body for 3D physics. + Physics body for 3D physics which is static or moves only by script. Useful for floor and walls. </brief_description> <description> - Static body for 3D physics. A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody3D], they don't consume any CPU resources as long as they don't move. - They however have extra functionalities to move and affect other bodies: - [b]Constant velocity:[/b] [member constant_linear_velocity] and [member constant_angular_velocity] can be set for the static body, so even if it doesn't move, it affects other bodies as if it was moving (this is useful for simulating conveyor belts or conveyor wheels). - [b]Transform change:[/b] Static bodies can be also moved by code. Unless [member kinematic_motion] is enabled, they are just teleported in this case and don't affect other bodies on their path. - [b]Kinematic motion:[/b] Static bodies can have [member kinematic_motion] enabled to make them kinematic bodies that can be moved by code and push other bodies on their path. + Static body for 3D physics. + A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody3D], it doesn't consume any CPU resources as long as they don't move. + They have extra functionalities to move and affect other bodies: + [b]Static transform change:[/b] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path. + [b]Constant velocity:[/b] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels. </description> <tutorials> <link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link> @@ -19,22 +19,15 @@ </methods> <members> <member name="constant_angular_velocity" type="Vector3" setter="set_constant_angular_velocity" getter="get_constant_angular_velocity" default="Vector3(0, 0, 0)"> - The body's constant angular velocity. This does not rotate the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were rotating. + The body's constant angular velocity. This does not rotate the body, but affects touching bodies, as if it were rotating. </member> <member name="constant_linear_velocity" type="Vector3" setter="set_constant_linear_velocity" getter="get_constant_linear_velocity" default="Vector3(0, 0, 0)"> - The body's constant linear velocity. This does not move the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were moving. - </member> - <member name="kinematic_motion" type="bool" setter="set_kinematic_motion_enabled" getter="is_kinematic_motion_enabled" default="false"> - If [code]true[/code], the body will act the same as a [RigidBody3D] in [constant RigidBody3D.MODE_KINEMATIC] mode. - When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). + The body's constant linear velocity. This does not move the body, but affects touching bodies, as if it were moving. </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one. </member> - <member name="sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false"> - If [code]true[/code] and [member kinematic_motion] is enabled, the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method PhysicsBody3D.move_and_collide]. - </member> </members> <constants> </constants> diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml index fbda005865..77bd7b1a0a 100644 --- a/doc/classes/TabContainer.xml +++ b/doc/classes/TabContainer.xml @@ -57,6 +57,13 @@ Returns the [Texture2D] for the tab at index [code]tab_idx[/code] or [code]null[/code] if the tab has no [Texture2D]. </description> </method> + <method name="get_tab_idx_at_point" qualifiers="const"> + <return type="int" /> + <argument index="0" name="point" type="Vector2" /> + <description> + Returns the index of the tab at local coordinates [code]point[/code]. Returns [code]-1[/code] if the point is outside the control boundaries or if there's no tab at the queried position. + </description> + </method> <method name="get_tab_title" qualifiers="const"> <return type="String" /> <argument index="0" name="tab_idx" type="int" /> diff --git a/doc/classes/XRInterfaceExtension.xml b/doc/classes/XRInterfaceExtension.xml index 46d8d7e4e8..66440d4bb4 100644 --- a/doc/classes/XRInterfaceExtension.xml +++ b/doc/classes/XRInterfaceExtension.xml @@ -11,8 +11,8 @@ <methods> <method name="_commit_views" qualifiers="virtual"> <return type="void" /> - <argument index="0" name="" type="RID" /> - <argument index="1" name="" type="Rect2" /> + <argument index="0" name="render_target" type="RID" /> + <argument index="1" name="screen_rect" type="Rect2" /> <description> </description> </method> @@ -107,15 +107,16 @@ <method name="add_blit"> <return type="void" /> <argument index="0" name="render_target" type="RID" /> - <argument index="1" name="rect" type="Rect2i" /> - <argument index="2" name="use_layer" type="bool" /> - <argument index="3" name="layer" type="int" /> - <argument index="4" name="apply_lens_distortion" type="bool" /> - <argument index="5" name="eye_center" type="Vector2" /> - <argument index="6" name="k1" type="float" /> - <argument index="7" name="k2" type="float" /> - <argument index="8" name="upscale" type="float" /> - <argument index="9" name="aspect_ratio" type="float" /> + <argument index="1" name="src_rect" type="Rect2" /> + <argument index="2" name="dst_rect" type="Rect2i" /> + <argument index="3" name="use_layer" type="bool" /> + <argument index="4" name="layer" type="int" /> + <argument index="5" name="apply_lens_distortion" type="bool" /> + <argument index="6" name="eye_center" type="Vector2" /> + <argument index="7" name="k1" type="float" /> + <argument index="8" name="k2" type="float" /> + <argument index="9" name="upscale" type="float" /> + <argument index="10" name="aspect_ratio" type="float" /> <description> Blits our render results to screen optionally applying lens distortion. This can only be called while processing [code]_commit_views[/code]. </description> diff --git a/editor/icons/AnimatableBody2D.svg b/editor/icons/AnimatableBody2D.svg new file mode 100644 index 0000000000..f4fed813c9 --- /dev/null +++ b/editor/icons/AnimatableBody2D.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#8da5f3" fill-opacity=".99" stroke-width="1.08904"><path d="m10.86822576 4.28299076h1.99947744v1.99947744h-1.99947744z"/><path d="m10.86822576 10.84273776h1.99947744v1.99947744h-1.99947744z"/><path d="m4.71256576 10.84273776h1.99947744v1.99947744h-1.99947744z"/></g><g fill="none" stroke="#8da5f3"><path d="m1.635 8.161v4.848c0 .713.579 1.293 1.292 1.293h9.857c.713 0 1.291-.58 1.291-1.293v-9.854c0-.714-.578-1.293-1.291-1.293h-5.526" stroke-width="1.07" transform="matrix(.939225 0 0 .938055 1.27996 1.07595)"/><path d="m1.339 1.364 2.539 2.539" stroke-width=".74" transform="matrix(2.04823 .655864 .655864 2.04823 -1.51683 -1.5267)"/><path d="m1.436 1.461 1.168 1.168" stroke-width="1.18" transform="matrix(1.69185 0 0 1.69185 4.50755 -.792876)"/><path d="m1.385 1.41 1.219 1.219" stroke-width="1.22" transform="matrix(1.63859 0 0 1.63859 -.688679 4.82985)"/></g></svg> diff --git a/editor/icons/AnimatableBody3D.svg b/editor/icons/AnimatableBody3D.svg new file mode 100644 index 0000000000..2e472f0625 --- /dev/null +++ b/editor/icons/AnimatableBody3D.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="1.5" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f" fill-opacity=".99" stroke-width="1.08904"><path d="m10.86822576 4.28299076h1.99947744v1.99947744h-1.99947744z"/><path d="m10.86822576 10.84273776h1.99947744v1.99947744h-1.99947744z"/><path d="m4.71256576 10.84273776h1.99947744v1.99947744h-1.99947744z"/></g><g fill="none" stroke="#fc7f7f"><path d="m1.635 8.161v4.848c0 .713.579 1.293 1.292 1.293h9.857c.713 0 1.291-.58 1.291-1.293v-9.854c0-.714-.578-1.293-1.291-1.293h-5.526" stroke-width="1.07" transform="matrix(.939225 0 0 .938055 1.27996 1.07595)"/><path d="m1.339 1.364 2.539 2.539" stroke-width=".74" transform="matrix(2.04823 .655864 .655864 2.04823 -1.51683 -1.5267)"/><path d="m1.436 1.461 1.168 1.168" stroke-width="1.18" transform="matrix(1.69185 0 0 1.69185 4.50755 -.792876)"/><path d="m1.385 1.41 1.219 1.219" stroke-width="1.22" transform="matrix(1.63859 0 0 1.63859 -.688679 4.82985)"/></g></svg> diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 2070e0e633..cf8549030d 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -76,13 +76,13 @@ private: public: BulletPhysicsDirectSpaceState(SpaceBullet *p_space); - virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override; - virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; + virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override; + virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; /// Returns the list of contacts pairs in this order: Local contact, other body contact - virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override; }; diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index 12bb0e5b44..bbf1db689d 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -455,16 +455,16 @@ Vector<BlitToScreen> MobileVRInterface::commit_views(RID p_render_target, const blit.lens_distortion.aspect_ratio = aspect; // left eye - blit.rect = p_screen_rect; - blit.rect.size.width *= 0.5; + blit.dst_rect = p_screen_rect; + blit.dst_rect.size.width *= 0.5; blit.multi_view.layer = 0; blit.lens_distortion.eye_center.x = ((-intraocular_dist / 2.0) + (display_width / 4.0)) / (display_width / 2.0); blit_to_screen.push_back(blit); // right eye - blit.rect = p_screen_rect; - blit.rect.size.width *= 0.5; - blit.rect.position.x = blit.rect.size.width; + blit.dst_rect = p_screen_rect; + blit.dst_rect.size.width *= 0.5; + blit.dst_rect.position.x = blit.dst_rect.size.width; blit.multi_view.layer = 1; blit.lens_distortion.eye_center.x = ((intraocular_dist / 2.0) - (display_width / 4.0)) / (display_width / 2.0); blit_to_screen.push_back(blit); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 3518d434c3..30f012c7aa 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -165,21 +165,13 @@ void PhysicsBody2D::remove_collision_exception_with(Node *p_node) { void StaticBody2D::set_constant_linear_velocity(const Vector2 &p_vel) { constant_linear_velocity = p_vel; - if (kinematic_motion) { - _update_kinematic_motion(); - } else { - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); - } + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); } void StaticBody2D::set_constant_angular_velocity(real_t p_vel) { constant_angular_velocity = p_vel; - if (kinematic_motion) { - _update_kinematic_motion(); - } else { - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); - } + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); } Vector2 StaticBody2D::get_constant_linear_velocity() const { @@ -209,62 +201,72 @@ Ref<PhysicsMaterial> StaticBody2D::get_physics_material_override() const { return physics_material_override; } -void StaticBody2D::set_kinematic_motion_enabled(bool p_enabled) { - if (p_enabled == kinematic_motion) { - return; - } - - kinematic_motion = p_enabled; +void StaticBody2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody2D::set_constant_linear_velocity); + ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody2D::set_constant_angular_velocity); + ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody2D::get_constant_linear_velocity); + ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody2D::get_constant_angular_velocity); - if (kinematic_motion) { - set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC); - } else { - set_body_mode(PhysicsServer2D::BODY_MODE_STATIC); - } + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override); -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); - return; - } -#endif + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); +} - _update_kinematic_motion(); +StaticBody2D::StaticBody2D(PhysicsServer2D::BodyMode p_mode) : + PhysicsBody2D(p_mode) { } -bool StaticBody2D::is_kinematic_motion_enabled() const { - return kinematic_motion; +void StaticBody2D::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0); + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1); + } else { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); + } } -void StaticBody2D::set_sync_to_physics(bool p_enable) { +void AnimatableBody2D::set_sync_to_physics(bool p_enable) { if (sync_to_physics == p_enable) { return; } sync_to_physics = p_enable; + _update_kinematic_motion(); +} + +bool AnimatableBody2D::is_sync_to_physics_enabled() const { + return sync_to_physics; +} + +void AnimatableBody2D::_update_kinematic_motion() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); return; } #endif - if (kinematic_motion) { - _update_kinematic_motion(); + if (sync_to_physics) { + PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); + set_only_update_transform_changes(true); + set_notify_local_transform(true); + } else { + PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr); + set_only_update_transform_changes(false); + set_notify_local_transform(false); } } -bool StaticBody2D::is_sync_to_physics_enabled() const { - return sync_to_physics; -} - -void StaticBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) { - StaticBody2D *body = (StaticBody2D *)p_instance; +void AnimatableBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) { + AnimatableBody2D *body = (AnimatableBody2D *)p_instance; body->_body_state_changed(p_state); } -void StaticBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { +void AnimatableBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { if (!sync_to_physics) { return; } @@ -275,17 +277,7 @@ void StaticBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) { set_notify_local_transform(true); } -TypedArray<String> StaticBody2D::get_configuration_warnings() const { - TypedArray<String> warnings = PhysicsBody2D::get_configuration_warnings(); - - if (sync_to_physics && !kinematic_motion) { - warnings.push_back(TTR("Sync to physics works only when kinematic motion is enabled.")); - } - - return warnings; -} - -void StaticBody2D::_notification(int p_what) { +void AnimatableBody2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { last_valid_transform = get_global_transform(); @@ -295,10 +287,6 @@ void StaticBody2D::_notification(int p_what) { // Used by sync to physics, send the new transform to the physics... Transform2D new_transform = get_global_transform(); - double delta_time = get_physics_process_delta_time(); - new_transform.translate(constant_linear_velocity * delta_time); - new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time); - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform); // ... but then revert changes. @@ -306,98 +294,19 @@ void StaticBody2D::_notification(int p_what) { set_global_transform(last_valid_transform); set_notify_local_transform(true); } break; - - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - return; - } -#endif - - ERR_FAIL_COND(!kinematic_motion); - - Transform2D new_transform = get_global_transform(); - - double delta_time = get_physics_process_delta_time(); - new_transform.translate(constant_linear_velocity * delta_time); - new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time); - - if (sync_to_physics) { - // Propagate transform change to node. - set_global_transform(new_transform); - } else { - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform); - - // Propagate transform change to node. - set_block_transform_notify(true); - set_global_transform(new_transform); - set_block_transform_notify(false); - } - } break; } } -void StaticBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody2D::set_constant_linear_velocity); - ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody2D::set_constant_angular_velocity); - ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody2D::get_constant_linear_velocity); - ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody2D::get_constant_angular_velocity); - - ClassDB::bind_method(D_METHOD("set_kinematic_motion_enabled", "enabled"), &StaticBody2D::set_kinematic_motion_enabled); - ClassDB::bind_method(D_METHOD("is_kinematic_motion_enabled"), &StaticBody2D::is_kinematic_motion_enabled); - - ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override); - ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override); - - ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &StaticBody2D::set_sync_to_physics); - ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &StaticBody2D::is_sync_to_physics_enabled); +void AnimatableBody2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &AnimatableBody2D::set_sync_to_physics); + ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &AnimatableBody2D::is_sync_to_physics_enabled); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "kinematic_motion"), "set_kinematic_motion_enabled", "is_kinematic_motion_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled"); } -StaticBody2D::StaticBody2D() : - PhysicsBody2D(PhysicsServer2D::BODY_MODE_STATIC) { -} - -void StaticBody2D::_reload_physics_characteristics() { - if (physics_material_override.is_null()) { - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0); - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1); - } else { - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); - } -} - -void StaticBody2D::_update_kinematic_motion() { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - return; - } -#endif - - if (kinematic_motion && sync_to_physics) { - PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); - set_only_update_transform_changes(true); - set_notify_local_transform(true); - } else { - PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr); - set_only_update_transform_changes(false); - set_notify_local_transform(false); - } - - bool needs_physics_process = false; - if (kinematic_motion) { - if (!Math::is_zero_approx(constant_angular_velocity) || !constant_linear_velocity.is_equal_approx(Vector2())) { - needs_physics_process = true; - } - } - - set_physics_process_internal(needs_physics_process); +AnimatableBody2D::AnimatableBody2D() : + StaticBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) { + _update_kinematic_motion(); } void RigidBody2D::_body_enter_tree(ObjectID p_id) { @@ -651,11 +560,53 @@ real_t RigidBody2D::get_mass() const { void RigidBody2D::set_inertia(real_t p_inertia) { ERR_FAIL_COND(p_inertia < 0); - PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, p_inertia); + inertia = p_inertia; + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia); } real_t RigidBody2D::get_inertia() const { - return PhysicsServer2D::get_singleton()->body_get_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA); + return inertia; +} + +void RigidBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) { + if (center_of_mass_mode == p_mode) { + return; + } + + center_of_mass_mode = p_mode; + + switch (center_of_mass_mode) { + case CENTER_OF_MASS_MODE_AUTO: { + center_of_mass = Vector2(); + PhysicsServer2D::get_singleton()->body_reset_mass_properties(get_rid()); + if (inertia != 0.0) { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia); + } + } break; + + case CENTER_OF_MASS_MODE_CUSTOM: { + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); + } break; + } +} + +RigidBody2D::CenterOfMassMode RigidBody2D::get_center_of_mass_mode() const { + return center_of_mass_mode; +} + +void RigidBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) { + if (center_of_mass == p_center_of_mass) { + return; + } + + ERR_FAIL_COND(center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM); + center_of_mass = p_center_of_mass; + + PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); +} + +const Vector2 &RigidBody2D::get_center_of_mass() const { + return center_of_mass; } void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { @@ -909,6 +860,12 @@ void RigidBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody2D::get_inertia); ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody2D::set_inertia); + ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody2D::set_center_of_mass_mode); + ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody2D::get_center_of_mass_mode); + + ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody2D::set_center_of_mass); + ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody2D::get_center_of_mass); + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody2D::set_physics_material_override); ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody2D::get_physics_material_override); @@ -965,8 +922,11 @@ void RigidBody2D::_bind_methods() { GDVIRTUAL_BIND(_integrate_forces, "state"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp", PROPERTY_USAGE_NONE), "set_inertia", "get_inertia"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater"), "set_center_of_mass", "get_center_of_mass"); + ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); @@ -996,11 +956,22 @@ void RigidBody2D::_bind_methods() { BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED); BIND_ENUM_CONSTANT(MODE_KINEMATIC); + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO); + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM); + BIND_ENUM_CONSTANT(CCD_MODE_DISABLED); BIND_ENUM_CONSTANT(CCD_MODE_CAST_RAY); BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE); } +void RigidBody2D::_validate_property(PropertyInfo &property) const { + if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { + if (property.name == "center_of_mass") { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } +} + RigidBody2D::RigidBody2D() : PhysicsBody2D(PhysicsServer2D::BODY_MODE_DYNAMIC) { PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 1bf53ea53c..1d6437a3ad 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -63,21 +63,13 @@ public: class StaticBody2D : public PhysicsBody2D { GDCLASS(StaticBody2D, PhysicsBody2D); +private: Vector2 constant_linear_velocity; real_t constant_angular_velocity = 0.0; Ref<PhysicsMaterial> physics_material_override; - bool kinematic_motion = false; - bool sync_to_physics = false; - - Transform2D last_valid_transform; - - static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state); - void _body_state_changed(PhysicsDirectBodyState2D *p_state); - protected: - void _notification(int p_what); static void _bind_methods(); public: @@ -90,17 +82,32 @@ public: Vector2 get_constant_linear_velocity() const; real_t get_constant_angular_velocity() const; - virtual TypedArray<String> get_configuration_warnings() const override; - - StaticBody2D(); + StaticBody2D(PhysicsServer2D::BodyMode p_mode = PhysicsServer2D::BODY_MODE_STATIC); private: void _reload_physics_characteristics(); +}; - void _update_kinematic_motion(); +class AnimatableBody2D : public StaticBody2D { + GDCLASS(AnimatableBody2D, StaticBody2D); + +private: + bool sync_to_physics = false; + + Transform2D last_valid_transform; - void set_kinematic_motion_enabled(bool p_enabled); - bool is_kinematic_motion_enabled() const; + static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state); + void _body_state_changed(PhysicsDirectBodyState2D *p_state); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + AnimatableBody2D(); + +private: + void _update_kinematic_motion(); void set_sync_to_physics(bool p_enable); bool is_sync_to_physics_enabled() const; @@ -117,6 +124,11 @@ public: MODE_KINEMATIC, }; + enum CenterOfMassMode { + CENTER_OF_MASS_MODE_AUTO, + CENTER_OF_MASS_MODE_CUSTOM, + }; + enum CCDMode { CCD_MODE_DISABLED, CCD_MODE_CAST_RAY, @@ -128,6 +140,10 @@ private: Mode mode = MODE_DYNAMIC; real_t mass = 1.0; + real_t inertia = 0.0; + CenterOfMassMode center_of_mass_mode = CENTER_OF_MASS_MODE_AUTO; + Vector2 center_of_mass; + Ref<PhysicsMaterial> physics_material_override; real_t gravity_scale = 1.0; real_t linear_damp = -1.0; @@ -191,6 +207,8 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const override; + GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *) public: @@ -203,6 +221,12 @@ public: void set_inertia(real_t p_inertia); real_t get_inertia() const; + void set_center_of_mass_mode(CenterOfMassMode p_mode); + CenterOfMassMode get_center_of_mass_mode() const; + + void set_center_of_mass(const Vector2 &p_center_of_mass); + const Vector2 &get_center_of_mass() const; + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); Ref<PhysicsMaterial> get_physics_material_override() const; @@ -267,6 +291,7 @@ private: }; VARIANT_ENUM_CAST(RigidBody2D::Mode); +VARIANT_ENUM_CAST(RigidBody2D::CenterOfMassMode); VARIANT_ENUM_CAST(RigidBody2D::CCDMode); class CharacterBody2D : public PhysicsBody2D { diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 0356994cdb..00c6664e65 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -223,72 +223,98 @@ Ref<PhysicsMaterial> StaticBody3D::get_physics_material_override() const { return physics_material_override; } -void StaticBody3D::set_kinematic_motion_enabled(bool p_enabled) { - if (p_enabled == kinematic_motion) { - return; - } +void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) { + constant_linear_velocity = p_vel; - kinematic_motion = p_enabled; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); +} - if (kinematic_motion) { - set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); - } else { - set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); - } +void StaticBody3D::set_constant_angular_velocity(const Vector3 &p_vel) { + constant_angular_velocity = p_vel; -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); - return; - } -#endif + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); +} - _update_kinematic_motion(); +Vector3 StaticBody3D::get_constant_linear_velocity() const { + return constant_linear_velocity; } -bool StaticBody3D::is_kinematic_motion_enabled() const { - return kinematic_motion; +Vector3 StaticBody3D::get_constant_angular_velocity() const { + return constant_angular_velocity; } -void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) { - constant_linear_velocity = p_vel; +void StaticBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity); + ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody3D::set_constant_angular_velocity); + ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody3D::get_constant_linear_velocity); + ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody3D::get_constant_angular_velocity); + + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody3D::set_physics_material_override); + ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody3D::get_physics_material_override); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); +} + +StaticBody3D::StaticBody3D(PhysicsServer3D::BodyMode p_mode) : + PhysicsBody3D(p_mode) { +} - if (kinematic_motion) { - _update_kinematic_motion(); +void StaticBody3D::_reload_physics_characteristics() { + if (physics_material_override.is_null()) { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0); + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1); } else { - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); } } -void StaticBody3D::set_sync_to_physics(bool p_enable) { +Vector3 AnimatableBody3D::get_linear_velocity() const { + return linear_velocity; +} + +Vector3 AnimatableBody3D::get_angular_velocity() const { + return angular_velocity; +} + +void AnimatableBody3D::set_sync_to_physics(bool p_enable) { if (sync_to_physics == p_enable) { return; } sync_to_physics = p_enable; + _update_kinematic_motion(); +} + +bool AnimatableBody3D::is_sync_to_physics_enabled() const { + return sync_to_physics; +} + +void AnimatableBody3D::_update_kinematic_motion() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); return; } #endif - if (kinematic_motion) { - _update_kinematic_motion(); + if (sync_to_physics) { + set_only_update_transform_changes(true); + set_notify_local_transform(true); + } else { + set_only_update_transform_changes(false); + set_notify_local_transform(false); } } -bool StaticBody3D::is_sync_to_physics_enabled() const { - return sync_to_physics; -} - -void StaticBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) { - StaticBody3D *body = (StaticBody3D *)p_instance; +void AnimatableBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) { + AnimatableBody3D *body = (AnimatableBody3D *)p_instance; body->_body_state_changed(p_state); } -void StaticBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { +void AnimatableBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { linear_velocity = p_state->get_linear_velocity(); angular_velocity = p_state->get_angular_velocity(); @@ -303,43 +329,7 @@ void StaticBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { _on_transform_changed(); } -TypedArray<String> StaticBody3D::get_configuration_warnings() const { - TypedArray<String> warnings = PhysicsBody3D::get_configuration_warnings(); - - if (sync_to_physics && !kinematic_motion) { - warnings.push_back(TTR("Sync to physics works only when kinematic motion is enabled.")); - } - - return warnings; -} - -void StaticBody3D::set_constant_angular_velocity(const Vector3 &p_vel) { - constant_angular_velocity = p_vel; - - if (kinematic_motion) { - _update_kinematic_motion(); - } else { - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); - } -} - -Vector3 StaticBody3D::get_constant_linear_velocity() const { - return constant_linear_velocity; -} - -Vector3 StaticBody3D::get_constant_angular_velocity() const { - return constant_angular_velocity; -} - -Vector3 StaticBody3D::get_linear_velocity() const { - return linear_velocity; -} - -Vector3 StaticBody3D::get_angular_velocity() const { - return angular_velocity; -} - -void StaticBody3D::_notification(int p_what) { +void AnimatableBody3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { last_valid_transform = get_global_transform(); @@ -349,17 +339,6 @@ void StaticBody3D::_notification(int p_what) { // Used by sync to physics, send the new transform to the physics... Transform3D new_transform = get_global_transform(); - double delta_time = get_physics_process_delta_time(); - new_transform.origin += constant_linear_velocity * delta_time; - - real_t ang_vel = constant_angular_velocity.length(); - if (!Math::is_zero_approx(ang_vel)) { - Vector3 ang_vel_axis = constant_angular_velocity / ang_vel; - Basis rot(ang_vel_axis, ang_vel * delta_time); - new_transform.basis = rot * new_transform.basis; - new_transform.orthonormalize(); - } - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); // ... but then revert changes. @@ -368,108 +347,21 @@ void StaticBody3D::_notification(int p_what) { set_notify_local_transform(true); _on_transform_changed(); } break; - - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - return; - } -#endif - - ERR_FAIL_COND(!kinematic_motion); - - Transform3D new_transform = get_global_transform(); - - double delta_time = get_physics_process_delta_time(); - new_transform.origin += constant_linear_velocity * delta_time; - - real_t ang_vel = constant_angular_velocity.length(); - if (!Math::is_zero_approx(ang_vel)) { - Vector3 ang_vel_axis = constant_angular_velocity / ang_vel; - Basis rot(ang_vel_axis, ang_vel * delta_time); - new_transform.basis = rot * new_transform.basis; - new_transform.orthonormalize(); - } - - if (sync_to_physics) { - // Propagate transform change to node. - set_global_transform(new_transform); - } else { - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); - - // Propagate transform change to node. - set_ignore_transform_notification(true); - set_global_transform(new_transform); - set_ignore_transform_notification(false); - _on_transform_changed(); - } - } break; } } -void StaticBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity); - ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody3D::set_constant_angular_velocity); - ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody3D::get_constant_linear_velocity); - ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody3D::get_constant_angular_velocity); - - ClassDB::bind_method(D_METHOD("set_kinematic_motion_enabled", "enabled"), &StaticBody3D::set_kinematic_motion_enabled); - ClassDB::bind_method(D_METHOD("is_kinematic_motion_enabled"), &StaticBody3D::is_kinematic_motion_enabled); - - ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody3D::set_physics_material_override); - ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody3D::get_physics_material_override); - - ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &StaticBody3D::set_sync_to_physics); - ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &StaticBody3D::is_sync_to_physics_enabled); +void AnimatableBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &AnimatableBody3D::set_sync_to_physics); + ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &AnimatableBody3D::is_sync_to_physics_enabled); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "kinematic_motion"), "set_kinematic_motion_enabled", "is_kinematic_motion_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled"); } -StaticBody3D::StaticBody3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) { -} - -void StaticBody3D::_reload_physics_characteristics() { - if (physics_material_override.is_null()) { - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0); - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1); - } else { - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); - PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); - } -} - -void StaticBody3D::_update_kinematic_motion() { -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - return; - } -#endif +AnimatableBody3D::AnimatableBody3D() : + StaticBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); - if (kinematic_motion && sync_to_physics) { - set_only_update_transform_changes(true); - set_notify_local_transform(true); - } else { - set_only_update_transform_changes(false); - set_notify_local_transform(false); - } - - bool needs_physics_process = false; - if (kinematic_motion) { - PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, &StaticBody3D::_body_state_changed_callback); - - if (!constant_angular_velocity.is_equal_approx(Vector3()) || !constant_linear_velocity.is_equal_approx(Vector3())) { - needs_physics_process = true; - } - } else { - PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr); - } - - set_physics_process_internal(needs_physics_process); + _update_kinematic_motion(); } void RigidBody3D::_body_enter_tree(ObjectID p_id) { @@ -739,6 +631,60 @@ real_t RigidBody3D::get_mass() const { return mass; } +void RigidBody3D::set_inertia(const Vector3 &p_inertia) { + ERR_FAIL_COND(p_inertia.x < 0); + ERR_FAIL_COND(p_inertia.y < 0); + ERR_FAIL_COND(p_inertia.z < 0); + + inertia = p_inertia; + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia); +} + +const Vector3 &RigidBody3D::get_inertia() const { + return inertia; +} + +void RigidBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) { + if (center_of_mass_mode == p_mode) { + return; + } + + center_of_mass_mode = p_mode; + + switch (center_of_mass_mode) { + case CENTER_OF_MASS_MODE_AUTO: { + center_of_mass = Vector3(); + PhysicsServer3D::get_singleton()->body_reset_mass_properties(get_rid()); + if (inertia != Vector3()) { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia); + } + } break; + + case CENTER_OF_MASS_MODE_CUSTOM: { + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); + } break; + } +} + +RigidBody3D::CenterOfMassMode RigidBody3D::get_center_of_mass_mode() const { + return center_of_mass_mode; +} + +void RigidBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) { + if (center_of_mass == p_center_of_mass) { + return; + } + + ERR_FAIL_COND(center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM); + center_of_mass = p_center_of_mass; + + PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass); +} + +const Vector3 &RigidBody3D::get_center_of_mass() const { + return center_of_mass; +} + void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { if (physics_material_override.is_valid()) { if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics))) { @@ -959,6 +905,15 @@ void RigidBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody3D::set_mass); ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass); + ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody3D::set_inertia); + ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody3D::get_inertia); + + ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody3D::set_center_of_mass_mode); + ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody3D::get_center_of_mass_mode); + + ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody3D::set_center_of_mass); + ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody3D::get_center_of_mass); + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody3D::set_physics_material_override); ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody3D::get_physics_material_override); @@ -1012,7 +967,11 @@ void RigidBody3D::_bind_methods() { GDVIRTUAL_BIND(_integrate_forces, "state"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater"), "set_center_of_mass", "get_center_of_mass"); + ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); @@ -1038,11 +997,22 @@ void RigidBody3D::_bind_methods() { BIND_ENUM_CONSTANT(MODE_STATIC); BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED); BIND_ENUM_CONSTANT(MODE_KINEMATIC); + + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO); + BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM); +} + +void RigidBody3D::_validate_property(PropertyInfo &property) const { + if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) { + if (property.name == "center_of_mass") { + property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; + } + } } RigidBody3D::RigidBody3D() : PhysicsBody3D(PhysicsServer3D::BODY_MODE_DYNAMIC) { - PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, &RigidBody3D::_body_state_changed_callback); + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); } RigidBody3D::~RigidBody3D() { @@ -2315,7 +2285,7 @@ void PhysicalBone3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset"), "set_body_offset", "get_body_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale"); @@ -2713,7 +2683,7 @@ void PhysicalBone3D::_start_physics_simulation() { set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); - PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, &PhysicalBone3D::_body_state_changed_callback); + PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback); set_as_top_level(true); _internal_simulate_physics = true; } diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 8c09f77846..8e6463f838 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -73,24 +73,13 @@ public: class StaticBody3D : public PhysicsBody3D { GDCLASS(StaticBody3D, PhysicsBody3D); +private: Vector3 constant_linear_velocity; Vector3 constant_angular_velocity; - Vector3 linear_velocity; - Vector3 angular_velocity; - Ref<PhysicsMaterial> physics_material_override; - bool kinematic_motion = false; - bool sync_to_physics = false; - - Transform3D last_valid_transform; - - static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); - void _body_state_changed(PhysicsDirectBodyState3D *p_state); - protected: - void _notification(int p_what); static void _bind_methods(); public: @@ -103,20 +92,38 @@ public: Vector3 get_constant_linear_velocity() const; Vector3 get_constant_angular_velocity() const; - virtual Vector3 get_linear_velocity() const override; - virtual Vector3 get_angular_velocity() const override; + StaticBody3D(PhysicsServer3D::BodyMode p_mode = PhysicsServer3D::BODY_MODE_STATIC); - virtual TypedArray<String> get_configuration_warnings() const override; +private: + void _reload_physics_characteristics(); +}; - StaticBody3D(); +class AnimatableBody3D : public StaticBody3D { + GDCLASS(AnimatableBody3D, StaticBody3D); private: - void _reload_physics_characteristics(); + Vector3 linear_velocity; + Vector3 angular_velocity; - void _update_kinematic_motion(); + bool sync_to_physics = false; - void set_kinematic_motion_enabled(bool p_enabled); - bool is_kinematic_motion_enabled() const; + Transform3D last_valid_transform; + + static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); + void _body_state_changed(PhysicsDirectBodyState3D *p_state); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + virtual Vector3 get_linear_velocity() const override; + virtual Vector3 get_angular_velocity() const override; + + AnimatableBody3D(); + +private: + void _update_kinematic_motion(); void set_sync_to_physics(bool p_enable); bool is_sync_to_physics_enabled() const; @@ -133,6 +140,11 @@ public: MODE_KINEMATIC, }; + enum CenterOfMassMode { + CENTER_OF_MASS_MODE_AUTO, + CENTER_OF_MASS_MODE_CUSTOM, + }; + GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *) protected: @@ -140,6 +152,10 @@ protected: Mode mode = MODE_DYNAMIC; real_t mass = 1.0; + Vector3 inertia; + CenterOfMassMode center_of_mass_mode = CENTER_OF_MASS_MODE_AUTO; + Vector3 center_of_mass; + Ref<PhysicsMaterial> physics_material_override; Vector3 linear_velocity; @@ -203,6 +219,8 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const override; + public: void set_mode(Mode p_mode); Mode get_mode() const; @@ -212,6 +230,15 @@ public: virtual real_t get_inverse_mass() const override { return 1.0 / mass; } + void set_inertia(const Vector3 &p_inertia); + const Vector3 &get_inertia() const; + + void set_center_of_mass_mode(CenterOfMassMode p_mode); + CenterOfMassMode get_center_of_mass_mode() const; + + void set_center_of_mass(const Vector3 &p_center_of_mass); + const Vector3 &get_center_of_mass() const; + void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); Ref<PhysicsMaterial> get_physics_material_override() const; @@ -272,6 +299,7 @@ private: }; VARIANT_ENUM_CAST(RigidBody3D::Mode); +VARIANT_ENUM_CAST(RigidBody3D::CenterOfMassMode); class KinematicCollision3D; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 845a2ec6c7..137ce7e96f 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -1212,6 +1212,7 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabContainer::get_tab_icon); ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabContainer::set_tab_disabled); ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &TabContainer::get_tab_disabled); + ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabContainer::get_tab_idx_at_point); ClassDB::bind_method(D_METHOD("set_popup", "popup"), &TabContainer::set_popup); ClassDB::bind_method(D_METHOD("get_popup"), &TabContainer::get_popup); ClassDB::bind_method(D_METHOD("set_drag_to_rearrange_enabled", "enabled"), &TabContainer::set_drag_to_rearrange_enabled); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 7e64c13b37..b9e9a4d450 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -557,13 +557,25 @@ void TextEdit::_notification(int p_what) { } int minimap_draw_amount = minimap_visible_lines + get_line_wrap_count(minimap_line + 1); - // draw the minimap - Color viewport_color = (background_color.get_v() < 0.5) ? Color(1, 1, 1, 0.1) : Color(0, 0, 0, 0.1); + // Draw the minimap. + + // Add visual feedback when dragging or hovering the the visible area rectangle. + float viewport_alpha; + if (dragging_minimap) { + viewport_alpha = 0.25; + } else if (hovering_minimap) { + viewport_alpha = 0.175; + } else { + viewport_alpha = 0.1; + } + + const Color viewport_color = (background_color.get_v() < 0.5) ? Color(1, 1, 1, viewport_alpha) : Color(0, 0, 0, viewport_alpha); if (rtl) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - minimap_width, viewport_offset_y, minimap_width, viewport_height), viewport_color); } else { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, minimap_width, viewport_height), viewport_color); } + for (int i = 0; i < minimap_draw_amount; i++) { minimap_line++; @@ -1549,6 +1561,10 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } } + if (draw_minimap && !dragging_selection) { + _update_minimap_hover(); + } + if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) { accept_event(); // Accept event if scroll changed. } @@ -5644,6 +5660,33 @@ void TextEdit::_scroll_lines_down() { } // Minimap + +void TextEdit::_update_minimap_hover() { + const Point2 mp = get_local_mouse_pos(); + const int xmargin_end = get_size().width - style_normal->get_margin(SIDE_RIGHT); + + const bool hovering_sidebar = mp.x > xmargin_end - minimap_width && mp.x < xmargin_end; + if (!hovering_sidebar) { + if (hovering_minimap) { + // Only redraw if the hovering status changed. + hovering_minimap = false; + update(); + } + + // Return early to avoid running the operations below when not needed. + return; + } + + const int row = get_minimap_line_at_pos(Point2i(mp.x, mp.y)); + + const bool new_hovering_minimap = row >= get_first_visible_line() && row <= get_last_full_visible_line(); + if (new_hovering_minimap != hovering_minimap) { + // Only redraw if the hovering status changed. + hovering_minimap = new_hovering_minimap; + update(); + } +} + void TextEdit::_update_minimap_click() { Point2 mp = get_local_mouse_pos(); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index ced03e19d0..07999c2442 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -446,12 +446,14 @@ private: // minimap scroll bool minimap_clicked = false; + bool hovering_minimap = false; bool dragging_minimap = false; bool can_drag_minimap = false; double minimap_scroll_ratio = 0.0; double minimap_scroll_click_pos = 0.0; + void _update_minimap_hover(); void _update_minimap_click(); void _update_minimap_drag(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 0c97fee711..25c8e3e0b7 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -488,6 +488,7 @@ void register_scene_types() { GDREGISTER_VIRTUAL_CLASS(CollisionObject3D); GDREGISTER_VIRTUAL_CLASS(PhysicsBody3D); GDREGISTER_CLASS(StaticBody3D); + GDREGISTER_CLASS(AnimatableBody3D); GDREGISTER_CLASS(RigidBody3D); GDREGISTER_CLASS(KinematicCollision3D); GDREGISTER_CLASS(CharacterBody3D); @@ -647,6 +648,7 @@ void register_scene_types() { GDREGISTER_VIRTUAL_CLASS(CollisionObject2D); GDREGISTER_VIRTUAL_CLASS(PhysicsBody2D); GDREGISTER_CLASS(StaticBody2D); + GDREGISTER_CLASS(AnimatableBody2D); GDREGISTER_CLASS(RigidBody2D); GDREGISTER_CLASS(CharacterBody2D); GDREGISTER_CLASS(KinematicCollision2D); diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index 64f71fd25c..edd769aa9a 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -34,47 +34,72 @@ #include "body_direct_state_2d_sw.h" #include "space_2d_sw.h" -void Body2DSW::_update_inertia() { - if (!user_inertia && get_space() && !inertia_update_list.in_list()) { - get_space()->body_add_to_inertia_update_list(&inertia_update_list); +void Body2DSW::_mass_properties_changed() { + if (get_space() && !mass_properties_update_list.in_list() && (calculate_inertia || calculate_center_of_mass)) { + get_space()->body_add_to_mass_properties_update_list(&mass_properties_update_list); } } -void Body2DSW::update_inertias() { +void Body2DSW::update_mass_properties() { //update shapes and motions switch (mode) { case PhysicsServer2D::BODY_MODE_DYNAMIC: { - if (user_inertia) { - _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0; - break; - } - //update tensor for allshapes, not the best way but should be somehow OK. (inspired from bullet) real_t total_area = 0; - for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } total_area += get_shape_aabb(i).get_area(); } - inertia = 0; + if (calculate_center_of_mass) { + // We have to recompute the center of mass. + center_of_mass = Vector2(); - for (int i = 0; i < get_shape_count(); i++) { - if (is_shape_disabled(i)) { - continue; + if (total_area != 0.0) { + for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } + + real_t area = get_shape_aabb(i).get_area(); + + real_t mass = area * this->mass / total_area; + + // NOTE: we assume that the shape origin is also its center of mass. + center_of_mass += mass * get_shape_transform(i).get_origin(); + } + + center_of_mass /= mass; } + } + + if (calculate_inertia) { + inertia = 0; + + for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } - const Shape2DSW *shape = get_shape(i); + const Shape2DSW *shape = get_shape(i); - real_t area = get_shape_aabb(i).get_area(); + real_t area = get_shape_aabb(i).get_area(); + if (area == 0.0) { + continue; + } - real_t mass = area * this->mass / total_area; + real_t mass = area * this->mass / total_area; - Transform2D mtx = get_shape_transform(i); - Vector2 scale = mtx.get_scale(); - inertia += shape->get_moment_of_inertia(mass, scale) + mass * mtx.get_origin().length_squared(); + Transform2D mtx = get_shape_transform(i); + Vector2 scale = mtx.get_scale(); + Vector2 shape_origin = mtx.get_origin() - center_of_mass; + inertia += shape->get_moment_of_inertia(mass, scale) + mass * shape_origin.length_squared(); + } } - _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0; + _inv_inertia = inertia > 0.0 ? (1.0 / inertia) : 0.0; if (mass) { _inv_mass = 1.0 / mass; @@ -94,9 +119,12 @@ void Body2DSW::update_inertias() { } break; } - //_update_inertia_tensor(); +} - //_update_shapes(); +void Body2DSW::reset_mass_properties() { + calculate_inertia = true; + calculate_center_of_mass = true; + _mass_properties_changed(); } void Body2DSW::set_active(bool p_active) { @@ -118,7 +146,7 @@ void Body2DSW::set_active(bool p_active) { } } -void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) { +void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, const Variant &p_value) { switch (p_param) { case PhysicsServer2D::BODY_PARAM_BOUNCE: { bounce = p_value; @@ -127,21 +155,32 @@ void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) friction = p_value; } break; case PhysicsServer2D::BODY_PARAM_MASS: { - ERR_FAIL_COND(p_value <= 0); - mass = p_value; - _update_inertia(); - + real_t mass_value = p_value; + ERR_FAIL_COND(mass_value <= 0); + mass = mass_value; + if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC) { + _mass_properties_changed(); + } } break; case PhysicsServer2D::BODY_PARAM_INERTIA: { - if (p_value <= 0) { - user_inertia = false; - _update_inertia(); + real_t inertia_value = p_value; + if (inertia_value <= 0.0) { + calculate_inertia = true; + if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) { + _mass_properties_changed(); + } } else { - user_inertia = true; - inertia = p_value; - _inv_inertia = 1.0 / p_value; + calculate_inertia = false; + inertia = inertia_value; + if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) { + _inv_inertia = 1.0 / inertia; + } } } break; + case PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS: { + calculate_center_of_mass = false; + center_of_mass = p_value; + } break; case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: { gravity_scale = p_value; } break; @@ -156,7 +195,7 @@ void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) } } -real_t Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const { +Variant Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const { switch (p_param) { case PhysicsServer2D::BODY_PARAM_BOUNCE: { return bounce; @@ -170,6 +209,9 @@ real_t Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const { case PhysicsServer2D::BODY_PARAM_INERTIA: { return inertia; } + case PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS: { + return center_of_mass; + } case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: { return gravity_scale; } @@ -207,7 +249,10 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) { } break; case PhysicsServer2D::BODY_MODE_DYNAMIC: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; - _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0; + if (!calculate_inertia) { + _inv_inertia = 1.0 / inertia; + } + _mass_properties_changed(); _set_static(false); set_active(true); @@ -215,18 +260,11 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) { case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; _inv_inertia = 0; + angular_velocity = 0; _set_static(false); set_active(true); - angular_velocity = 0; - } break; - } - if (p_mode == PhysicsServer2D::BODY_MODE_DYNAMIC && _inv_inertia == 0) { - _update_inertia(); + } } - /* - if (get_space()) - _update_queries(); - */ } PhysicsServer2D::BodyMode Body2DSW::get_mode() const { @@ -234,7 +272,7 @@ PhysicsServer2D::BodyMode Body2DSW::get_mode() const { } void Body2DSW::_shapes_changed() { - _update_inertia(); + _mass_properties_changed(); wakeup_neighbours(); } @@ -269,11 +307,13 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va } break; case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: { linear_velocity = p_variant; + constant_linear_velocity = linear_velocity; wakeup(); } break; case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: { angular_velocity = p_variant; + constant_angular_velocity = angular_velocity; wakeup(); } break; @@ -296,7 +336,7 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va } break; case PhysicsServer2D::BODY_STATE_CAN_SLEEP: { can_sleep = p_variant; - if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) { + if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) { set_active(true); } @@ -330,8 +370,8 @@ void Body2DSW::set_space(Space2DSW *p_space) { if (get_space()) { wakeup_neighbours(); - if (inertia_update_list.in_list()) { - get_space()->body_remove_from_inertia_update_list(&inertia_update_list); + if (mass_properties_update_list.in_list()) { + get_space()->body_remove_from_mass_properties_update_list(&mass_properties_update_list); } if (active_list.in_list()) { get_space()->body_remove_from_active_list(&active_list); @@ -344,13 +384,11 @@ void Body2DSW::set_space(Space2DSW *p_space) { _set_space(p_space); if (get_space()) { - _update_inertia(); + _mass_properties_changed(); if (active) { get_space()->body_add_to_active_list(&active_list); } } - - first_integration = false; } void Body2DSW::_compute_area_gravity_and_damping(const Area2DSW *p_area) { @@ -429,10 +467,10 @@ void Body2DSW::integrate_forces(real_t p_step) { if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) { //compute motion, angular and etc. velocities from prev transform motion = new_transform.get_origin() - get_transform().get_origin(); - linear_velocity = motion / p_step; + linear_velocity = constant_linear_velocity + motion / p_step; real_t rot = new_transform.get_rotation() - get_transform().get_rotation(); - angular_velocity = remainder(rot, 2.0 * Math_PI) / p_step; + angular_velocity = constant_angular_velocity + remainder(rot, 2.0 * Math_PI) / p_step; do_motion = true; @@ -444,7 +482,7 @@ void Body2DSW::integrate_forces(real_t p_step) { */ } else { - if (!omit_force_integration && !first_integration) { + if (!omit_force_integration) { //overridden by direct state query Vector2 force = gravity * mass; @@ -478,7 +516,6 @@ void Body2DSW::integrate_forces(real_t p_step) { //motion=linear_velocity*p_step; - first_integration = false; biased_angular_velocity = 0; biased_linear_velocity = Vector2(); @@ -515,14 +552,22 @@ void Body2DSW::integrate_velocities(real_t p_step) { real_t angle = get_transform().get_rotation() + total_angular_velocity * p_step; Vector2 pos = get_transform().get_origin() + total_linear_velocity * p_step; + real_t center_of_mass_distance = center_of_mass.length(); + if (center_of_mass_distance > CMP_EPSILON) { + // Calculate displacement due to center of mass offset. + real_t prev_angle = get_transform().get_rotation(); + real_t angle_base = Math::atan2(center_of_mass.y, center_of_mass.x); + Vector2 point1(Math::cos(angle_base + prev_angle), Math::sin(angle_base + prev_angle)); + Vector2 point2(Math::cos(angle_base + angle), Math::sin(angle_base + angle)); + pos += center_of_mass_distance * (point1 - point2); + } + _set_transform(Transform2D(angle, pos), continuous_cd_mode == PhysicsServer2D::CCD_MODE_DISABLED); _set_inv_transform(get_transform().inverse()); if (continuous_cd_mode != PhysicsServer2D::CCD_MODE_DISABLED) { new_transform = get_transform(); } - - //_update_inertia_tensor(); } void Body2DSW::wakeup_neighbours() { @@ -536,7 +581,7 @@ void Body2DSW::wakeup_neighbours() { continue; } Body2DSW *b = n[i]; - if (b->mode != PhysicsServer2D::BODY_MODE_DYNAMIC) { + if (b->mode < PhysicsServer2D::BODY_MODE_DYNAMIC) { continue; } @@ -617,35 +662,9 @@ PhysicsDirectBodyState2DSW *Body2DSW::get_direct_state() { Body2DSW::Body2DSW() : CollisionObject2DSW(TYPE_BODY), active_list(this), - inertia_update_list(this), + mass_properties_update_list(this), direct_state_query_list(this) { - mode = PhysicsServer2D::BODY_MODE_DYNAMIC; - active = true; - angular_velocity = 0; - biased_angular_velocity = 0; - mass = 1; - inertia = 0; - user_inertia = false; - _inv_inertia = 0; - _inv_mass = 1; - bounce = 0; - friction = 1; - omit_force_integration = false; - applied_torque = 0; - island_step = 0; _set_static(false); - first_time_kinematic = false; - linear_damp = -1; - angular_damp = -1; - area_angular_damp = 0; - area_linear_damp = 0; - contact_count = 0; - gravity_scale = 1.0; - first_integration = false; - - still_time = 0; - continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED; - can_sleep = true; } Body2DSW::~Body2DSW() { diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index 9cd53ceca1..95e89786cd 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -41,48 +41,55 @@ class Constraint2DSW; class PhysicsDirectBodyState2DSW; class Body2DSW : public CollisionObject2DSW { - PhysicsServer2D::BodyMode mode; + PhysicsServer2D::BodyMode mode = PhysicsServer2D::BODY_MODE_DYNAMIC; Vector2 biased_linear_velocity; - real_t biased_angular_velocity; + real_t biased_angular_velocity = 0.0; Vector2 linear_velocity; - real_t angular_velocity; + real_t angular_velocity = 0.0; - real_t linear_damp; - real_t angular_damp; - real_t gravity_scale; + Vector2 constant_linear_velocity; + real_t constant_angular_velocity = 0.0; - real_t mass; - real_t inertia; - real_t bounce; - real_t friction; + real_t linear_damp = -1.0; + real_t angular_damp = -1.0; + real_t gravity_scale = 1.0; - real_t _inv_mass; - real_t _inv_inertia; - bool user_inertia; + real_t bounce = 0.0; + real_t friction = 1.0; + + real_t mass = 1.0; + real_t _inv_mass = 1.0; + + real_t inertia = 0.0; + real_t _inv_inertia = 0.0; + + Vector2 center_of_mass; + + bool calculate_inertia = true; + bool calculate_center_of_mass = true; Vector2 gravity; - real_t area_linear_damp; - real_t area_angular_damp; + real_t area_linear_damp = 0.0; + real_t area_angular_damp = 0.0; - real_t still_time; + real_t still_time = 0.0; Vector2 applied_force; - real_t applied_torque; + real_t applied_torque = 0.0; SelfList<Body2DSW> active_list; - SelfList<Body2DSW> inertia_update_list; + SelfList<Body2DSW> mass_properties_update_list; SelfList<Body2DSW> direct_state_query_list; VSet<RID> exceptions; - PhysicsServer2D::CCDMode continuous_cd_mode; - bool omit_force_integration; - bool active; - bool can_sleep; - bool first_time_kinematic; - bool first_integration; - void _update_inertia(); + PhysicsServer2D::CCDMode continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED; + bool omit_force_integration = false; + bool active = true; + bool can_sleep = true; + bool first_time_kinematic = false; + void _mass_properties_changed(); virtual void _shapes_changed(); Transform2D new_transform; @@ -115,7 +122,7 @@ class Body2DSW : public CollisionObject2DSW { }; Vector<Contact> contacts; //no contacts by default - int contact_count; + int contact_count = 0; void *body_state_callback_instance = nullptr; PhysicsServer2D::BodyStateCallback body_state_callback = nullptr; @@ -129,7 +136,7 @@ class Body2DSW : public CollisionObject2DSW { PhysicsDirectBodyState2DSW *direct_state = nullptr; - uint64_t island_step; + uint64_t island_step = 0; _FORCE_INLINE_ void _compute_area_gravity_and_damping(const Area2DSW *p_area); @@ -207,7 +214,7 @@ public: _FORCE_INLINE_ void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) { linear_velocity += p_impulse * _inv_mass; - angular_velocity += _inv_inertia * p_position.cross(p_impulse); + angular_velocity += _inv_inertia * (p_position - center_of_mass).cross(p_impulse); } _FORCE_INLINE_ void apply_torque_impulse(real_t p_torque) { @@ -216,7 +223,7 @@ public: _FORCE_INLINE_ void apply_bias_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) { biased_linear_velocity += p_impulse * _inv_mass; - biased_angular_velocity += _inv_inertia * p_position.cross(p_impulse); + biased_angular_velocity += _inv_inertia * (p_position - center_of_mass).cross(p_impulse); } void set_active(bool p_active); @@ -229,8 +236,8 @@ public: set_active(true); } - void set_param(PhysicsServer2D::BodyParameter p_param, real_t); - real_t get_param(PhysicsServer2D::BodyParameter p_param) const; + void set_param(PhysicsServer2D::BodyParameter p_param, const Variant &p_value); + Variant get_param(PhysicsServer2D::BodyParameter p_param) const; void set_mode(PhysicsServer2D::BodyMode p_mode); PhysicsServer2D::BodyMode get_mode() const; @@ -250,7 +257,7 @@ public: _FORCE_INLINE_ void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) { applied_force += p_force; - applied_torque += p_position.cross(p_force); + applied_torque += (p_position - center_of_mass).cross(p_force); } _FORCE_INLINE_ void add_torque(real_t p_torque) { @@ -262,8 +269,10 @@ public: void set_space(Space2DSW *p_space); - void update_inertias(); + void update_mass_properties(); + void reset_mass_properties(); + _FORCE_INLINE_ Vector2 get_center_of_mass() const { return center_of_mass; } _FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; } _FORCE_INLINE_ real_t get_inv_inertia() const { return _inv_inertia; } _FORCE_INLINE_ real_t get_friction() const { return friction; } diff --git a/servers/physics_2d/body_direct_state_2d_sw.cpp b/servers/physics_2d/body_direct_state_2d_sw.cpp index 1f68cca843..58250c3077 100644 --- a/servers/physics_2d/body_direct_state_2d_sw.cpp +++ b/servers/physics_2d/body_direct_state_2d_sw.cpp @@ -46,6 +46,10 @@ real_t PhysicsDirectBodyState2DSW::get_total_linear_damp() const { return body->area_linear_damp; } +Vector2 PhysicsDirectBodyState2DSW::get_center_of_mass() const { + return body->get_center_of_mass(); +} + real_t PhysicsDirectBodyState2DSW::get_inverse_mass() const { return body->get_inv_mass(); } diff --git a/servers/physics_2d/body_direct_state_2d_sw.h b/servers/physics_2d/body_direct_state_2d_sw.h index aef9186086..34faa174d8 100644 --- a/servers/physics_2d/body_direct_state_2d_sw.h +++ b/servers/physics_2d/body_direct_state_2d_sw.h @@ -45,6 +45,7 @@ public: virtual real_t get_total_angular_damp() const override; virtual real_t get_total_linear_damp() const override; + virtual Vector2 get_center_of_mass() const override; virtual real_t get_inverse_mass() const override; virtual real_t get_inverse_inertia() const override; diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp index 5a0a628fbc..fa8499a81d 100644 --- a/servers/physics_2d/joints_2d_sw.cpp +++ b/servers/physics_2d/joints_2d_sw.cpp @@ -68,13 +68,13 @@ static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const { value += a->get_inv_mass(); - real_t rcn = rA.cross(n); + real_t rcn = (rA - a->get_center_of_mass()).cross(n); value += a->get_inv_inertia() * rcn * rcn; } if (b) { value += b->get_inv_mass(); - real_t rcn = rB.cross(n); + real_t rcn = (rB - b->get_center_of_mass()).cross(n); value += b->get_inv_inertia() * rcn * rcn; } @@ -83,9 +83,9 @@ static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const static inline Vector2 relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB) { - Vector2 sum = a->get_linear_velocity() - rA.orthogonal() * a->get_angular_velocity(); + Vector2 sum = a->get_linear_velocity() - (rA - a->get_center_of_mass()).orthogonal() * a->get_angular_velocity(); if (b) { - return (b->get_linear_velocity() - rB.orthogonal() * b->get_angular_velocity()) - sum; + return (b->get_linear_velocity() - (rB - b->get_center_of_mass()).orthogonal() * b->get_angular_velocity()) - sum; } else { return -sum; } @@ -172,11 +172,11 @@ bool PinJoint2DSW::pre_solve(real_t p_step) { void PinJoint2DSW::solve(real_t p_step) { // compute relative velocity - Vector2 vA = A->get_linear_velocity() - custom_cross(rA, A->get_angular_velocity()); + Vector2 vA = A->get_linear_velocity() - custom_cross(rA - A->get_center_of_mass(), A->get_angular_velocity()); Vector2 rel_vel; if (B) { - rel_vel = B->get_linear_velocity() - custom_cross(rB, B->get_angular_velocity()) - vA; + rel_vel = B->get_linear_velocity() - custom_cross(rB - B->get_center_of_mass(), B->get_angular_velocity()) - vA; } else { rel_vel = -vA; } @@ -238,6 +238,9 @@ k_tensor(Body2DSW *a, Body2DSW *b, Vector2 r1, Vector2 r2, Vector2 *k1, Vector2 k21 = 0.0f; k22 = m_sum; + r1 -= a->get_center_of_mass(); + r2 -= b->get_center_of_mass(); + // add the influence from r1 real_t a_i_inv = a->get_inv_inertia(); real_t r1xsq = r1.x * r1.x * a_i_inv; diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp index 85b5e40752..d0a42ca95b 100644 --- a/servers/physics_2d/physics_server_2d_sw.cpp +++ b/servers/physics_2d/physics_server_2d_sw.cpp @@ -743,20 +743,27 @@ uint32_t PhysicsServer2DSW::body_get_collision_mask(RID p_body) const { return body->get_collision_mask(); }; -void PhysicsServer2DSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) { +void PhysicsServer2DSW::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) { Body2DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); body->set_param(p_param, p_value); }; -real_t PhysicsServer2DSW::body_get_param(RID p_body, BodyParameter p_param) const { +Variant PhysicsServer2DSW::body_get_param(RID p_body, BodyParameter p_param) const { Body2DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, 0); return body->get_param(p_param); }; +void PhysicsServer2DSW::body_reset_mass_properties(RID p_body) { + Body2DSW *body = body_owner.getornull(p_body); + ERR_FAIL_COND(!body); + + return body->reset_mass_properties(); +} + void PhysicsServer2DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { Body2DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h index ef1306cf59..6a2d9e37e0 100644 --- a/servers/physics_2d/physics_server_2d_sw.h +++ b/servers/physics_2d/physics_server_2d_sw.h @@ -205,8 +205,10 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override; virtual uint32_t body_get_collision_mask(RID p_body) const override; - virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override; - virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override; + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override; + virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override; + + virtual void body_reset_mass_properties(RID p_body) override; virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override; virtual Variant body_get_state(RID p_body, BodyState p_state) const override; diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h index 6761e37daa..e65c4f5f3a 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.h +++ b/servers/physics_2d/physics_server_2d_wrap_mt.h @@ -212,8 +212,10 @@ public: FUNC2(body_set_collision_mask, RID, uint32_t); FUNC1RC(uint32_t, body_get_collision_mask, RID); - FUNC3(body_set_param, RID, BodyParameter, real_t); - FUNC2RC(real_t, body_get_param, RID, BodyParameter); + FUNC3(body_set_param, RID, BodyParameter, const Variant &); + FUNC2RC(Variant, body_get_param, RID, BodyParameter); + + FUNC1(body_reset_mass_properties, RID); FUNC3(body_set_state, RID, BodyState, const Variant &); FUNC2RC(Variant, body_get_state, RID, BodyState); diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 6c23f49928..7dbd1243cc 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -482,7 +482,7 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh r_info->metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); if (rcd.best_object->get_type() == CollisionObject2DSW::TYPE_BODY) { const Body2DSW *body = static_cast<const Body2DSW *>(rcd.best_object); - Vector2 rel_vec = r_info->point - body->get_transform().get_origin(); + Vector2 rel_vec = r_info->point - (body->get_transform().get_origin() + body->get_center_of_mass()); r_info->linear_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity(); } else { @@ -961,7 +961,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); const Body2DSW *body = static_cast<const Body2DSW *>(rcd.best_object); - Vector2 rel_vec = r_result->collision_point - body->get_transform().get_origin(); + Vector2 rel_vec = r_result->collision_point - (body->get_transform().get_origin() + body->get_center_of_mass()); r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity(); r_result->travel = safe * p_motion; @@ -1041,12 +1041,12 @@ void Space2DSW::body_remove_from_active_list(SelfList<Body2DSW> *p_body) { active_list.remove(p_body); } -void Space2DSW::body_add_to_inertia_update_list(SelfList<Body2DSW> *p_body) { - inertia_update_list.add(p_body); +void Space2DSW::body_add_to_mass_properties_update_list(SelfList<Body2DSW> *p_body) { + mass_properties_update_list.add(p_body); } -void Space2DSW::body_remove_from_inertia_update_list(SelfList<Body2DSW> *p_body) { - inertia_update_list.remove(p_body); +void Space2DSW::body_remove_from_mass_properties_update_list(SelfList<Body2DSW> *p_body) { + mass_properties_update_list.remove(p_body); } BroadPhase2DSW *Space2DSW::get_broadphase() { @@ -1112,9 +1112,9 @@ void Space2DSW::call_queries() { void Space2DSW::setup() { contact_debug_count = 0; - while (inertia_update_list.first()) { - inertia_update_list.first()->self()->update_inertias(); - inertia_update_list.remove(inertia_update_list.first()); + while (mass_properties_update_list.first()) { + mass_properties_update_list.first()->self()->update_mass_properties(); + mass_properties_update_list.remove(mass_properties_update_list.first()); } } diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 5de071a475..ad82a14af5 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -49,13 +49,13 @@ class PhysicsDirectSpaceState2DSW : public PhysicsDirectSpaceState2D { public: Space2DSW *space; - virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override; - virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override; - virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override; + virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) override; + virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; PhysicsDirectSpaceState2DSW(); }; @@ -86,7 +86,7 @@ private: BroadPhase2DSW *broadphase; SelfList<Body2DSW>::List active_list; - SelfList<Body2DSW>::List inertia_update_list; + SelfList<Body2DSW>::List mass_properties_update_list; SelfList<Body2DSW>::List state_query_list; SelfList<Area2DSW>::List monitor_query_list; SelfList<Area2DSW>::List area_moved_list; @@ -140,8 +140,8 @@ public: const SelfList<Body2DSW>::List &get_active_body_list() const; void body_add_to_active_list(SelfList<Body2DSW> *p_body); void body_remove_from_active_list(SelfList<Body2DSW> *p_body); - void body_add_to_inertia_update_list(SelfList<Body2DSW> *p_body); - void body_remove_from_inertia_update_list(SelfList<Body2DSW> *p_body); + void body_add_to_mass_properties_update_list(SelfList<Body2DSW> *p_body); + void body_remove_from_mass_properties_update_list(SelfList<Body2DSW> *p_body); void area_add_to_moved_list(SelfList<Area2DSW> *p_area); void area_remove_from_moved_list(SelfList<Area2DSW> *p_area); const SelfList<Area2DSW>::List &get_moved_area_list() const; diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp index 7f62e4eb85..41745545d8 100644 --- a/servers/physics_3d/body_3d_sw.cpp +++ b/servers/physics_3d/body_3d_sw.cpp @@ -34,9 +34,9 @@ #include "body_direct_state_3d_sw.h" #include "space_3d_sw.h" -void Body3DSW::_update_inertia() { - if (get_space() && !inertia_update_list.in_list()) { - get_space()->body_add_to_inertia_update_list(&inertia_update_list); +void Body3DSW::_mass_properties_changed() { + if (get_space() && !mass_properties_update_list.in_list() && (calculate_inertia || calculate_center_of_mass)) { + get_space()->body_add_to_mass_properties_update_list(&mass_properties_update_list); } } @@ -44,7 +44,7 @@ void Body3DSW::_update_transform_dependant() { center_of_mass = get_transform().basis.xform(center_of_mass_local); principal_inertia_axes = get_transform().basis * principal_inertia_axes_local; - // update inertia tensor + // Update inertia tensor. Basis tb = principal_inertia_axes; Basis tbt = tb.transposed(); Basis diag; @@ -52,74 +52,95 @@ void Body3DSW::_update_transform_dependant() { _inv_inertia_tensor = tb * diag * tbt; } -void Body3DSW::update_inertias() { +void Body3DSW::update_mass_properties() { // Update shapes and motions. switch (mode) { case PhysicsServer3D::BODY_MODE_DYNAMIC: { - // Update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet) real_t total_area = 0; - for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } + total_area += get_shape_area(i); } - // We have to recompute the center of mass. - center_of_mass_local.zero(); + if (calculate_center_of_mass) { + // We have to recompute the center of mass. + center_of_mass_local.zero(); - if (total_area != 0.0) { - for (int i = 0; i < get_shape_count(); i++) { - real_t area = get_shape_area(i); + if (total_area != 0.0) { + for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } - real_t mass = area * this->mass / total_area; + real_t area = get_shape_area(i); - // NOTE: we assume that the shape origin is also its center of mass. - center_of_mass_local += mass * get_shape_transform(i).origin; - } + real_t mass = area * this->mass / total_area; + + // NOTE: we assume that the shape origin is also its center of mass. + center_of_mass_local += mass * get_shape_transform(i).origin; + } - center_of_mass_local /= mass; + center_of_mass_local /= mass; + } } - // Recompute the inertia tensor. - Basis inertia_tensor; - inertia_tensor.set_zero(); - bool inertia_set = false; + if (calculate_inertia) { + // Recompute the inertia tensor. + Basis inertia_tensor; + inertia_tensor.set_zero(); + bool inertia_set = false; - for (int i = 0; i < get_shape_count(); i++) { - if (is_shape_disabled(i)) { - continue; - } + for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } - real_t area = get_shape_area(i); - if (area == 0.0) { - continue; - } + real_t area = get_shape_area(i); + if (area == 0.0) { + continue; + } - inertia_set = true; + inertia_set = true; - const Shape3DSW *shape = get_shape(i); + const Shape3DSW *shape = get_shape(i); - real_t mass = area * this->mass / total_area; + real_t mass = area * this->mass / total_area; - Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix(); - Transform3D shape_transform = get_shape_transform(i); - Basis shape_basis = shape_transform.basis.orthonormalized(); + Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix(); + Transform3D shape_transform = get_shape_transform(i); + Basis shape_basis = shape_transform.basis.orthonormalized(); - // NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor! - shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed(); + // NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor! + shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed(); - Vector3 shape_origin = shape_transform.origin - center_of_mass_local; - inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass; - } + Vector3 shape_origin = shape_transform.origin - center_of_mass_local; + inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass; + } - // Set the inertia to a valid value when there are no valid shapes. - if (!inertia_set) { - inertia_tensor.set_diagonal(Vector3(1.0, 1.0, 1.0)); - } + // Set the inertia to a valid value when there are no valid shapes. + if (!inertia_set) { + inertia_tensor.set_diagonal(Vector3(1.0, 1.0, 1.0)); + } - // Compute the principal axes of inertia. - principal_inertia_axes_local = inertia_tensor.diagonalize().transposed(); - _inv_inertia = inertia_tensor.get_main_diagonal().inverse(); + // Handle partial custom inertia. + if (inertia.x > 0.0) { + inertia_tensor[0][0] = inertia.x; + } + if (inertia.y > 0.0) { + inertia_tensor[1][1] = inertia.y; + } + if (inertia.z > 0.0) { + inertia_tensor[2][2] = inertia.z; + } + + // Compute the principal axes of inertia. + principal_inertia_axes_local = inertia_tensor.diagonalize().transposed(); + _inv_inertia = inertia_tensor.get_main_diagonal().inverse(); + } if (mass) { _inv_mass = 1.0 / mass; @@ -128,10 +149,9 @@ void Body3DSW::update_inertias() { } } break; - case PhysicsServer3D::BODY_MODE_KINEMATIC: case PhysicsServer3D::BODY_MODE_STATIC: { - _inv_inertia_tensor.set_zero(); + _inv_inertia = Vector3(); _inv_mass = 0; } break; case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: { @@ -141,11 +161,15 @@ void Body3DSW::update_inertias() { } break; } - //_update_shapes(); - _update_transform_dependant(); } +void Body3DSW::reset_mass_properties() { + calculate_inertia = true; + calculate_center_of_mass = true; + _mass_properties_changed(); +} + void Body3DSW::set_active(bool p_active) { if (active == p_active) { return; @@ -165,7 +189,7 @@ void Body3DSW::set_active(bool p_active) { } } -void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) { +void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value) { switch (p_param) { case PhysicsServer3D::BODY_PARAM_BOUNCE: { bounce = p_value; @@ -174,10 +198,33 @@ void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) friction = p_value; } break; case PhysicsServer3D::BODY_PARAM_MASS: { - ERR_FAIL_COND(p_value <= 0); - mass = p_value; - _update_inertia(); - + real_t mass_value = p_value; + ERR_FAIL_COND(mass_value <= 0); + mass = mass_value; + if (mode >= PhysicsServer3D::BODY_MODE_DYNAMIC) { + _mass_properties_changed(); + } + } break; + case PhysicsServer3D::BODY_PARAM_INERTIA: { + inertia = p_value; + if ((inertia.x <= 0.0) || (inertia.y <= 0.0) || (inertia.z <= 0.0)) { + calculate_inertia = true; + if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) { + _mass_properties_changed(); + } + } else { + calculate_inertia = false; + if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) { + principal_inertia_axes_local.set_diagonal(Vector3(1.0, 1.0, 1.0)); + _inv_inertia = inertia.inverse(); + _update_transform_dependant(); + } + } + } break; + case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: { + calculate_center_of_mass = false; + center_of_mass_local = p_value; + _update_transform_dependant(); } break; case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: { gravity_scale = p_value; @@ -193,7 +240,7 @@ void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) } } -real_t Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const { +Variant Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const { switch (p_param) { case PhysicsServer3D::BODY_PARAM_BOUNCE: { return bounce; @@ -204,6 +251,16 @@ real_t Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const { case PhysicsServer3D::BODY_PARAM_MASS: { return mass; } break; + case PhysicsServer3D::BODY_PARAM_INERTIA: { + if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) { + return _inv_inertia.inverse(); + } else { + return Vector3(); + } + } break; + case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: { + return center_of_mass; + } break; case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: { return gravity_scale; } break; @@ -226,40 +283,42 @@ void Body3DSW::set_mode(PhysicsServer3D::BodyMode p_mode) { mode = p_mode; switch (p_mode) { - //CLEAR UP EVERYTHING IN CASE IT NOT WORKS! case PhysicsServer3D::BODY_MODE_STATIC: case PhysicsServer3D::BODY_MODE_KINEMATIC: { _set_inv_transform(get_transform().affine_inverse()); _inv_mass = 0; + _inv_inertia = Vector3(); _set_static(p_mode == PhysicsServer3D::BODY_MODE_STATIC); - //set_active(p_mode==PhysicsServer3D::BODY_MODE_KINEMATIC); set_active(p_mode == PhysicsServer3D::BODY_MODE_KINEMATIC && contacts.size()); linear_velocity = Vector3(); angular_velocity = Vector3(); if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC && prev != mode) { first_time_kinematic = true; } + _update_transform_dependant(); } break; case PhysicsServer3D::BODY_MODE_DYNAMIC: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; + if (!calculate_inertia) { + principal_inertia_axes_local.set_diagonal(Vector3(1.0, 1.0, 1.0)); + _inv_inertia = inertia.inverse(); + _update_transform_dependant(); + } + _mass_properties_changed(); _set_static(false); set_active(true); } break; case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; + _inv_inertia = Vector3(); + angular_velocity = Vector3(); + _update_transform_dependant(); _set_static(false); set_active(true); - angular_velocity = Vector3(); - } break; + } } - - _update_inertia(); - /* - if (get_space()) - _update_queries(); - */ } PhysicsServer3D::BodyMode Body3DSW::get_mode() const { @@ -267,7 +326,7 @@ PhysicsServer3D::BodyMode Body3DSW::get_mode() const { } void Body3DSW::_shapes_changed() { - _update_inertia(); + _mass_properties_changed(); } void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) { @@ -302,10 +361,12 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va } break; case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: { linear_velocity = p_variant; + constant_linear_velocity = linear_velocity; wakeup(); } break; case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: { angular_velocity = p_variant; + constant_angular_velocity = angular_velocity; wakeup(); } break; @@ -326,7 +387,7 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va } break; case PhysicsServer3D::BODY_STATE_CAN_SLEEP: { can_sleep = p_variant; - if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC && !active && !can_sleep) { + if (mode >= PhysicsServer3D::BODY_MODE_DYNAMIC && !active && !can_sleep) { set_active(true); } @@ -358,8 +419,8 @@ Variant Body3DSW::get_state(PhysicsServer3D::BodyState p_state) const { void Body3DSW::set_space(Space3DSW *p_space) { if (get_space()) { - if (inertia_update_list.in_list()) { - get_space()->body_remove_from_inertia_update_list(&inertia_update_list); + if (mass_properties_update_list.in_list()) { + get_space()->body_remove_from_mass_properties_update_list(&mass_properties_update_list); } if (active_list.in_list()) { get_space()->body_remove_from_active_list(&active_list); @@ -372,13 +433,11 @@ void Body3DSW::set_space(Space3DSW *p_space) { _set_space(p_space); if (get_space()) { - _update_inertia(); + _mass_properties_changed(); if (active) { get_space()->body_add_to_active_list(&active_list); } } - - first_integration = true; } void Body3DSW::_compute_area_gravity_and_damping(const Area3DSW *p_area) { @@ -473,7 +532,7 @@ void Body3DSW::integrate_forces(real_t p_step) { //compute motion, angular and etc. velocities from prev transform motion = new_transform.origin - get_transform().origin; do_motion = true; - linear_velocity = motion / p_step; + linear_velocity = constant_linear_velocity + motion / p_step; //compute a FAKE angular velocity, not so easy Basis rot = new_transform.basis.orthonormalized() * get_transform().basis.orthonormalized().transposed(); @@ -482,9 +541,9 @@ void Body3DSW::integrate_forces(real_t p_step) { rot.get_axis_angle(axis, angle); axis.normalize(); - angular_velocity = axis * (angle / p_step); + angular_velocity = constant_angular_velocity + axis * (angle / p_step); } else { - if (!omit_force_integration && !first_integration) { + if (!omit_force_integration) { //overridden by direct state query Vector3 force = gravity * mass; @@ -518,7 +577,6 @@ void Body3DSW::integrate_forces(real_t p_step) { applied_force = Vector3(); applied_torque = Vector3(); - first_integration = false; //motion=linear_velocity*p_step; @@ -640,7 +698,7 @@ void Body3DSW::wakeup_neighbours() { continue; } Body3DSW *b = n[i]; - if (b->mode != PhysicsServer3D::BODY_MODE_DYNAMIC) { + if (b->mode < PhysicsServer3D::BODY_MODE_DYNAMIC) { continue; } @@ -717,32 +775,9 @@ PhysicsDirectBodyState3DSW *Body3DSW::get_direct_state() { Body3DSW::Body3DSW() : CollisionObject3DSW(TYPE_BODY), active_list(this), - inertia_update_list(this), + mass_properties_update_list(this), direct_state_query_list(this) { - mode = PhysicsServer3D::BODY_MODE_DYNAMIC; - active = true; - - mass = 1; - _inv_mass = 1; - bounce = 0; - friction = 1; - omit_force_integration = false; - //applied_torque=0; - island_step = 0; - first_time_kinematic = false; - first_integration = false; _set_static(false); - - contact_count = 0; - gravity_scale = 1.0; - linear_damp = -1; - angular_damp = -1; - area_angular_damp = 0; - area_linear_damp = 0; - - still_time = 0; - continuous_cd = false; - can_sleep = true; } Body3DSW::~Body3DSW() { diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index f58f40652b..8b74c7e5b9 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/body_3d_sw.h @@ -39,24 +39,28 @@ class Constraint3DSW; class PhysicsDirectBodyState3DSW; class Body3DSW : public CollisionObject3DSW { - PhysicsServer3D::BodyMode mode; + PhysicsServer3D::BodyMode mode = PhysicsServer3D::BODY_MODE_DYNAMIC; Vector3 linear_velocity; Vector3 angular_velocity; + Vector3 constant_linear_velocity; + Vector3 constant_angular_velocity; + Vector3 biased_linear_velocity; Vector3 biased_angular_velocity; - real_t mass; - real_t bounce; - real_t friction; + real_t mass = 1.0; + real_t bounce = 0.0; + real_t friction = 1.0; + Vector3 inertia; - real_t linear_damp; - real_t angular_damp; - real_t gravity_scale; + real_t linear_damp = -1.0; + real_t angular_damp = -1.0; + real_t gravity_scale = 1.0; uint16_t locked_axis = 0; - real_t _inv_mass; + real_t _inv_mass = 1.0; Vector3 _inv_inertia; // Relative to the principal axes of inertia // Relative to the local frame of reference @@ -68,30 +72,32 @@ class Body3DSW : public CollisionObject3DSW { Basis principal_inertia_axes; Vector3 center_of_mass; + bool calculate_inertia = true; + bool calculate_center_of_mass = true; + Vector3 gravity; - real_t still_time; + real_t still_time = 0.0; Vector3 applied_force; Vector3 applied_torque; - real_t area_angular_damp; - real_t area_linear_damp; + real_t area_angular_damp = 0.0; + real_t area_linear_damp = 0.0; SelfList<Body3DSW> active_list; - SelfList<Body3DSW> inertia_update_list; + SelfList<Body3DSW> mass_properties_update_list; SelfList<Body3DSW> direct_state_query_list; VSet<RID> exceptions; - bool omit_force_integration; - bool active; + bool omit_force_integration = false; + bool active = true; - bool first_integration; + bool continuous_cd = false; + bool can_sleep = true; + bool first_time_kinematic = false; - bool continuous_cd; - bool can_sleep; - bool first_time_kinematic; - void _update_inertia(); + void _mass_properties_changed(); virtual void _shapes_changed(); Transform3D new_transform; @@ -112,7 +118,7 @@ class Body3DSW : public CollisionObject3DSW { }; Vector<Contact> contacts; //no contacts by default - int contact_count; + int contact_count = 0; void *body_state_callback_instance = nullptr; PhysicsServer3D::BodyStateCallback body_state_callback = nullptr; @@ -126,7 +132,7 @@ class Body3DSW : public CollisionObject3DSW { PhysicsDirectBodyState3DSW *direct_state = nullptr; - uint64_t island_step; + uint64_t island_step = 0; _FORCE_INLINE_ void _compute_area_gravity_and_damping(const Area3DSW *p_area); @@ -251,8 +257,8 @@ public: set_active(true); } - void set_param(PhysicsServer3D::BodyParameter p_param, real_t); - real_t get_param(PhysicsServer3D::BodyParameter p_param) const; + void set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value); + Variant get_param(PhysicsServer3D::BodyParameter p_param) const; void set_mode(PhysicsServer3D::BodyMode p_mode); PhysicsServer3D::BodyMode get_mode() const; @@ -271,7 +277,8 @@ public: void set_space(Space3DSW *p_space); - void update_inertias(); + void update_mass_properties(); + void reset_mass_properties(); _FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; } _FORCE_INLINE_ const Vector3 &get_inv_inertia() const { return _inv_inertia; } diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp index a214e80c6c..8de54c5c48 100644 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ b/servers/physics_3d/physics_server_3d_sw.cpp @@ -643,20 +643,27 @@ uint32_t PhysicsServer3DSW::body_get_user_flags(RID p_body) const { return 0; }; -void PhysicsServer3DSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) { +void PhysicsServer3DSW::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); body->set_param(p_param, p_value); }; -real_t PhysicsServer3DSW::body_get_param(RID p_body, BodyParameter p_param) const { +Variant PhysicsServer3DSW::body_get_param(RID p_body, BodyParameter p_param) const { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, 0); return body->get_param(p_param); }; +void PhysicsServer3DSW::body_reset_mass_properties(RID p_body) { + Body3DSW *body = body_owner.getornull(p_body); + ERR_FAIL_COND(!body); + + return body->reset_mass_properties(); +} + void PhysicsServer3DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h index f283f83112..071ad0a694 100644 --- a/servers/physics_3d/physics_server_3d_sw.h +++ b/servers/physics_3d/physics_server_3d_sw.h @@ -198,8 +198,10 @@ public: virtual void body_set_user_flags(RID p_body, uint32_t p_flags) override; virtual uint32_t body_get_user_flags(RID p_body) const override; - virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override; - virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override; + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override; + virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override; + + virtual void body_reset_mass_properties(RID p_body) override; virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override; virtual Variant body_get_state(RID p_body, BodyState p_state) const override; diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h index 8865bd4bd2..58986969d4 100644 --- a/servers/physics_3d/physics_server_3d_wrap_mt.h +++ b/servers/physics_3d/physics_server_3d_wrap_mt.h @@ -210,8 +210,10 @@ public: FUNC2(body_set_user_flags, RID, uint32_t); FUNC1RC(uint32_t, body_get_user_flags, RID); - FUNC3(body_set_param, RID, BodyParameter, real_t); - FUNC2RC(real_t, body_get_param, RID, BodyParameter); + FUNC3(body_set_param, RID, BodyParameter, const Variant &); + FUNC2RC(Variant, body_get_param, RID, BodyParameter); + + FUNC1(body_reset_mass_properties, RID); FUNC3(body_set_state, RID, BodyState, const Variant &); FUNC2RC(Variant, body_get_state, RID, BodyState); diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp index b81d3272c3..945d0120be 100644 --- a/servers/physics_3d/shape_3d_sw.cpp +++ b/servers/physics_3d/shape_3d_sw.cpp @@ -1676,6 +1676,17 @@ struct _HeightmapSegmentCullParams { FaceShape3DSW *face = nullptr; }; +struct _HeightmapGridCullState { + real_t length = 0.0; + real_t length_flat = 0.0; + + real_t dist = 0.0; + real_t prev_dist = 0.0; + + int x = 0; + int z = 0; +}; + _FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) { Vector3 res; Vector3 normal; @@ -1688,11 +1699,11 @@ _FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_ return false; } -_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, int p_x, int p_z) { +_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, const _HeightmapGridCullState &p_state) { // First triangle. - p_params.heightmap->_get_point(p_x, p_z, p_params.face->vertex[0]); - p_params.heightmap->_get_point(p_x + 1, p_z, p_params.face->vertex[1]); - p_params.heightmap->_get_point(p_x, p_z + 1, p_params.face->vertex[2]); + p_params.heightmap->_get_point(p_state.x, p_state.z, p_params.face->vertex[0]); + p_params.heightmap->_get_point(p_state.x + 1, p_state.z, p_params.face->vertex[1]); + p_params.heightmap->_get_point(p_state.x, p_state.z + 1, p_params.face->vertex[2]); p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal; if (_heightmap_face_cull_segment(p_params)) { return true; @@ -1700,7 +1711,7 @@ _FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_ // Second triangle. p_params.face->vertex[0] = p_params.face->vertex[1]; - p_params.heightmap->_get_point(p_x + 1, p_z + 1, p_params.face->vertex[1]); + p_params.heightmap->_get_point(p_state.x + 1, p_state.z + 1, p_params.face->vertex[1]); p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal; if (_heightmap_face_cull_segment(p_params)) { return true; @@ -1709,13 +1720,51 @@ _FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_ return false; } -bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const { - if (heights.is_empty()) { +_FORCE_INLINE_ bool _heightmap_chunk_cull_segment(_HeightmapSegmentCullParams &p_params, const _HeightmapGridCullState &p_state) { + const HeightMapShape3DSW::Range &chunk = p_params.heightmap->_get_bounds_chunk(p_state.x, p_state.z); + + Vector3 enter_pos; + Vector3 exit_pos; + + if (p_state.length_flat > CMP_EPSILON) { + real_t flat_to_3d = p_state.length / p_state.length_flat; + real_t enter_param = p_state.prev_dist * flat_to_3d; + real_t exit_param = p_state.dist * flat_to_3d; + enter_pos = p_params.from + p_params.dir * enter_param; + exit_pos = p_params.from + p_params.dir * exit_param; + } else { + // Consider the ray vertical. + // (though we shouldn't reach this often because there is an early check up-front) + enter_pos = p_params.from; + exit_pos = p_params.to; + } + + // Transform positions to heightmap space. + enter_pos *= HeightMapShape3DSW::BOUNDS_CHUNK_SIZE; + exit_pos *= HeightMapShape3DSW::BOUNDS_CHUNK_SIZE; + + // We did enter the flat projection of the AABB, + // but we have to check if we intersect it on the vertical axis. + if ((enter_pos.y > chunk.max) && (exit_pos.y > chunk.max)) { + return false; + } + if ((enter_pos.y < chunk.min) && (exit_pos.y < chunk.min)) { return false; } - Vector3 local_begin = p_begin + local_origin; - Vector3 local_end = p_end + local_origin; + return p_params.heightmap->_intersect_grid_segment(_heightmap_cell_cull_segment, enter_pos, exit_pos, p_params.heightmap->width, p_params.heightmap->depth, p_params.heightmap->local_origin, p_params.result, p_params.normal); +} + +template <typename ProcessFunction> +bool HeightMapShape3DSW::_intersect_grid_segment(ProcessFunction &p_process, const Vector3 &p_begin, const Vector3 &p_end, int p_width, int p_depth, const Vector3 &offset, Vector3 &r_point, Vector3 &r_normal) const { + Vector3 delta = (p_end - p_begin); + real_t length = delta.length(); + + if (length < CMP_EPSILON) { + return false; + } + + Vector3 local_begin = p_begin + offset; FaceShape3DSW face; face.backface_collision = false; @@ -1723,136 +1772,181 @@ bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 _HeightmapSegmentCullParams params; params.from = p_begin; params.to = p_end; - params.dir = (p_end - p_begin).normalized(); + params.dir = delta / length; params.heightmap = this; params.face = &face; - // Quantize the ray begin/end. - int begin_x = floor(local_begin.x); - int begin_z = floor(local_begin.z); - int end_x = floor(local_end.x); - int end_z = floor(local_end.z); + _HeightmapGridCullState state; - if ((begin_x == end_x) && (begin_z == end_z)) { - // Simple case for rays that don't traverse the grid horizontally. - // Just perform a test on the given cell. - int x = CLAMP(begin_x, 0, width - 2); - int z = CLAMP(begin_z, 0, depth - 2); - if (_heightmap_cell_cull_segment(params, x, z)) { - r_point = params.result; - r_normal = params.normal; - return true; - } - } else { - // Perform grid query from projected ray. - Vector2 ray_dir_proj(local_end.x - local_begin.x, local_end.z - local_begin.z); - real_t ray_dist_proj = ray_dir_proj.length(); + // Perform grid query from projected ray. + Vector2 ray_dir_flat(delta.x, delta.z); + state.length = length; + state.length_flat = ray_dir_flat.length(); - if (ray_dist_proj < CMP_EPSILON) { - ray_dir_proj = Vector2(); - } else { - ray_dir_proj /= ray_dist_proj; - } + if (state.length_flat < CMP_EPSILON) { + ray_dir_flat = Vector2(); + } else { + ray_dir_flat /= state.length_flat; + } - const int x_step = (ray_dir_proj.x > CMP_EPSILON) ? 1 : ((ray_dir_proj.x < -CMP_EPSILON) ? -1 : 0); - const int z_step = (ray_dir_proj.y > CMP_EPSILON) ? 1 : ((ray_dir_proj.y < -CMP_EPSILON) ? -1 : 0); + const int x_step = (ray_dir_flat.x > CMP_EPSILON) ? 1 : ((ray_dir_flat.x < -CMP_EPSILON) ? -1 : 0); + const int z_step = (ray_dir_flat.y > CMP_EPSILON) ? 1 : ((ray_dir_flat.y < -CMP_EPSILON) ? -1 : 0); - const real_t infinite = 1e20; - const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_proj.x) : infinite; - const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_proj.y) : infinite; + const real_t infinite = 1e20; + const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_flat.x) : infinite; + const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_flat.y) : infinite; - real_t cross_x; // At which value of `param` we will cross a x-axis lane? - real_t cross_z; // At which value of `param` we will cross a z-axis lane? + real_t cross_x; // At which value of `param` we will cross a x-axis lane? + real_t cross_z; // At which value of `param` we will cross a z-axis lane? - // X initialization. - if (x_step != 0) { - if (x_step == 1) { - cross_x = (ceil(local_begin.x) - local_begin.x) * delta_x; - } else { - cross_x = (local_begin.x - floor(local_begin.x)) * delta_x; - } + // X initialization. + if (x_step != 0) { + if (x_step == 1) { + cross_x = (Math::ceil(local_begin.x) - local_begin.x) * delta_x; } else { - cross_x = infinite; // Will never cross on X. + cross_x = (local_begin.x - Math::floor(local_begin.x)) * delta_x; } + } else { + cross_x = infinite; // Will never cross on X. + } - // Z initialization. - if (z_step != 0) { - if (z_step == 1) { - cross_z = (ceil(local_begin.z) - local_begin.z) * delta_z; - } else { - cross_z = (local_begin.z - floor(local_begin.z)) * delta_z; - } + // Z initialization. + if (z_step != 0) { + if (z_step == 1) { + cross_z = (Math::ceil(local_begin.z) - local_begin.z) * delta_z; } else { - cross_z = infinite; // Will never cross on Z. + cross_z = (local_begin.z - Math::floor(local_begin.z)) * delta_z; } + } else { + cross_z = infinite; // Will never cross on Z. + } - int x = floor(local_begin.x); - int z = floor(local_begin.z); + int x = Math::floor(local_begin.x); + int z = Math::floor(local_begin.z); - // Workaround cases where the ray starts at an integer position. - if (Math::is_zero_approx(cross_x)) { - cross_x += delta_x; - // If going backwards, we should ignore the position we would get by the above flooring, - // because the ray is not heading in that direction. - if (x_step == -1) { - x -= 1; - } + // Workaround cases where the ray starts at an integer position. + if (Math::is_zero_approx(cross_x)) { + cross_x += delta_x; + // If going backwards, we should ignore the position we would get by the above flooring, + // because the ray is not heading in that direction. + if (x_step == -1) { + x -= 1; } + } - if (Math::is_zero_approx(cross_z)) { - cross_z += delta_z; - if (z_step == -1) { - z -= 1; - } + if (Math::is_zero_approx(cross_z)) { + cross_z += delta_z; + if (z_step == -1) { + z -= 1; } + } + + // Start inside the grid. + int x_start = MAX(MIN(x, p_width - 2), 0); + int z_start = MAX(MIN(z, p_depth - 2), 0); - // Start inside the grid. - int x_start = CLAMP(x, 0, width - 2); - int z_start = CLAMP(z, 0, depth - 2); + // Adjust initial cross values. + cross_x += delta_x * x_step * (x_start - x); + cross_z += delta_z * z_step * (z_start - z); - // Adjust initial cross values. - cross_x += delta_x * x_step * (x_start - x); - cross_z += delta_z * z_step * (z_start - z); + x = x_start; + z = z_start; - x = x_start; - z = z_start; + while (true) { + state.prev_dist = state.dist; + state.x = x; + state.z = z; - if (_heightmap_cell_cull_segment(params, x, z)) { + if (cross_x < cross_z) { + // X lane. + x += x_step; + // Assign before advancing the param, + // to be in sync with the initialization step. + state.dist = cross_x; + cross_x += delta_x; + } else { + // Z lane. + z += z_step; + state.dist = cross_z; + cross_z += delta_z; + } + + if (state.dist > state.length_flat) { + state.dist = state.length_flat; + if (p_process(params, state)) { + r_point = params.result; + r_normal = params.normal; + return true; + } + break; + } + + if (p_process(params, state)) { r_point = params.result; r_normal = params.normal; return true; } - real_t dist = 0.0; - while (true) { - if (cross_x < cross_z) { - // X lane. - x += x_step; - // Assign before advancing the param, - // to be in sync with the initialization step. - dist = cross_x; - cross_x += delta_x; - } else { - // Z lane. - z += z_step; - dist = cross_z; - cross_z += delta_z; - } + // Stop when outside the grid. + if ((x < 0) || (z < 0) || (x >= p_width - 1) || (z >= p_depth - 1)) { + break; + } + } - // Stop when outside the grid. - if ((x < 0) || (z < 0) || (x >= width - 1) || (z >= depth - 1)) { - break; - } + return false; +} - if (_heightmap_cell_cull_segment(params, x, z)) { - r_point = params.result; - r_normal = params.normal; - return true; - } +bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const { + if (heights.is_empty()) { + return false; + } - if (dist > ray_dist_proj) { - break; - } + Vector3 local_begin = p_begin + local_origin; + Vector3 local_end = p_end + local_origin; + + // Quantize the ray begin/end. + int begin_x = Math::floor(local_begin.x); + int begin_z = Math::floor(local_begin.z); + int end_x = Math::floor(local_end.x); + int end_z = Math::floor(local_end.z); + + if ((begin_x == end_x) && (begin_z == end_z)) { + // Simple case for rays that don't traverse the grid horizontally. + // Just perform a test on the given cell. + FaceShape3DSW face; + face.backface_collision = false; + + _HeightmapSegmentCullParams params; + params.from = p_begin; + params.to = p_end; + params.dir = (p_end - p_begin).normalized(); + + params.heightmap = this; + params.face = &face; + + _HeightmapGridCullState state; + state.x = MAX(MIN(begin_x, width - 2), 0); + state.z = MAX(MIN(begin_z, depth - 2), 0); + if (_heightmap_cell_cull_segment(params, state)) { + r_point = params.result; + r_normal = params.normal; + return true; + } + } else if (bounds_grid.is_empty()) { + // Process all cells intersecting the flat projection of the ray. + return _intersect_grid_segment(_heightmap_cell_cull_segment, p_begin, p_end, width, depth, local_origin, r_point, r_normal); + } else { + Vector3 ray_diff = (p_end - p_begin); + real_t length_flat_sqr = ray_diff.x * ray_diff.x + ray_diff.z * ray_diff.z; + if (length_flat_sqr < BOUNDS_CHUNK_SIZE * BOUNDS_CHUNK_SIZE) { + // Don't use chunks, the ray is too short in the plane. + return _intersect_grid_segment(_heightmap_cell_cull_segment, p_begin, p_end, width, depth, local_origin, r_point, r_normal); + } else { + // The ray is long, run raycast on a higher-level grid. + Vector3 bounds_from = p_begin / BOUNDS_CHUNK_SIZE; + Vector3 bounds_to = p_end / BOUNDS_CHUNK_SIZE; + Vector3 bounds_offset = local_origin / BOUNDS_CHUNK_SIZE; + return _intersect_grid_segment(_heightmap_chunk_cull_segment, bounds_from, bounds_to, bounds_grid_width, bounds_grid_depth, bounds_offset, r_point, r_normal); } } @@ -1917,7 +2011,7 @@ void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback _get_point(x, z, face.vertex[0]); _get_point(x + 1, z, face.vertex[1]); _get_point(x, z + 1, face.vertex[2]); - face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal; + face.normal = Plane(face.vertex[0], face.vertex[1], face.vertex[2]).normal; if (p_callback(p_userdata, &face)) { return; } @@ -1925,7 +2019,7 @@ void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback // Second triangle. face.vertex[0] = face.vertex[1]; _get_point(x + 1, z + 1, face.vertex[1]); - face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal; + face.normal = Plane(face.vertex[0], face.vertex[1], face.vertex[2]).normal; if (p_callback(p_userdata, &face)) { return; } @@ -1943,6 +2037,75 @@ Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const { (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y)); } +void HeightMapShape3DSW::_build_accelerator() { + bounds_grid.clear(); + + bounds_grid_width = width / BOUNDS_CHUNK_SIZE; + bounds_grid_depth = depth / BOUNDS_CHUNK_SIZE; + + if (width % BOUNDS_CHUNK_SIZE > 0) { + ++bounds_grid_width; // In case terrain size isn't dividable by chunk size. + } + + if (depth % BOUNDS_CHUNK_SIZE > 0) { + ++bounds_grid_depth; + } + + uint32_t bound_grid_size = (uint32_t)(bounds_grid_width * bounds_grid_depth); + + if (bound_grid_size < 2) { + // Grid is empty or just one chunk. + return; + } + + bounds_grid.resize(bound_grid_size); + + // Compute min and max height for all chunks. + for (int cz = 0; cz < bounds_grid_depth; ++cz) { + int z0 = cz * BOUNDS_CHUNK_SIZE; + + for (int cx = 0; cx < bounds_grid_width; ++cx) { + int x0 = cx * BOUNDS_CHUNK_SIZE; + + Range r; + + r.min = _get_height(x0, z0); + r.max = r.min; + + // Compute min and max height for this chunk. + // We have to include one extra cell to account for neighbors. + // Here is why: + // Say we have a flat terrain, and a plateau that fits a chunk perfectly. + // + // Left Right + // 0---0---0---1---1---1 + // | | | | | | + // 0---0---0---1---1---1 + // | | | | | | + // 0---0---0---1---1---1 + // x + // + // If the AABB for the Left chunk did not share vertices with the Right, + // then we would fail collision tests at x due to a gap. + // + int z_max = MIN(z0 + BOUNDS_CHUNK_SIZE + 1, depth); + int x_max = MIN(x0 + BOUNDS_CHUNK_SIZE + 1, width); + for (int z = z0; z < z_max; ++z) { + for (int x = x0; x < x_max; ++x) { + real_t height = _get_height(x, z); + if (height < r.min) { + r.min = height; + } else if (height > r.max) { + r.max = height; + } + } + } + + bounds_grid[cx + cz * bounds_grid_width] = r; + } + } +} + void HeightMapShape3DSW::_setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { heights = p_heights; width = p_width; @@ -1959,6 +2122,8 @@ void HeightMapShape3DSW::_setup(const Vector<real_t> &p_heights, int p_width, in aabb.position -= local_origin; + _build_accelerator(); + configure(aabb); } @@ -2017,7 +2182,7 @@ void HeightMapShape3DSW::set_data(const Variant &p_data) { } else { int heights_size = heights.size(); for (int i = 0; i < heights_size; ++i) { - float h = heights[i]; + real_t h = heights[i]; if (h < min_height) { min_height = h; } else if (h > max_height) { diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h index b05f65f268..73eddc469c 100644 --- a/servers/physics_3d/shape_3d_sw.h +++ b/servers/physics_3d/shape_3d_sw.h @@ -32,6 +32,7 @@ #define SHAPE_SW_H #include "core/math/geometry_3d.h" +#include "core/templates/local_vector.h" #include "servers/physics_server_3d.h" class Shape3DSW; @@ -385,6 +386,21 @@ struct HeightMapShape3DSW : public ConcaveShape3DSW { int depth = 0; Vector3 local_origin; + // Accelerator. + struct Range { + real_t min = 0.0; + real_t max = 0.0; + }; + LocalVector<Range> bounds_grid; + int bounds_grid_width = 0; + int bounds_grid_depth = 0; + + static const int BOUNDS_CHUNK_SIZE = 16; + + _FORCE_INLINE_ const Range &_get_bounds_chunk(int p_x, int p_z) const { + return bounds_grid[(p_z * bounds_grid_width) + p_x]; + } + _FORCE_INLINE_ real_t _get_height(int p_x, int p_z) const { return heights[(p_z * width) + p_x]; } @@ -397,6 +413,11 @@ struct HeightMapShape3DSW : public ConcaveShape3DSW { void _get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const; + void _build_accelerator(); + + template <typename ProcessFunction> + bool _intersect_grid_segment(ProcessFunction &p_process, const Vector3 &p_begin, const Vector3 &p_end, int p_width, int p_depth, const Vector3 &offset, Vector3 &r_point, Vector3 &r_normal) const; + void _setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); public: diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index 37dee436df..3b08184e00 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -977,12 +977,12 @@ void Space3DSW::body_remove_from_active_list(SelfList<Body3DSW> *p_body) { active_list.remove(p_body); } -void Space3DSW::body_add_to_inertia_update_list(SelfList<Body3DSW> *p_body) { - inertia_update_list.add(p_body); +void Space3DSW::body_add_to_mass_properties_update_list(SelfList<Body3DSW> *p_body) { + mass_properties_update_list.add(p_body); } -void Space3DSW::body_remove_from_inertia_update_list(SelfList<Body3DSW> *p_body) { - inertia_update_list.remove(p_body); +void Space3DSW::body_remove_from_mass_properties_update_list(SelfList<Body3DSW> *p_body) { + mass_properties_update_list.remove(p_body); } BroadPhase3DSW *Space3DSW::get_broadphase() { @@ -1059,9 +1059,9 @@ void Space3DSW::call_queries() { void Space3DSW::setup() { contact_debug_count = 0; - while (inertia_update_list.first()) { - inertia_update_list.first()->self()->update_inertias(); - inertia_update_list.remove(inertia_update_list.first()); + while (mass_properties_update_list.first()) { + mass_properties_update_list.first()->self()->update_mass_properties(); + mass_properties_update_list.remove(mass_properties_update_list.first()); } } diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h index eff494a7bc..98c335cb80 100644 --- a/servers/physics_3d/space_3d_sw.h +++ b/servers/physics_3d/space_3d_sw.h @@ -48,12 +48,12 @@ class PhysicsDirectSpaceState3DSW : public PhysicsDirectSpaceState3D { public: Space3DSW *space; - virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override; - virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; - virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override; + virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; + virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override; PhysicsDirectSpaceState3DSW(); @@ -79,7 +79,7 @@ private: BroadPhase3DSW *broadphase; SelfList<Body3DSW>::List active_list; - SelfList<Body3DSW>::List inertia_update_list; + SelfList<Body3DSW>::List mass_properties_update_list; SelfList<Body3DSW>::List state_query_list; SelfList<Area3DSW>::List monitor_query_list; SelfList<Area3DSW>::List area_moved_list; @@ -137,8 +137,8 @@ public: const SelfList<Body3DSW>::List &get_active_body_list() const; void body_add_to_active_list(SelfList<Body3DSW> *p_body); void body_remove_from_active_list(SelfList<Body3DSW> *p_body); - void body_add_to_inertia_update_list(SelfList<Body3DSW> *p_body); - void body_remove_from_inertia_update_list(SelfList<Body3DSW> *p_body); + void body_add_to_mass_properties_update_list(SelfList<Body3DSW> *p_body); + void body_remove_from_mass_properties_update_list(SelfList<Body3DSW> *p_body); void body_add_to_state_query_list(SelfList<Body3DSW> *p_body); void body_remove_from_state_query_list(SelfList<Body3DSW> *p_body); diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 4660b83f4d..2656ef1d6d 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -77,6 +77,7 @@ void PhysicsDirectBodyState2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_total_linear_damp"), &PhysicsDirectBodyState2D::get_total_linear_damp); ClassDB::bind_method(D_METHOD("get_total_angular_damp"), &PhysicsDirectBodyState2D::get_total_angular_damp); + ClassDB::bind_method(D_METHOD("get_center_of_mass"), &PhysicsDirectBodyState2D::get_center_of_mass); ClassDB::bind_method(D_METHOD("get_inverse_mass"), &PhysicsDirectBodyState2D::get_inverse_mass); ClassDB::bind_method(D_METHOD("get_inverse_inertia"), &PhysicsDirectBodyState2D::get_inverse_inertia); @@ -123,6 +124,7 @@ void PhysicsDirectBodyState2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_angular_damp"), "", "get_total_angular_damp"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_linear_damp"), "", "get_total_linear_damp"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "total_gravity"), "", "get_total_gravity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass"), "", "get_center_of_mass"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping"); @@ -257,13 +259,6 @@ void PhysicsShapeQueryParameters2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); } -PhysicsShapeQueryParameters2D::PhysicsShapeQueryParameters2D() { - margin = 0; - collision_mask = 0x7FFFFFFF; - collide_with_bodies = true; - collide_with_areas = false; -} - Dictionary PhysicsDirectSpaceState2D::_intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) { RayResult inters; Set<RID> exclude; @@ -411,9 +406,9 @@ PhysicsDirectSpaceState2D::PhysicsDirectSpaceState2D() { } void PhysicsDirectSpaceState2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point, DEFVAL(32), DEFVAL(Array()), DEFVAL(UINT32_MAX), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("intersect_point_on_canvas", "point", "canvas_instance_id", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_point_on_canvas, DEFVAL(32), DEFVAL(Array()), DEFVAL(UINT32_MAX), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_ray, DEFVAL(Array()), DEFVAL(UINT32_MAX), DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_intersect_shape, DEFVAL(32)); ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &PhysicsDirectSpaceState2D::_cast_motion); ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_collide_shape, DEFVAL(32)); @@ -614,6 +609,8 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer2D::body_set_param); ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer2D::body_get_param); + ClassDB::bind_method(D_METHOD("body_reset_mass_properties", "body"), &PhysicsServer2D::body_reset_mass_properties); + ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer2D::body_set_state); ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer2D::body_get_state); @@ -709,6 +706,7 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION); BIND_ENUM_CONSTANT(BODY_PARAM_MASS); BIND_ENUM_CONSTANT(BODY_PARAM_INERTIA); + BIND_ENUM_CONSTANT(BODY_PARAM_CENTER_OF_MASS); BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE); BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP); BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 021d7be7c0..1145bb8b91 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -48,6 +48,7 @@ public: virtual real_t get_total_linear_damp() const = 0; // get density of this body space/area virtual real_t get_total_angular_damp() const = 0; // get density of this body space/area + virtual Vector2 get_center_of_mass() const = 0; virtual real_t get_inverse_mass() const = 0; // get the mass virtual real_t get_inverse_inertia() const = 0; // get density of this body space @@ -103,12 +104,12 @@ class PhysicsShapeQueryParameters2D : public RefCounted { RID shape; Transform2D transform; Vector2 motion; - real_t margin; + real_t margin = 0.0; Set<RID> exclude; - uint32_t collision_mask; + uint32_t collision_mask = UINT32_MAX; - bool collide_with_bodies; - bool collide_with_areas; + bool collide_with_bodies = true; + bool collide_with_areas = false; protected: static void _bind_methods(); @@ -139,8 +140,6 @@ public: void set_exclude(const Vector<RID> &p_exclude); Vector<RID> get_exclude() const; - - PhysicsShapeQueryParameters2D(); }; class PhysicsDirectSpaceState2D : public Object { @@ -169,7 +168,7 @@ public: Variant metadata; }; - virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool intersect_ray(const Vector2 &p_from, const Vector2 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; struct ShapeResult { RID rid; @@ -179,14 +178,14 @@ public: Variant metadata; }; - virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0; - virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0; + virtual int intersect_point(const Vector2 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0; + virtual int intersect_point_on_canvas(const Vector2 &p_point, ObjectID p_canvas_instance_id, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_point = false) = 0; - virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual int intersect_shape(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; - virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool cast_motion(const RID &p_shape, const Transform2D &p_xform, const Vector2 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; - virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; struct ShapeRestInfo { Vector2 point; @@ -198,7 +197,7 @@ public: Variant metadata; }; - virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool rest_info(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_layer = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; PhysicsDirectSpaceState2D(); }; @@ -404,15 +403,18 @@ public: BODY_PARAM_BOUNCE, BODY_PARAM_FRICTION, BODY_PARAM_MASS, ///< unused for static, always infinite - BODY_PARAM_INERTIA, // read-only: computed from mass & shapes + BODY_PARAM_INERTIA, + BODY_PARAM_CENTER_OF_MASS, BODY_PARAM_GRAVITY_SCALE, BODY_PARAM_LINEAR_DAMP, BODY_PARAM_ANGULAR_DAMP, BODY_PARAM_MAX, }; - virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0; - virtual real_t body_get_param(RID p_body, BodyParameter p_param) const = 0; + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) = 0; + virtual Variant body_get_param(RID p_body, BodyParameter p_param) const = 0; + + virtual void body_reset_mass_properties(RID p_body) = 0; //state enum BodyState { diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 6cde4977f4..0c487b83ea 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -249,13 +249,6 @@ void PhysicsShapeQueryParameters3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); } -PhysicsShapeQueryParameters3D::PhysicsShapeQueryParameters3D() { - margin = 0; - collision_mask = 0x7FFFFFFF; - collide_with_bodies = true; - collide_with_areas = false; -} - ///////////////////////////////////// Dictionary PhysicsDirectSpaceState3D::_intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { @@ -360,7 +353,7 @@ PhysicsDirectSpaceState3D::PhysicsDirectSpaceState3D() { } void PhysicsDirectSpaceState3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState3D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState3D::_intersect_ray, DEFVAL(Array()), DEFVAL(UINT32_MAX), DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState3D::_intersect_shape, DEFVAL(32)); ClassDB::bind_method(D_METHOD("cast_motion", "shape", "motion"), &PhysicsDirectSpaceState3D::_cast_motion); ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState3D::_collide_shape, DEFVAL(32)); @@ -584,6 +577,8 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer3D::body_set_param); ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer3D::body_get_param); + ClassDB::bind_method(D_METHOD("body_reset_mass_properties", "body"), &PhysicsServer3D::body_reset_mass_properties); + ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer3D::body_set_state); ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer3D::body_get_state); @@ -789,6 +784,8 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE); BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION); BIND_ENUM_CONSTANT(BODY_PARAM_MASS); + BIND_ENUM_CONSTANT(BODY_PARAM_INERTIA); + BIND_ENUM_CONSTANT(BODY_PARAM_CENTER_OF_MASS); BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE); BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP); BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index a365802220..5677604682 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -103,12 +103,12 @@ class PhysicsShapeQueryParameters3D : public RefCounted { RES shape_ref; RID shape; Transform3D transform; - real_t margin; + real_t margin = 0.0; Set<RID> exclude; - uint32_t collision_mask; + uint32_t collision_mask = UINT32_MAX; - bool collide_with_bodies; - bool collide_with_areas; + bool collide_with_bodies = true; + bool collide_with_areas = false; protected: static void _bind_methods(); @@ -136,15 +136,13 @@ public: void set_collide_with_areas(bool p_enable); bool is_collide_with_areas_enabled() const; - - PhysicsShapeQueryParameters3D(); }; class PhysicsDirectSpaceState3D : public Object { GDCLASS(PhysicsDirectSpaceState3D, Object); private: - Dictionary _intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_collision_mask = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); + Dictionary _intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); Array _intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32); Array _cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, const Vector3 &p_motion); Array _collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32); @@ -161,7 +159,7 @@ public: int shape = 0; }; - virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; struct RayResult { Vector3 position; @@ -172,9 +170,9 @@ public: int shape = 0; }; - virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) = 0; + virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) = 0; - virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; struct ShapeRestInfo { Vector3 point; @@ -185,11 +183,11 @@ public: Vector3 linear_velocity; //velocity at contact point }; - virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) = 0; + virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) = 0; - virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; - virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = UINT32_MAX, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const = 0; @@ -407,14 +405,18 @@ public: BODY_PARAM_BOUNCE, BODY_PARAM_FRICTION, BODY_PARAM_MASS, ///< unused for static, always infinite + BODY_PARAM_INERTIA, + BODY_PARAM_CENTER_OF_MASS, BODY_PARAM_GRAVITY_SCALE, BODY_PARAM_LINEAR_DAMP, BODY_PARAM_ANGULAR_DAMP, BODY_PARAM_MAX, }; - virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0; - virtual real_t body_get_param(RID p_body, BodyParameter p_param) const = 0; + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) = 0; + virtual Variant body_get_param(RID p_body, BodyParameter p_param) const = 0; + + virtual void body_reset_mass_properties(RID p_body) = 0; //state enum BodyState { diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index 6206849b66..1971c3e781 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -41,7 +41,8 @@ class RendererSceneRender; struct BlitToScreen { RID render_target; - Rect2i rect; + Rect2 src_rect = Rect2(0.0, 0.0, 1.0, 1.0); + Rect2i dst_rect; struct { bool use_layer = false; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 62e9386f95..c53c202bab 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -46,6 +46,8 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID RID rd_texture = storage->texture_get_rd_texture(texture); ERR_CONTINUE(rd_texture.is_null()); + // TODO if keep_3d_linear was set when rendering to this render target we need to add a linear->sRGB conversion in. + if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) { Vector<RD::Uniform> uniforms; RD::Uniform u; @@ -65,10 +67,14 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0); - blit.push_constant.rect[0] = p_render_targets[i].rect.position.x / screen_size.width; - blit.push_constant.rect[1] = p_render_targets[i].rect.position.y / screen_size.height; - blit.push_constant.rect[2] = p_render_targets[i].rect.size.width / screen_size.width; - blit.push_constant.rect[3] = p_render_targets[i].rect.size.height / screen_size.height; + blit.push_constant.src_rect[0] = p_render_targets[i].src_rect.position.x; + blit.push_constant.src_rect[1] = p_render_targets[i].src_rect.position.y; + blit.push_constant.src_rect[2] = p_render_targets[i].src_rect.size.width; + blit.push_constant.src_rect[3] = p_render_targets[i].src_rect.size.height; + blit.push_constant.dst_rect[0] = p_render_targets[i].dst_rect.position.x / screen_size.width; + blit.push_constant.dst_rect[1] = p_render_targets[i].dst_rect.position.y / screen_size.height; + blit.push_constant.dst_rect[2] = p_render_targets[i].dst_rect.size.width / screen_size.width; + blit.push_constant.dst_rect[3] = p_render_targets[i].dst_rect.size.height / screen_size.height; blit.push_constant.layer = p_render_targets[i].multi_view.layer; blit.push_constant.eye_center[0] = p_render_targets[i].lens_distortion.eye_center.x; blit.push_constant.eye_center[1] = p_render_targets[i].lens_distortion.eye_center.y; @@ -203,10 +209,14 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uset, 0); - blit.push_constant.rect[0] = screenrect.position.x; - blit.push_constant.rect[1] = screenrect.position.y; - blit.push_constant.rect[2] = screenrect.size.width; - blit.push_constant.rect[3] = screenrect.size.height; + blit.push_constant.src_rect[0] = 0.0; + blit.push_constant.src_rect[1] = 0.0; + blit.push_constant.src_rect[2] = 1.0; + blit.push_constant.src_rect[3] = 1.0; + blit.push_constant.dst_rect[0] = screenrect.position.x; + blit.push_constant.dst_rect[1] = screenrect.position.y; + blit.push_constant.dst_rect[2] = screenrect.size.width; + blit.push_constant.dst_rect[3] = screenrect.size.height; blit.push_constant.layer = 0; blit.push_constant.eye_center[0] = 0; blit.push_constant.eye_center[1] = 0; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 8639362da9..0230c46800 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -55,7 +55,8 @@ protected: }; struct BlitPushConstant { - float rect[4]; + float src_rect[4]; + float dst_rect[4]; float eye_center[2]; float k1; diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl index 967da1e6e4..8051f96738 100644 --- a/servers/rendering/renderer_rd/shaders/blit.glsl +++ b/servers/rendering/renderer_rd/shaders/blit.glsl @@ -5,6 +5,7 @@ #VERSION_DEFINES layout(push_constant, binding = 0, std140) uniform Pos { + vec4 src_rect; vec4 dst_rect; vec2 eye_center; @@ -22,8 +23,8 @@ layout(location = 0) out vec2 uv; void main() { vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); - uv = base_arr[gl_VertexIndex]; - vec2 vtx = data.dst_rect.xy + uv * data.dst_rect.zw; + uv = data.src_rect.xy + base_arr[gl_VertexIndex] * data.src_rect.zw; + vec2 vtx = data.dst_rect.xy + base_arr[gl_VertexIndex] * data.dst_rect.zw; gl_Position = vec4(vtx * 2.0 - 1.0, 0.0, 1.0); } @@ -34,6 +35,7 @@ void main() { #VERSION_DEFINES layout(push_constant, binding = 0, std140) uniform Pos { + vec4 src_rect; vec4 dst_rect; vec2 eye_center; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 3ede9fed2d..8af2049ab3 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -626,10 +626,10 @@ void RendererViewport::draw_viewports() { BlitToScreen blit; blit.render_target = vp->render_target; if (vp->viewport_to_screen_rect != Rect2()) { - blit.rect = vp->viewport_to_screen_rect; + blit.dst_rect = vp->viewport_to_screen_rect; } else { - blit.rect.position = Vector2(); - blit.rect.size = vp->size; + blit.dst_rect.position = Vector2(); + blit.dst_rect.size = vp->size; } if (!blit_to_screen_list.has(vp->viewport_to_screen)) { diff --git a/servers/xr/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp index e1519d1463..5c90139375 100644 --- a/servers/xr/xr_interface_extension.cpp +++ b/servers/xr/xr_interface_extension.cpp @@ -41,7 +41,7 @@ void XRInterfaceExtension::_bind_methods() { GDVIRTUAL_BIND(_get_tracking_status); - ClassDB::bind_method(D_METHOD("add_blit", "render_target", "rect", "use_layer", "layer", "apply_lens_distortion", "eye_center", "k1", "k2", "upscale", "aspect_ratio"), &XRInterfaceExtension::add_blit); + ClassDB::bind_method(D_METHOD("add_blit", "render_target", "src_rect", "dst_rect", "use_layer", "layer", "apply_lens_distortion", "eye_center", "k1", "k2", "upscale", "aspect_ratio"), &XRInterfaceExtension::add_blit); GDVIRTUAL_BIND(_get_render_target_size); GDVIRTUAL_BIND(_get_view_count); @@ -49,7 +49,7 @@ void XRInterfaceExtension::_bind_methods() { GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform"); GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far"); - GDVIRTUAL_BIND(_commit_views); + GDVIRTUAL_BIND(_commit_views, "render_target", "screen_rect"); GDVIRTUAL_BIND(_process); GDVIRTUAL_BIND(_notification, "what"); @@ -198,13 +198,14 @@ CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, real return CameraMatrix(); } -void XRInterfaceExtension::add_blit(RID p_render_target, Rect2i p_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, float p_k1, float p_k2, float p_upscale, float p_aspect_ratio) { +void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, float p_k1, float p_k2, float p_upscale, float p_aspect_ratio) { BlitToScreen blit; ERR_FAIL_COND_MSG(!can_add_blits, "add_blit can only be called from an XR plugin from within _commit_views!"); blit.render_target = p_render_target; - blit.rect = p_rect; + blit.src_rect = p_src_rect; + blit.dst_rect = p_dst_rect; blit.multi_view.use_layer = p_use_layer; blit.multi_view.layer = p_layer; diff --git a/servers/xr/xr_interface_extension.h b/servers/xr/xr_interface_extension.h index ab4d90bfe6..df6f5f8e35 100644 --- a/servers/xr/xr_interface_extension.h +++ b/servers/xr/xr_interface_extension.h @@ -91,7 +91,7 @@ public: GDVIRTUAL2R(Transform3D, _get_transform_for_view, uint32_t, const Transform3D &); GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, real_t, real_t, real_t); - void add_blit(RID p_render_target, Rect2i p_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), float p_k1 = 0.0, float p_k2 = 0.0, float p_upscale = 1.0, float p_aspect_ratio = 1.0); + void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), float p_k1 = 0.0, float p_k2 = 0.0, float p_upscale = 1.0, float p_aspect_ratio = 1.0); virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; GDVIRTUAL2(_commit_views, RID, const Rect2 &); |