Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Make radius & height in CapsuleShape3D independent #51522

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions doc/classes/CapsuleMesh.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
<methods>
</methods>
<members>
<member name="mid_height" type="float" setter="set_mid_height" getter="get_mid_height" default="1.0">
Height of the middle cylindrical part of the capsule (without the hemispherical ends).
[b]Note:[/b] The capsule's total height is equal to [member mid_height] + 2 * [member radius].
<member name="height" type="float" setter="set_height" getter="get_height" default="3.0">
Total height of the capsule mesh (including the hemispherical ends).
</member>
<member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="64">
Number of radial segments on the capsule mesh.
Expand Down
2 changes: 1 addition & 1 deletion doc/classes/CapsuleShape3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<methods>
</methods>
<members>
<member name="height" type="float" setter="set_height" getter="get_height" default="1.0">
<member name="height" type="float" setter="set_height" getter="get_height" default="3.0">
The capsule's height.
</member>
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
Expand Down
9 changes: 3 additions & 6 deletions editor/plugins/node_3d_editor_gizmos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4168,14 +4168,11 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i

if (Object::cast_to<CapsuleShape3D>(*s)) {
Vector3 axis;
axis[p_id == 0 ? 0 : 2] = 1.0;
axis[p_id == 0 ? 0 : 1] = 1.0;
Ref<CapsuleShape3D> cs2 = s;
Vector3 ra, rb;
Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
if (p_id == 1) {
d -= cs2->get_radius();
}

if (Node3DEditor::get_singleton()->is_snap_enabled()) {
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
Expand Down Expand Up @@ -4397,7 +4394,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {

Vector<Vector3> points;

Vector3 d(0, height * 0.5, 0);
Vector3 d(0, height * 0.5 - radius, 0);
for (int i = 0; i < 360; i++) {
float ra = Math::deg2rad((float)i);
float rb = Math::deg2rad((float)i + 1);
Expand Down Expand Up @@ -4456,7 +4453,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {

Vector<Vector3> handles;
handles.push_back(Vector3(cs2->get_radius(), 0, 0));
handles.push_back(Vector3(0, cs2->get_height() * 0.5 + cs2->get_radius(), 0));
handles.push_back(Vector3(0, cs2->get_height() * 0.5, 0));
p_gizmo->add_handles(handles, handles_material);
}

Expand Down
2 changes: 1 addition & 1 deletion editor/plugins/skeleton_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
const real_t radius(half_height * 0.2);

CapsuleShape3D *bone_shape_capsule = memnew(CapsuleShape3D);
bone_shape_capsule->set_height((half_height - radius) * 2);
bone_shape_capsule->set_height(half_height * 2);
bone_shape_capsule->set_radius(radius);

CollisionShape3D *bone_shape = memnew(CollisionShape3D);
Expand Down
2 changes: 1 addition & 1 deletion modules/navigation/navigation_mesh_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transfor
Ref<CapsuleMesh> capsule_mesh;
capsule_mesh.instantiate();
capsule_mesh->set_radius(capsule->get_radius());
capsule_mesh->set_mid_height(capsule->get_height() / 2.0);
capsule_mesh->set_height(capsule->get_height());
mesh = capsule_mesh;
}

Expand Down
10 changes: 8 additions & 2 deletions scene/resources/capsule_shape_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {

Vector<Vector3> points;

Vector3 d(0, height * 0.5, 0);
Vector3 d(0, height * 0.5 - radius, 0);
for (int i = 0; i < 360; i++) {
float ra = Math::deg2rad((float)i);
float rb = Math::deg2rad((float)i + 1);
Expand Down Expand Up @@ -67,7 +67,7 @@ Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
}

real_t CapsuleShape3D::get_enclosing_radius() const {
return radius + height * 0.5;
return height * 0.5;
}

void CapsuleShape3D::_update_shape() {
Expand All @@ -80,6 +80,9 @@ void CapsuleShape3D::_update_shape() {

void CapsuleShape3D::set_radius(float p_radius) {
radius = p_radius;
if (radius > height * 0.5) {
radius = height * 0.5;
}
_update_shape();
notify_change_to_owners();
}
Expand All @@ -90,6 +93,9 @@ float CapsuleShape3D::get_radius() const {

void CapsuleShape3D::set_height(float p_height) {
height = p_height;
if (radius > height * 0.5) {
height = radius * 2;
}
_update_shape();
notify_change_to_owners();
}
Expand Down
2 changes: 1 addition & 1 deletion scene/resources/capsule_shape_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
class CapsuleShape3D : public Shape3D {
GDCLASS(CapsuleShape3D, Shape3D);
float radius = 1.0;
float height = 1.0;
float height = 3.0;

protected:
static void _bind_methods();
Expand Down
28 changes: 17 additions & 11 deletions scene/resources/primitive_meshes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const {
z = cos(u * Math_TAU);

Vector3 p = Vector3(x * radius * w, y, -z * radius * w);
points.push_back(p + Vector3(0.0, 0.5 * mid_height, 0.0));
points.push_back(p + Vector3(0.0, 0.5 * height - radius, 0.0));
normals.push_back(p.normalized());
ADD_TANGENT(z, 0.0, x, 1.0)
uvs.push_back(Vector2(u, v * onethird));
Expand Down Expand Up @@ -328,8 +328,8 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const {
v = j;
v /= (rings + 1);

y = mid_height * v;
y = (mid_height * 0.5) - y;
y = (height - 2.0 * radius) * v;
y = (0.5 * height - radius) - y;

for (i = 0; i <= radial_segments; i++) {
u = i;
Expand Down Expand Up @@ -379,7 +379,7 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const {
z = cos(u2 * Math_TAU);

Vector3 p = Vector3(x * radius * w, y, -z * radius * w);
points.push_back(p + Vector3(0.0, -0.5 * mid_height, 0.0));
points.push_back(p + Vector3(0.0, -0.5 * height + radius, 0.0));
normals.push_back(p.normalized());
ADD_TANGENT(z, 0.0, x, 1.0)
uvs.push_back(Vector2(u2, twothirds + ((v - 1.0) * onethird)));
Expand Down Expand Up @@ -410,36 +410,42 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const {
void CapsuleMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CapsuleMesh::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &CapsuleMesh::get_radius);
ClassDB::bind_method(D_METHOD("set_mid_height", "mid_height"), &CapsuleMesh::set_mid_height);
ClassDB::bind_method(D_METHOD("get_mid_height"), &CapsuleMesh::get_mid_height);
ClassDB::bind_method(D_METHOD("set_height", "height"), &CapsuleMesh::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CapsuleMesh::get_height);

ClassDB::bind_method(D_METHOD("set_radial_segments", "segments"), &CapsuleMesh::set_radial_segments);
ClassDB::bind_method(D_METHOD("get_radial_segments"), &CapsuleMesh::get_radial_segments);
ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CapsuleMesh::set_rings);
ClassDB::bind_method(D_METHOD("get_rings"), &CapsuleMesh::get_rings);

ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mid_height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_mid_height", "get_mid_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
}

void CapsuleMesh::set_radius(const float p_radius) {
radius = p_radius;
if (radius > height * 0.5) {
radius = height * 0.5;
}
_request_update();
}

float CapsuleMesh::get_radius() const {
return radius;
}

void CapsuleMesh::set_mid_height(const float p_mid_height) {
mid_height = p_mid_height;
void CapsuleMesh::set_height(const float p_height) {
height = p_height;
if (radius > height * 0.5) {
height = radius * 2;
}
_request_update();
}

float CapsuleMesh::get_mid_height() const {
return mid_height;
float CapsuleMesh::get_height() const {
return height;
}

void CapsuleMesh::set_radial_segments(const int p_segments) {
Expand Down
6 changes: 3 additions & 3 deletions scene/resources/primitive_meshes.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class CapsuleMesh : public PrimitiveMesh {

private:
float radius = 1.0;
float mid_height = 1.0;
float height = 3.0;
int radial_segments = 64;
int rings = 8;

Expand All @@ -120,8 +120,8 @@ class CapsuleMesh : public PrimitiveMesh {
void set_radius(const float p_radius);
float get_radius() const;

void set_mid_height(const float p_mid_height);
float get_mid_height() const;
void set_height(const float p_height);
float get_height() const;

void set_radial_segments(const int p_segments);
int get_radial_segments() const;
Expand Down
16 changes: 8 additions & 8 deletions servers/physics_3d/collision_solver_3d_sat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@ static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform3D &p

//capsule sphere 1, sphere

Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);
Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius());

Vector3 capsule_ball_1 = p_transform_b.origin + capsule_axis;

Expand Down Expand Up @@ -1207,7 +1207,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform3D &p_tr
// capsule balls, edges of A

for (int i = 0; i < 2; i++) {
Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);
Vector3 capsule_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius());

Vector3 sphere_pos = p_transform_b.origin + ((i == 0) ? capsule_axis : -capsule_axis);

Expand Down Expand Up @@ -1607,8 +1607,8 @@ static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform3D &

// some values

Vector3 capsule_A_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);
Vector3 capsule_B_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5);
Vector3 capsule_A_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5 - capsule_A->get_radius());
Vector3 capsule_B_axis = p_transform_b.basis.get_axis(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius());

Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis;
Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis;
Expand Down Expand Up @@ -1679,8 +1679,8 @@ static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform3D

Vector3 capsule_A_axis = p_transform_a.basis.get_axis(1);

Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis * (capsule_A->get_height() * 0.5);
Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis * (capsule_A->get_height() * 0.5);
Vector3 capsule_A_ball_1 = p_transform_a.origin + capsule_A_axis * (capsule_A->get_height() * 0.5 - capsule_A->get_radius());
Vector3 capsule_A_ball_2 = p_transform_a.origin - capsule_A_axis * (capsule_A->get_height() * 0.5 - capsule_A->get_radius());

if (!separator.test_axis((p_transform_b.origin - capsule_A_ball_1).cross(cylinder_B_axis).cross(cylinder_B_axis).normalized())) {
return;
Expand Down Expand Up @@ -1768,7 +1768,7 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf
for (int i = 0; i < 2; i++) {
// edges of B, capsule cylinder

Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);
Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5 - capsule_A->get_radius());

Vector3 sphere_pos = p_transform_a.origin + ((i == 0) ? capsule_axis : -capsule_axis);

Expand Down Expand Up @@ -1808,7 +1808,7 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform3D &p_t

// edges of B, capsule cylinder

Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5);
Vector3 capsule_axis = p_transform_a.basis.get_axis(1) * (capsule_A->get_height() * 0.5 - capsule_A->get_radius());

for (int i = 0; i < 3; i++) {
// edge-cylinder
Expand Down
32 changes: 16 additions & 16 deletions servers/physics_3d/shape_3d_sw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,10 +424,10 @@ BoxShape3DSW::BoxShape3DSW() {

void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
Vector3 n = p_transform.basis.xform_inv(p_normal).normalized();
real_t h = (n.y > 0) ? height : -height;
real_t h = height * 0.5 - radius;

n *= radius;
n.y += h * 0.5;
n.y += (n.y > 0) ? h : -h;

r_max = p_normal.dot(p_transform.xform(n));
r_min = p_normal.dot(p_transform.xform(-n));
Expand All @@ -436,10 +436,10 @@ void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform3D
Vector3 CapsuleShape3DSW::get_support(const Vector3 &p_normal) const {
Vector3 n = p_normal;

real_t h = (n.y > 0) ? height : -height;
real_t h = height * 0.5 - radius;

n *= radius;
n.y += h * 0.5;
n.y += (n.y > 0) ? h : -h;
return n;
}

Expand All @@ -457,15 +457,15 @@ void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3
r_amount = 2;
r_type = FEATURE_EDGE;
r_supports[0] = n;
r_supports[0].y += height * 0.5;
r_supports[0].y += height * 0.5 - radius;
r_supports[1] = n;
r_supports[1].y -= height * 0.5;
r_supports[1].y -= height * 0.5 - radius;

} else {
real_t h = (d > 0) ? height : -height;
real_t h = height * 0.5 - radius;

n *= radius;
n.y += h * 0.5;
n.y += (d > 0) ? h : -h;
r_amount = 1;
r_type = FEATURE_POINT;
*r_supports = n;
Expand All @@ -484,7 +484,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &

// test against cylinder and spheres :-|

collided = Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &auxres, &auxn, 1);
collided = Geometry3D::segment_intersects_cylinder(p_begin, p_end, height - radius * 2.0, radius, &auxres, &auxn, 1);

if (collided) {
real_t d = norm.dot(auxres);
Expand All @@ -496,7 +496,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
}
}

collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * 0.5, 0), radius, &auxres, &auxn);
collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * 0.5 - radius, 0), radius, &auxres, &auxn);

if (collided) {
real_t d = norm.dot(auxres);
Expand All @@ -508,7 +508,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
}
}

collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * -0.5, 0), radius, &auxres, &auxn);
collided = Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(0, height * -0.5 + radius, 0), radius, &auxres, &auxn);

if (collided) {
real_t d = norm.dot(auxres);
Expand All @@ -529,19 +529,19 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &
}

bool CapsuleShape3DSW::intersect_point(const Vector3 &p_point) const {
if (Math::abs(p_point.y) < height * 0.5) {
if (Math::abs(p_point.y) < height * 0.5 - radius) {
return Vector3(p_point.x, 0, p_point.z).length() < radius;
} else {
Vector3 p = p_point;
p.y = Math::abs(p.y) - height * 0.5;
p.y = Math::abs(p.y) - height * 0.5 + radius;
return p.length() < radius;
}
}

Vector3 CapsuleShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
Vector3 s[2] = {
Vector3(0, -height * 0.5, 0),
Vector3(0, height * 0.5, 0),
Vector3(0, -height * 0.5 + radius, 0),
Vector3(0, height * 0.5 - radius, 0),
};

Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, s);
Expand All @@ -566,7 +566,7 @@ Vector3 CapsuleShape3DSW::get_moment_of_inertia(real_t p_mass) const {
void CapsuleShape3DSW::_setup(real_t p_height, real_t p_radius) {
height = p_height;
radius = p_radius;
configure(AABB(Vector3(-radius, -height * 0.5 - radius, -radius), Vector3(radius * 2, height + radius * 2.0, radius * 2)));
configure(AABB(Vector3(-radius, -height * 0.5, -radius), Vector3(radius * 2, height, radius * 2)));
}

void CapsuleShape3DSW::set_data(const Variant &p_data) {
Expand Down
2 changes: 1 addition & 1 deletion servers/physics_3d/shape_3d_sw.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ class CapsuleShape3DSW : public Shape3DSW {
_FORCE_INLINE_ real_t get_height() const { return height; }
_FORCE_INLINE_ real_t get_radius() const { return radius; }

virtual real_t get_area() const { return 4.0 / 3.0 * Math_PI * radius * radius * radius + height * Math_PI * radius * radius; }
virtual real_t get_area() const { return 4.0 / 3.0 * Math_PI * radius * radius * radius + (height - radius * 2.0) * Math_PI * radius * radius; }

virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CAPSULE; }

Expand Down