added cylinder shape support

This commit is contained in:
muiroc 2018-06-13 00:53:28 +02:00
parent d2b75557a5
commit 0a36e974da
14 changed files with 398 additions and 4 deletions

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CylinderShape" inherits="Shape" category="Core" version="3.1">
<brief_description>
Cylinder shape for collisions.
</brief_description>
<description>
Cylinder shape for collisions.
</description>
<tutorials>
</tutorials>
<demos>
</demos>
<methods>
</methods>
<members>
<member name="height" type="float" setter="set_height" getter="get_height">
The cylinder's height.
</member>
<member name="radius" type="float" setter="set_radius" getter="get_radius">
The cylinder's radius.
</member>
</members>
<constants>
</constants>
</class>

View file

@ -1413,16 +1413,19 @@
<constant name="SHAPE_CAPSULE" value="4" enum="ShapeType">
The [Shape] is a [CapsuleShape].
</constant>
<constant name="SHAPE_CONVEX_POLYGON" value="5" enum="ShapeType">
<constant name="SHAPE_CYLINDER" value="5" enum="ShapeType">
The [Shape] is a [CylinderShape].
</constant>
<constant name="SHAPE_CONVEX_POLYGON" value="6" enum="ShapeType">
The [Shape] is a [ConvexPolygonShape].
</constant>
<constant name="SHAPE_CONCAVE_POLYGON" value="6" enum="ShapeType">
<constant name="SHAPE_CONCAVE_POLYGON" value="7" enum="ShapeType">
The [Shape] is a [ConcavePolygonShape].
</constant>
<constant name="SHAPE_HEIGHTMAP" value="7" enum="ShapeType">
<constant name="SHAPE_HEIGHTMAP" value="8" enum="ShapeType">
The [Shape] is a [HeightMapShape].
</constant>
<constant name="SHAPE_CUSTOM" value="8" enum="ShapeType">
<constant name="SHAPE_CUSTOM" value="9" enum="ShapeType">
This constant is used internally by the engine. Any attempt to create this kind of shape results in an error.
</constant>
<constant name="AREA_PARAM_GRAVITY" value="0" enum="AreaParameter">

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16" height="16" version="1.1" viewBox="0 0 14.999999 14.999999" xmlns="http://www.w3.org/2000/svg">
<rect fill="#68b6ff" width="13.171325" height="7.6993308" x="0.89037383" y="3.6879442"/>
<ellipse fill="#a2d2ff" cx="7.4772978" cy="3.7229116" rx="6.5864792" ry="2.820821"/>
<ellipse fill="#68b6ff" cx="7.4746876" cy="11.34481" rx="6.5864792" ry="2.8208208"/>
</svg>

After

Width:  |  Height:  |  Size: 433 B

View file

@ -36,6 +36,7 @@
#include "scene/resources/box_shape.h"
#include "scene/resources/capsule_shape.h"
#include "scene/resources/convex_polygon_shape.h"
#include "scene/resources/cylinder_shape.h"
#include "scene/resources/plane_shape.h"
#include "scene/resources/primitive_meshes.h"
#include "scene/resources/ray_shape.h"
@ -1861,6 +1862,11 @@ String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const {
return p_idx == 0 ? "Radius" : "Height";
}
if (Object::cast_to<CylinderShape>(*s)) {
return p_idx == 0 ? "Radius" : "Height";
}
if (Object::cast_to<RayShape>(*s)) {
return "Length";
@ -1892,6 +1898,12 @@ Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const {
return p_idx == 0 ? cs->get_radius() : cs->get_height();
}
if (Object::cast_to<CylinderShape>(*s)) {
Ref<CylinderShape> cs = s;
return p_idx == 0 ? cs->get_radius() : cs->get_height();
}
if (Object::cast_to<RayShape>(*s)) {
Ref<RayShape> cs = s;
@ -1972,6 +1984,24 @@ void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const P
else if (p_idx == 1)
cs->set_height(d * 2.0);
}
if (Object::cast_to<CylinderShape>(*s)) {
Vector3 axis;
axis[p_idx == 0 ? 0 : 1] = 1.0;
Ref<CylinderShape> cs = s;
Vector3 ra, rb;
Geometry::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
float d = axis.dot(ra);
if (d < 0.001)
d = 0.001;
if (p_idx == 0)
cs->set_radius(d);
else if (p_idx == 1)
cs->set_height(d * 2.0);
}
}
void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
Ref<Shape> s = cs->get_shape();
@ -2033,6 +2063,31 @@ void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_resto
ur->commit_action();
}
if (Object::cast_to<CylinderShape>(*s)) {
Ref<CylinderShape> ss = s;
if (p_cancel) {
if (p_idx == 0)
ss->set_radius(p_restore);
else
ss->set_height(p_restore);
return;
}
UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
if (p_idx == 0) {
ur->create_action(TTR("Change Cylinder Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
} else {
ur->create_action(TTR("Change Cylinder Shape Height"));
ur->add_do_method(ss.ptr(), "set_height", ss->get_height());
ur->add_undo_method(ss.ptr(), "set_height", p_restore);
}
ur->commit_action();
}
if (Object::cast_to<RayShape>(*s)) {
Ref<RayShape> ss = s;
@ -2209,6 +2264,67 @@ void CollisionShapeSpatialGizmo::redraw() {
add_handles(handles);
}
if (Object::cast_to<CylinderShape>(*s)) {
Ref<CylinderShape> cs = s;
float radius = cs->get_radius();
float height = cs->get_height();
Vector<Vector3> points;
Vector3 d(0, height * 0.5, 0);
for (int i = 0; i < 360; i++) {
float ra = Math::deg2rad((float)i);
float rb = Math::deg2rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(b.x, 0, b.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
points.push_back(Vector3(b.x, 0, b.y) - d);
if (i % 90 == 0) {
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
}
}
add_lines(points, material);
Vector<Vector3> collision_segments;
for (int i = 0; i < 64; i++) {
float ra = i * Math_PI * 2.0 / 64.0;
float rb = (i + 1) * Math_PI * 2.0 / 64.0;
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
collision_segments.push_back(Vector3(b.x, 0, b.y) + d);
collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
collision_segments.push_back(Vector3(b.x, 0, b.y) - d);
if (i % 16 == 0) {
collision_segments.push_back(Vector3(a.x, 0, a.y) + d);
collision_segments.push_back(Vector3(a.x, 0, a.y) - d);
}
}
add_collision_segments(collision_segments);
Vector<Vector3> handles;
handles.push_back(Vector3(cs->get_radius(), 0, 0));
handles.push_back(Vector3(0, cs->get_height() * 0.5, 0));
add_handles(handles);
}
if (Object::cast_to<PlaneShape>(*s)) {
Ref<PlaneShape> ps = s;

View file

@ -113,6 +113,10 @@ RID BulletPhysicsServer::shape_create(ShapeType p_shape) {
shape = bulletnew(CapsuleShapeBullet);
} break;
case SHAPE_CYLINDER: {
shape = bulletnew(CylinderShapeBullet);
} break;
case SHAPE_CONVEX_POLYGON: {
shape = bulletnew(ConvexPolygonShapeBullet);

View file

@ -226,6 +226,7 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() {
case PhysicsServer::SHAPE_SPHERE:
case PhysicsServer::SHAPE_BOX:
case PhysicsServer::SHAPE_CAPSULE:
case PhysicsServer::SHAPE_CYLINDER:
case PhysicsServer::SHAPE_CONVEX_POLYGON:
case PhysicsServer::SHAPE_RAY: {
shapes[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin));

View file

@ -113,6 +113,10 @@ btCapsuleShapeZ *ShapeBullet::create_shape_capsule(btScalar radius, btScalar hei
return bulletnew(btCapsuleShapeZ(radius, height));
}
btCylinderShape *ShapeBullet::create_shape_cylinder(btScalar radius, btScalar height) {
return bulletnew(btCylinderShape(btVector3(radius, height / 2.0, radius)));
}
btConvexPointCloudShape *ShapeBullet::create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling) {
return bulletnew(btConvexPointCloudShape(&p_vertices[0], p_vertices.size(), p_local_scaling));
}
@ -254,6 +258,39 @@ btCollisionShape *CapsuleShapeBullet::create_bt_shape(const btVector3 &p_implici
return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin));
}
/* Cylinder */
CylinderShapeBullet::CylinderShapeBullet() :
ShapeBullet() {}
void CylinderShapeBullet::set_data(const Variant &p_data) {
Dictionary d = p_data;
ERR_FAIL_COND(!d.has("radius"));
ERR_FAIL_COND(!d.has("height"));
setup(d["height"], d["radius"]);
}
Variant CylinderShapeBullet::get_data() const {
Dictionary d;
d["radius"] = radius;
d["height"] = height;
return d;
}
PhysicsServer::ShapeType CylinderShapeBullet::get_type() const {
return PhysicsServer::SHAPE_CYLINDER;
}
void CylinderShapeBullet::setup(real_t p_height, real_t p_radius) {
radius = p_radius;
height = p_height;
notifyShapeChanged();
}
btCollisionShape *CylinderShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) {
return prepare(ShapeBullet::create_shape_cylinder(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin));
}
/* Convex polygon */
ConvexPolygonShapeBullet::ConvexPolygonShapeBullet() :

View file

@ -82,6 +82,7 @@ public:
static class btSphereShape *create_shape_sphere(btScalar radius);
static class btBoxShape *create_shape_box(const btVector3 &boxHalfExtents);
static class btCapsuleShapeZ *create_shape_capsule(btScalar radius, btScalar height);
static class btCylinderShape *create_shape_cylinder(btScalar radius, btScalar height);
/// IMPORTANT: Remember to delete the shape interface by calling: delete my_shape->getMeshInterface();
static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
@ -158,6 +159,25 @@ private:
void setup(real_t p_height, real_t p_radius);
};
class CylinderShapeBullet : public ShapeBullet {
real_t height;
real_t radius;
public:
CylinderShapeBullet();
_FORCE_INLINE_ real_t get_height() { return height; }
_FORCE_INLINE_ real_t get_radius() { return radius; }
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
virtual PhysicsServer::ShapeType get_type() const;
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0);
private:
void setup(real_t p_height, real_t p_radius);
};
class ConvexPolygonShapeBullet : public ShapeBullet {
public:

View file

@ -128,6 +128,7 @@
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape.h"
#include "scene/resources/convex_polygon_shape_2d.h"
#include "scene/resources/cylinder_shape.h"
#include "scene/resources/default_theme/default_theme.h"
#include "scene/resources/dynamic_font.h"
#include "scene/resources/dynamic_font_stb.h"
@ -510,6 +511,7 @@ void register_scene_types() {
ClassDB::register_class<SphereShape>();
ClassDB::register_class<BoxShape>();
ClassDB::register_class<CapsuleShape>();
ClassDB::register_class<CylinderShape>();
ClassDB::register_class<PlaneShape>();
ClassDB::register_class<ConvexPolygonShape>();
ClassDB::register_class<ConcavePolygonShape>();

View file

@ -0,0 +1,116 @@
/*************************************************************************/
/* cylinder_shape.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "cylinder_shape.h"
#include "servers/physics_server.h"
Vector<Vector3> CylinderShape::_gen_debug_mesh_lines() {
float radius = get_radius();
float height = get_height();
Vector<Vector3> points;
Vector3 d(0, height * 0.5, 0);
for (int i = 0; i < 360; i++) {
float ra = Math::deg2rad((float)i);
float rb = Math::deg2rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(b.x, 0, b.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
points.push_back(Vector3(b.x, 0, b.y) - d);
if (i % 90 == 0) {
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(a.x, 0, a.y) - d);
}
}
return points;
}
void CylinderShape::_update_shape() {
Dictionary d;
d["radius"] = radius;
d["height"] = height;
PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
}
void CylinderShape::set_radius(float p_radius) {
radius = p_radius;
_update_shape();
notify_change_to_owners();
_change_notify("radius");
}
float CylinderShape::get_radius() const {
return radius;
}
void CylinderShape::set_height(float p_height) {
height = p_height;
_update_shape();
notify_change_to_owners();
_change_notify("height");
}
float CylinderShape::get_height() const {
return height;
}
void CylinderShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &CylinderShape::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &CylinderShape::get_radius);
ClassDB::bind_method(D_METHOD("set_height", "height"), &CylinderShape::set_height);
ClassDB::bind_method(D_METHOD("get_height"), &CylinderShape::get_height);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.01,4096,0.01"), "set_height", "get_height");
}
CylinderShape::CylinderShape() :
Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_CYLINDER)) {
radius = 1.0;
height = 2.0;
_update_shape();
}

View file

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

View file

@ -65,6 +65,11 @@ RID PhysicsServerSW::shape_create(ShapeType p_shape) {
shape = memnew(CapsuleShapeSW);
} break;
case SHAPE_CYLINDER: {
ERR_EXPLAIN("CylinderShape is not supported in GodotPhysics. Please switch to Bullet in the Project Settings.");
ERR_FAIL_V(RID());
} break;
case SHAPE_CONVEX_POLYGON: {
shape = memnew(ConvexPolygonShapeSW);

View file

@ -664,6 +664,7 @@ void PhysicsServer::_bind_methods() {
BIND_ENUM_CONSTANT(SHAPE_SPHERE);
BIND_ENUM_CONSTANT(SHAPE_BOX);
BIND_ENUM_CONSTANT(SHAPE_CAPSULE);
BIND_ENUM_CONSTANT(SHAPE_CYLINDER);
BIND_ENUM_CONSTANT(SHAPE_CONVEX_POLYGON);
BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON);
BIND_ENUM_CONSTANT(SHAPE_HEIGHTMAP);

View file

@ -228,6 +228,7 @@ public:
SHAPE_SPHERE, ///< float:"radius"
SHAPE_BOX, ///< vec3:"extents"
SHAPE_CAPSULE, ///< dict( float:"radius", float:"height"):capsule
SHAPE_CYLINDER, ///< dict( float:"radius", float:"height"):cylinder
SHAPE_CONVEX_POLYGON, ///< array of planes:"planes"
SHAPE_CONCAVE_POLYGON, ///< vector3 array:"triangles" , or Dictionary with "indices" (int array) and "triangles" (Vector3 array)
SHAPE_HEIGHTMAP, ///< dict( int:"width", int:"depth",float:"cell_size", float_array:"heights"