reactphysics3d icon indicating copy to clipboard operation
reactphysics3d copied to clipboard

Cylinder and cone shapes

Open tksuoran opened this issue 3 years ago • 11 comments

Are there any plans to have more collision shapes like cylinder and cone?

For example Jitter physics provides cylinder, cone and minkowski sum shapes, each of them being just few lines of code.

tksuoran avatar May 21 '21 07:05 tksuoran

Hello. Thanks for your feedback.

I currently don't plan to add those shapes in a near future. It is currently possible to approximate those shapes with a tessellated mesh and using a ConvexMeshShape in ReactPhysics3D.

However, if many people are interested in this feature. I can reconsider this of course.

DanielChappuis avatar May 21 '21 08:05 DanielChappuis

Yeah, I am also looking forward to a cylinder shape since I am working on a dice simulation software. Maybe currently I have to resort to a tessellated mesh even though it looks a bit odd.

Teddy-van-Jerry avatar Oct 03 '21 13:10 Teddy-van-Jerry

Yeah, I am also looking forward to a cylinder shape since I am working on a dice simulation software. Maybe currently I have to resort to a tessellated mesh even though it looks a bit odd.

I hope so for I need to do the same work haha.

Dorbmon avatar Nov 02 '21 12:11 Dorbmon

@Dorbmon I have successfully used a ConvexMeshShape to approximate the cylinder shape though the speed is not satisfactory. Here is the main code:

// ====== Create a Cylinder ======
// Use ConvexMeshShape to approximate a cylinder.
// Be cafeful to set vertices of a face as counter clockwise
// order as seen from the outside of your convex mesh.

RigidBody* body = world->createRigidBody(transform);

const int   cylinderSides = 1000; // number of side faces
const float cylinderR     = 5; // radius [m]
const float cylinderH     = 4; // height [m]
// Array with the vertices coordinates of the convex mesh
float vertices[6 * cylinderSides]; // 2 * cylinderSides * 3
for (int i = 0; i != cylinderSides; i++) {
    vertices[3 * i] = cylinderR * std::cos(2 * 3.14159265358979 * i / cylinderSides);
    vertices[3 * i + 1] = -cylinderH / 2;
    vertices[3 * i + 2] = cylinderR * std::sin(2 * 3.14159265358979 * i / cylinderSides);
    vertices[3 * (cylinderSides + i)] = vertices[3 * i];
    vertices[3 * (cylinderSides + i) + 1] = cylinderH / 2;
    vertices[3 * (cylinderSides + i) + 2] = vertices[3 * i + 2];
}
// Array with the vertices indices for each face of the mesh
int indices[6 * cylinderSides]; // 4 * cylinderSides + cylinderSides * 2
for (int i = 0; i != cylinderSides - 1; i++) {
    // side face
    indices[4 * i    ] = i;
    indices[4 * i + 1] = i + 1;
    indices[4 * i + 2] = cylinderSides + i + 1;
    indices[4 * i + 3] = cylinderSides + i;
    // top and bottom face
    indices[4 * cylinderSides + i] = cylinderSides - i - 1;
    indices[5 * cylinderSides + i] = cylinderSides + i;
}
indices[4 * cylinderSides - 4] = cylinderSides - 1;
indices[4 * cylinderSides - 3] = 0;
indices[4 * cylinderSides - 2] = cylinderSides;
indices[4 * cylinderSides - 1] = 2 * cylinderSides - 1;
indices[5 * cylinderSides - 1] = 0;
indices[6 * cylinderSides - 1] = 2 * cylinderSides - 1;
// Description of the (cylinderSides + 2) faces of the convex mesh
PolygonVertexArray::PolygonFace polygonFaces[cylinderSides + 2];
// PolygonVertexArray::PolygonFace* face = polygonFaces;
for (int f = 0; f != cylinderSides; f++) { // first for side faces
    // First vertex of the face in the indices array
    polygonFaces[f].indexBase = f * 4;
    // Number of vertices in the face
    polygonFaces[f].nbVertices = 4;
}
polygonFaces[cylinderSides].indexBase = cylinderSides * 4;
polygonFaces[cylinderSides].nbVertices = cylinderSides;
polygonFaces[cylinderSides + 1].indexBase = cylinderSides * 5;
polygonFaces[cylinderSides + 1].nbVertices = cylinderSides;

// Create the polygon vertex array
PolygonVertexArray * polygonVertexArray = new PolygonVertexArray(
    2 * cylinderSides, vertices, 3 * sizeof(float), indices,
    sizeof(int), cylinderSides + 2 , polygonFaces,
    PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE,
    PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE);

// Create the polyhedron mesh
PolyhedronMesh* polyhedronMesh = physicsCommon.createPolyhedronMesh(polygonVertexArray);
// Create the convex mesh collision shape
ConvexMeshShape* cylinderShape = physicsCommon.createConvexMeshShape(polyhedronMesh);
body->addCollider(cylinderShape, Transform::identity());

The full code is in this file of repo Dice Simulation.

Teddy-van-Jerry avatar Dec 15 '21 17:12 Teddy-van-Jerry

@Teddy-van-Jerry Hello, I tried your cylinder code but it seems to fall straight through my floor?

patrikpatrik avatar Dec 30 '22 04:12 patrikpatrik

@patrikpatrik Hi, it is quite a long time since I wrote this code. At that time, it was version 0.8.0. I am not sure whether this method is broken for 0.9.0. Have you tried this simple code where there is also a floor to collide with. Some settings for the floor:

    // Create a rigid body in the world
    Vector3 position(0, 20, 0);
    Vector3 floorPosition(0, -100, 0);
    Quaternion orientation = Quaternion::identity();
    Transform transform(position, orientation);
    Transform floorTransform(floorPosition, orientation);
    RigidBody* floor = world->createRigidBody(floorTransform);
    floor->setType(BodyType::STATIC);
    
    // Half extents of the box in the x, y and z directions
    const Vector3 floorSize (100000, 100, 100000);

    /* other code */

    BoxShape* floorShape = physicsCommon.createBoxShape(floorSize);
    Transform transform0 = Transform::identity();
    
    floor->addCollider(floorShape, transform0);

Teddy-van-Jerry avatar Dec 30 '22 06:12 Teddy-van-Jerry

Yeah I've tried creating a ground. I got it to work on the default convex cube method on the user manual page and a 3 sided equilateral triangle. Here is a snapshot of the cylinder in action. I turned down the cylinderSides count to 100 for testing, the camera is looking slightly down as the cylinder just passed through the floor. I had the debug lines enabled to see it. I also noticed there seems to be no mesh on the top and bottom ? Or maybe its just one big piece.

https://ibb.co/LS67jC6

I've had this problem before where some of my objects passed through, could it be the winding order?

patrikpatrik avatar Dec 30 '22 15:12 patrikpatrik

I am not quite sure where the problem lies since in my code snippet vertices of each face are defined clockwise so as to satisfy the requirement.

About the mesh line on the top and bottom, I am not quite sure why. But according to the code itself, there are $N+2$ faces added to the cylinder, where $N$ is the number of cylinderSides.

Sorry I am not familiar with the graphic interface provided by the library (including how debug lines work). Probably the logic there is a bit different from doing the simulation from the terminal.

P.S. I am just about to sleep, so there can be delay of response. :-)

Teddy-van-Jerry avatar Dec 30 '22 15:12 Teddy-van-Jerry

Clockwise? But in the user manual @ 11.1.4 Convex Mesh Shape it states: When you specify the vertices for each face of your convex mesh, be careful with their order. The vertices of a face must be specified in counter clockwise order as seen from the outside of your convex mesh.

patrikpatrik avatar Dec 30 '22 16:12 patrikpatrik

Oops, sorry, I mean counter clockwise.

I reckon the idea behind the code snippet is relatively clear. Each face is built first, and then faces are added to the mesh according to the sequence of $N$ sides, top side and bottom side.

Teddy-van-Jerry avatar Dec 31 '22 02:12 Teddy-van-Jerry

Proper non-hacky cylinder support would be appreciated

cykoder avatar Jan 15 '23 05:01 cykoder