Add Tapered collision shapes - #116707
Add Tapered collision shapes #116707Moddingear wants to merge 10 commits into
Conversation
|
Here is a video demo: Screencast.From.2026-02-24.14-24-54.mp4The UVs on the top of the tapered cylinder aren't quite correct yet |
|
godotengine/godot-proposals#610 is implemented by this PR Just to clarify : I haven't yet checked the physics in game, there may be a mismatch between what's seen and what's collided with |
|
sorry about the wrong styles, I hadn't setup everything to have it run automatically, this is my first contrib... |
|
For completeness: this also addresses the original proposal, godotengine/godot-proposals#12875 |
23ddd21 to
08c6748
Compare
|
Physics have been made and tested to work with both Godot physics server (using regular non-tapered variants) and Jolt tapered_physics.mp4 |
|
I'll note here that a lot of the code between the tapered Cylinder and tapered Capsule is very similar, maybe it could be merged into a single parent class? Also, I haven't made icons for the meshes or the shapes. I tried to have a go at it, but in the end it was programmer art... Finally, maybe there could be a button to convert non-tapered cylinder/capsules into their tapered variants and vice-versa? |
|
@Moddingear Please run |
aaronfranke
left a comment
There was a problem hiding this comment.
Looks pretty good from my perspective. Needs these property info changes, and a rebase+squash, and approval from physics folks.
02e46a7 to
0ab802f
Compare
|
I did the squash+rebase, but I kept the original commit from #109009 to keep their contribution |
0ab802f to
d28e417
Compare
|
Last change is so that the tapered capsule, both mesh and collision, correctly handle being turned into spheres. There was a superfluous test to avoid that, but Jolt actually handles the case just fine... |
You could add a Then add those tapered specific properties that can not be shared / reused from the normal version as extra properties to the Resource. E.g. in case of cylinders add Assuming we have such a tapered bool to detect, you can update the Mesh::create_mesh_array() code of the related mesh primitives and branch internal so that it creates the old version or the new tapered version depending on what is used. That way you dont need to bother updating each parser tool individual as they will just get whatever version is set. To sum up.
|
|
I've had to rework the way gizmo handles work so that the gizmos can allow switching between tapered and non-tapered. Screencast.From.2026-07-31.14-11-44.mp4Non-tapered shapes support being represented by tapered shapes, and vice-versa (though, when a tapered shape is represented by a non-tapered shape, the collision doesn't match ofc). |
|
It now uses non-tapered shapes when top_radius and bottom_radius are the same. There is an accessor for radius, which sets both top_radius and bottom_radius to the same value, and when read, gives the average of both. Tapered shapes have 6 longitudinal lines, as opposed to non-tapered shapes which have 4, so they can easily be told apart. I haven't tested migrating cylinder shapes from 4.7 to this version. |
Some sort of compile error. Click to expand logs. ./scene/resources/3d/primitive_meshes.cpp:426:6: error: no declaration matches 'void CapsuleMesh::create_mesh_array(Array&, float, float, int, int, bool, float)'
426 | void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const float height, const int radial_segments, const int rings, bool p_add_uv2, const float p_uv2_padding) {
| ^~~~~~~~~~~
In file included from ./modules/gltf/tests/test_gltf_extras.h:44,
from ./modules/modules_tests.gen.h:45,
from ./tests/test_main.cpp:78,
from tests/.scu/scu_tests_exception_1.gen.cpp:1:
./scene/resources/3d/primitive_meshes.h:154:21: note: candidates are: 'static void CapsuleMesh::create_mesh_array(Array&, real_t, real_t, real_t, int, int, bool, real_t)'
154 | static void create_mesh_array(Array &p_arr, real_t p_radius_top, real_t p_radius_bottom, real_t p_mid_height, int p_radial_segments = 64, int p_rings = 16, bool p_add_uv2 = false, const real_t p_uv2_padding = 1.0);
| ^~~~~~~~~~~~~~~~~
./scene/resources/3d/primitive_meshes.h:152:21: note: 'static void CapsuleMesh::create_mesh_array(Array&, real_t, real_t, int, int, bool, real_t)'
152 | static void create_mesh_array(Array &p_arr, real_t p_radius, real_t p_height, int p_radial_segments = 64, int p_rings = 16, bool p_add_uv2 = false, const real_t p_uv2_padding = 1.0);
| ^~~~~~~~~~~~~~~~~
In file included from ./modules/gltf/tests/test_gltf_extras.h:44,
from ./modules/modules_tests.gen.h:45,
from ./tests/test_main.cpp:78,
from tests/.scu/scu_tests_exception_1.gen.cpp:1:
./scene/resources/3d/primitive_meshes.h:127:7: note: 'class CapsuleMesh' defined here
127 | class CapsuleMesh : public PrimitiveMesh {
| ^~~~~~~~~~~
scons: *** [tests/.scu/scu_tests_exception_1.gen.linuxbsd.editor.dev.double.x86_64.san.o] Error 1
ranlib modules/libmodules.linuxbsd.editor.dev.double.x86_64.san.a
scons: building terminated because of errors.
INFO: Time elapsed: 00:35:38.51
Error: Process completed with exit code 2. |
|
The shape resources with the new tapered properties combined look mostly fine. Combining that tapered feature with existing shape types implied doing it on the PhysicsServer API and extension layer as well. Right now those server and extension files have extra entries in enums and functions that should not exist. It should not concern the user at the server API level if they use e.g. a normal capsule or a tapered capsule, it is all just capsule with some extra tapered properties. Now there are valid reason to handle them different (mostly performance) but that is something the physics engine backend can and should internally branch to more optimized paths if it detects certain properties in use. It is not a concern of the front server API to do this technical split. So |
|
@smix8 Removing that would mean either always creating tapered shapes for engines that can, or transferring a lot more data to be, in fine, discarded. Got a preference on how to do that ? |
|
Regarding data to transfer, I see two way:
Option 2 is a bit more elegant but less straightforward |
|
I am not sure I follow with the "always creating more data". The only place you need to send geometry data is with the So you can add key-value pairs for tapered related properties when tapered is enabled and used on that shape and leave them out when not. Everything else is up to the physics backend and does not concern the core physics server directly, e.g. falling back to the simpler default shape when the tapered keys are not found in the dict. On creation of e.g. a capsule shape all that is happening (or should) is a request for a |
|
@smix8 Coming back on this now: This also means that setting height before radius isn't the same as setting height after radius, but it was the same before. IMO this PR now accomplishes what you asked. |
|
The way to avoid this change of properties and magic radius calculation that will create compatibility problems and make users trip is to add the It is okay when users need to click a single bool to toggle a new and more niche feature. Lots of Resources do this in the Editor for their more complex stuff. You can rename your current
That way ...
|
|
@smix8 I've added what you wanted, but this makes it worse:
Please reconsider the implications of what you're asking. A checkbox doesn't make it better. Also, I haven't found a way to show/hide parameters based on that boolean. Only thing I found was to hide a whole group, but this isn't what we want here. Perhaps this change is better done as a editor-only change, that is only the controls change, but behind the hood, there is only top_radius, bottom_radius and mid_height. |
You can do a tiered system similar to the problem in MeshInstance3D which needs to get the material but there's a material in the mesh, a material in the meshinstance3d's list of material overrides and the base class's default material. For your tier list of:
You can use the condition of checking if property is set to the default value or not to choose the tiers. Alternatively, it might be legal to not serialize the old properties and only serialize the new ones. |
Co-authored-by: Aaron Franke <arnfranke@yahoo.com> Co-authored-by: K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
…nify gizmo handles across Capsule and Cylinders
… switching is handled by the physics server
|
I've undone the last changes, as I haven't been able to make them work like you asked (that is, i've reverted to top_radius, bottom_radius and height/mid_height). It's also rebased to master. The documentation for CapsuleMesh get_tangent_angle doesn't work for some reason. |
AThousandShips
left a comment
There was a problem hiding this comment.
Otherwise the style looks good, haven't tested
|
You can use
I'm not sure what approach is best when it comes to handling clashing properties that maps to the same underlying variable, one approach is to use For the data transfer you don't need to always send all the data, for example: void CylinderShape3D::_update_shape() {
Dictionary d;
d.reserve(is_tapered() ? 5 : 2);
d["radius"] = get_radius();
d["height"] = get_height();
if(is_tapered()) {
d["tapered"] = is_tapered();
d["radius_top"] = get_top_radius();
d["radius_bottom"] = get_bottom_radius();
}
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
Shape3D::_update_shape();
}And then you will only extract the new properties if the |
|
@NoctemCat I've added the requested Gizmos are still not the best but they work. |
|
Will squash everything once it's all okay'ed |
This is the continuation of #109009
I've fixed the mesh generation of the tapered capsule, and right now am looking at also adding tapered cylinders.
Bugsquad edit: