Convex mesh creation and collisions
ZeunO8 opened this issue · comments
Here is my code for creating a convex mesh:
void Entity::createConvexMesh()
{
reactphysics3d::Transform transform = reactphysics3d::Transform::identity();
body = scene_p->physicsWorld->createRigidBody(transform);
vec3 *evertices = (vec3 *)(*this).operator()<Floating>(EntityQuanta::Vertex);
ivec3 *eindices = (ivec3 *)(*this).operator()<Floating>(EntityQuanta::Indice);
const int nbVertices = QuantaSize(EntityQuanta::Vertex) / 3;
const int nbTriangles = QuantaSize(EntityQuanta::Indice) / 3;
float vertices[nbVertices * 3];
for (Integer i = 0; i < nbVertices; i++)
{
vec3 &vertex = evertices[i];
vertices[(i * 3)] = vertex.x;
vertices[(i * 3) + 1] = vertex.y;
vertices[(i * 3) + 2] = vertex.z;
}
int indices[nbTriangles * 3];
for (Integer i = 0; i < nbTriangles; i++)
{
ivec3& indice = eindices[i];
indices[(i * 3)] = indice.x;
indices[(i * 3) + 1] = indice.y;
indices[(i * 3) + 2] = indice.z;
}
reactphysics3d::PolygonVertexArray::PolygonFace *polygonFaces = new reactphysics3d::PolygonVertexArray::PolygonFace[nbTriangles];
reactphysics3d::PolygonVertexArray::PolygonFace *face = polygonFaces;
for (int f = 0; f < nbTriangles; f++)
{
face->indexBase = f * 3;
face->nbVertices = 3;
face++;
}
reactphysics3d::PolygonVertexArray *polygonVertexArray = new reactphysics3d::PolygonVertexArray(nbVertices, vertices, 3 * sizeof(float),
indices, sizeof(int), nbTriangles, polygonFaces,
reactphysics3d::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE,
reactphysics3d::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE);
reactphysics3d::PolyhedronMesh *polyhedronMesh = scene_p->physicsCommon.createPolyhedronMesh(polygonVertexArray);
reactphysics3d::ConvexMeshShape *convexMeshShape = scene_p->physicsCommon.createConvexMeshShape(polyhedronMesh);
body->addCollider(convexMeshShape, transform);
return;
};
I added a Quad to my scene, which should have two faces (two triangles making up the Quad), and now I'm getting an assertion error:
122 if (2 + nbEdges - mPolygonVertexArray->getNbFaces() != mPolygonVertexArray->getNbVertices()) {
(gdb)
124 RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon,
(gdb) print nbEdges
$37 = 3
(gdb) u
127 assert(false);
(gdb)
Cojarexp: /home/saeun/Projects/coje/venjor/reactphysics3d/src/collision/PolyhedronMesh.cpp:127: bool reactphysics3d::PolyhedronMesh::createHalfEdgeStructure(): Assertion `false' failed.
NbFaces = 2,
NbVertices = 4.
What is going wrong here, what can I do to fix the assertion?
The assert here is because a quad is not a valid convex mesh. A convex mesh should be a closed shape that has an interior like a cube for instance. A plane (a quad) is therefore not a valid convex mesh.
Secondly, as described in the documentation here, when you create a convex mesh, you should really avoid coplanar faces. Note that you can have faces with more than three vertices in a convex mesh. Therefore, if you want to have a quad face in your convex mesh, do not use two triangles but directly create a quad face with four vertices. The collision detection will be more stable this way.
I hope this helps.
I extended the mesh so that it is 3d (box rather than plane) and after fiddling with the order of indices, got createPolyhedronMesh
working. Now I'm having the issue where my triangle shape (with depth) does not collide correctly with my box shape. I'm assuming this is because I used triangles for the faces of the triangle (on its sides) and box. So now to work on createConvexMesh
to create 4 vertice faces.
Turns out I was using the Transform twice in this code rather than Transform::identity() in the second use.
void Entity::createConvexMeshFromData(float *vertices, const int &nbVertices, int *indices, const int &nbFaces, reactphysics3d::PolygonVertexArray::PolygonFace *polygonFaces)
{
reactphysics3d::Transform transform = reactphysics3d::Transform(reactphysics3d::Vector3(position.x, position.y, position.z), reactphysics3d::Quaternion::identity());
body = scene_p->physicsWorld->createRigidBody(transform);
reactphysics3d::PolygonVertexArray *polygonVertexArray = new reactphysics3d::PolygonVertexArray(nbVertices, vertices, 3 * sizeof(float),
indices, sizeof(int), nbFaces, polygonFaces,
reactphysics3d::PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE,
reactphysics3d::PolygonVertexArray::IndexDataType::INDEX_INTEGER_TYPE);
reactphysics3d::PolyhedronMesh *polyhedronMesh = scene_p->physicsCommon.createPolyhedronMesh(polygonVertexArray);
reactphysics3d::ConvexMeshShape *convexMeshShape = scene_p->physicsCommon.createConvexMeshShape(polyhedronMesh);
body->addCollider(convexMeshShape, rp3d::Transform::identity()); // was using transform again here
return;
};
Now I'm getting a new assertion failure:
Cojarexp: /home/saeun/Projects/coje/venjor/reactphysics3d/src/collision/shapes/ConvexMeshShape.cpp:76: virtual reactphysics3d::Vector3 reactphysics3d::ConvexMeshShape::getLocalSupportPointWithoutMargin(const reactphysics3d::Vector3&) const: Assertion `maxDotProduct >= decimal(0.0)' failed.
maxDotProduct
was -4.83096852e-13
in the case with triangle colliding with box
This is as soon as one rigidbody touches another
Can you post the code you use to create your PolygonVertexArray for your triangular prism?
Triangle::Triangle(const vec2 &size, const vec3 &position)
{
(*this).position = position;
ivec3 *indices = (ivec3 *)(*this).operator()<uint32_t>(EntityQuanta::Indice, 8);
vec3 *vertices = (vec3 *)(*this).operator()<Floating>(EntityQuanta::Vertex, 6);
vec4 *colors = (vec4 *)(*this).operator()<Floating>(EntityQuanta::Color, 6);
indices[0] = {0, 2, 1};
indices[1] = {1, 2, 5};
indices[2] = {5, 4, 1};
indices[3] = {3, 4, 5};
indices[4] = {3, 1, 0};
indices[5] = {3, 4, 1};
indices[6] = {0, 3, 5};
indices[7] = {5, 2, 0};
vertices[0] = {-size.x / 2, -size.x / 2, size.y / 2};
vertices[1] = {0, size.x / 2, size.y / 2};
vertices[2] = {size.x / 2, -size.x / 2, size.y / 2};
vertices[3] = {-size.x / 2, -size.x / 2, -size.y / 2};
vertices[4] = {0, size.x / 2, -size.y / 2};
vertices[5] = {size.x / 2, -size.x / 2, -size.y / 2};
colors[0] = {1, 1, 1, 0.8f};
colors[1] = {0, 0, 1, 1};
colors[2] = {1, 1, 1, 0.8f};
colors[3] = {1, 1, 1, 0.8f};
colors[4] = {0, 0, 1, 1};
colors[5] = {1, 1, 1, 0.8f};
return;
};
/*
*/
void Triangle::createConvexMesh()
{
vec3 *evertices = (vec3 *)(*this).operator()<Floating>(EntityQuanta::Vertex);
const int nbVertices = QuantaSize(EntityQuanta::Vertex) / 3;
const int nbFaces = 5; // (2 front and back, 3 on sides)
float vertices[nbVertices * 3];
for (Integer i = 0; i < nbVertices; i++)
{
vec3 &vertex = evertices[i];
vertices[(i * 3)] = vertex.x;
vertices[(i * 3) + 1] = vertex.y;
vertices[(i * 3) + 2] = vertex.z;
}
int indices[(2 * 3) + (3 * 4)];
ivec3 &indice1 = (ivec3&)indices[0];
ivec3 &indice2 = (ivec3&)indices[1 * 3];
ivec4 &indice3 = (ivec4&)indices[2 * 3];
ivec4 &indice4 = (ivec4&)indices[(2 * 3) + (1 * 4)];
ivec4 &indice5 = (ivec4&)indices[(2 * 3) + (2 * 4)];
indice1 = {0, 1, 2};
indice2 = {5, 4, 3};
indice3 = {1, 0, 3, 4};
indice4 = {4, 5, 2, 1};
indice5 = {0, 2, 5, 3};
reactphysics3d::PolygonVertexArray::PolygonFace *polygonFaces = new reactphysics3d::PolygonVertexArray::PolygonFace[nbFaces];
polygonFaces[0].indexBase = 0;
polygonFaces[0].nbVertices = 3;
polygonFaces[1].indexBase = 1 * 3;
polygonFaces[1].nbVertices = 3;
polygonFaces[2].indexBase = 2 * 3;
polygonFaces[2].nbVertices = 4;
polygonFaces[3].indexBase = (2 * 3) + (1 * 4);
polygonFaces[3].nbVertices = 4;
polygonFaces[4].indexBase = (2 * 3) + (2 * 4);
polygonFaces[4].nbVertices = 4;
createConvexMeshFromData(vertices, nbVertices, indices, nbFaces, polygonFaces);
return;
};
Below is Quad creation code for reference
Quad::Quad(const vec3 &size, const vec3 &position)
{
(*this).position = position;
ivec3 *indices = (ivec3 *)(*this).operator()<uint32_t>(EntityQuanta::Indice, 12);
resize(size);
indices[0] = {0, 3, 1};
indices[1] = {2, 1, 3};
indices[2] = {0, 1, 4};
indices[3] = {1, 5, 4};
indices[4] = {7, 4, 5};
indices[5] = {5, 6, 7};
indices[6] = {7, 6, 2};
indices[7] = {2, 3, 7};
indices[8] = {2, 6, 5};
indices[9] = {5, 1, 2};
indices[10] = {4, 7, 3};
indices[11] = {4, 3, 0};
return;
};
/*
*/
const Boolean Quad::resize(const vec3 &_size)
{
size = _size;
vec3 *vertices = (vec3*)(*this).operator()<Floating>(EntityQuanta::Vertex, 8);
vertices[0] = {size.x / 2, size.y / 2, size.z / 2};
vertices[1] = {size.x / 2, -(size.y / 2), size.z / 2};
vertices[2] = {-(size.x / 2), -(size.y / 2), size.z / 2};
vertices[3] = {-(size.x / 2), size.y / 2, size.z / 2};
vertices[4] = {size.x / 2, size.y / 2, -size.z / 2};
vertices[5] = {size.x / 2, -(size.y / 2), -size.z / 2};
vertices[6] = {-(size.x / 2), -(size.y / 2), -size.z / 2};
vertices[7] = {-(size.x / 2), size.y / 2, -size.z / 2};
return true;
};
/*
*/
void Quad::createConvexMesh()
{
vec3 *evertices = (vec3 *)(*this).operator()<Floating>(EntityQuanta::Vertex);
const int nbVertices = QuantaSize(EntityQuanta::Vertex) / 3;
const int nbFaces = 6; // (2 front and back, 2 on sides, 2 on top and bottom)
float vertices[nbVertices * 3];
for (Integer i = 0; i < nbVertices; i++)
{
vec3 &vertex = evertices[i];
vertices[(i * 3)] = vertex.x;
vertices[(i * 3) + 1] = vertex.y;
vertices[(i * 3) + 2] = vertex.z;
}
int indices[(6 * 4)];
ivec4 &indice1 = (ivec4&)indices[0];
ivec4 &indice2 = (ivec4&)indices[1 * 4];
ivec4 &indice3 = (ivec4&)indices[2 * 4];
ivec4 &indice4 = (ivec4&)indices[3 * 4];
ivec4 &indice5 = (ivec4&)indices[4 * 4];
ivec4 &indice6 = (ivec4&)indices[5 * 4];
indice1 = {0, 1, 2, 3};
indice2 = {4, 5, 1, 0};
indice3 = {5, 4, 7, 6};
indice4 = {3, 2, 6, 7};
indice5 = {1, 5, 6, 2};
indice6 = {4, 0, 3, 7};
reactphysics3d::PolygonVertexArray::PolygonFace *polygonFaces = new reactphysics3d::PolygonVertexArray::PolygonFace[nbFaces];
polygonFaces[0].indexBase = 0;
polygonFaces[0].nbVertices = 4;
polygonFaces[1].indexBase = 1 * 4;
polygonFaces[1].nbVertices = 4;
polygonFaces[2].indexBase = 2 * 4;
polygonFaces[2].nbVertices = 4;
polygonFaces[3].indexBase = 3 * 4;
polygonFaces[3].nbVertices = 4;
polygonFaces[4].indexBase = 4 * 4;
polygonFaces[4].nbVertices = 4;
polygonFaces[5].indexBase = 5 * 4;
polygonFaces[5].nbVertices = 4;
createConvexMeshFromData(vertices, nbVertices, indices, nbFaces, polygonFaces);
};
I read in the usermanual:
Note that the vertex coordinates and indices array are not copied and therefore you need to make sure that they exist until the collision shape exists. This is also true for the all the PolygonFace, the PolygonVertexArray and the PolyhedronMesh objects.
Does this mean I need to store vertices
and indices
in my Entity
struct for the lifecycle of the object. Or is it just until I've called physicsCommon.createConvexMeshShape
No longer have the assertion error after persisting vertices
and indices
. However the bodies still don't collide
Does this mean I need to store
vertices
andindices
in myEntity
struct for the lifecycle of the object. Or is it just until I've calledphysicsCommon.createConvexMeshShape
Currently, yes you need to keep the vertices array, the indices array and the PolygonVertexArray around during the whole simulation (until you destroy the collision shape). This will change in the next release of the library.
However the bodies still don't collide
How are the bodies moving (it's not very clear in the GIF)? Using gravity?
Gravity is off
I'm applying a force like so:
case KEY_w:
case KEY_W:
{
triangle2_p->body->applyLocalForceAtCenterOfMass({ 0, 50, 0 });
break;
};
case KEY_a:
case KEY_A:
{
triangle2_p->body->applyLocalTorque({ 0, 0, 50 });
break;
};
case KEY_s:
case KEY_S:
{
triangle2_p->body->applyLocalForceAtCenterOfMass({ 0, -50, 0 });
break;
};
case KEY_d:
case KEY_D:
{
triangle2_p->body->applyLocalTorque({ 0, 0, -50 });
break;
};
I think it could be due to this:
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.
The issue with them not colliding was due to the indices not in ccw order.
Here is a GIF of my currently working collisions with gravity set to { 0, -1, 0 }. As you can see the collision isn't exact and the rendering looks off (they overlap by a fair amount at one point). What could be the issue here?
It's difficult to say what could be wrong here but if you want to check that the collision shapes for the physics are perfectly aligned with the rendered shapes, you can use the DebugRenderer of the library. It will allow you to render the collision shape in your simulation. This way, you can check that they match your rendered shapes.
I am creating a TrianglesDebugRenderer
Entity
like so:
struct TrianglesDebugRenderer : Entity
{
rp3d::DebugRenderer &debugRenderer;
TrianglesDebugRenderer(rp3d::DebugRenderer &debugRenderer);
void updateFromDebugRenderer();
void preEnsureBuffersAndCopyData() override;
void createMesh() override;
};
/*
*/
#include <coje/Entitys/TrianglesDebugRenderer.hpp>
/*
*/
TrianglesDebugRenderer::TrianglesDebugRenderer(rp3d::DebugRenderer &debugRenderer) : debugRenderer(debugRenderer){};
/*
*/
void TrianglesDebugRenderer::updateFromDebugRenderer()
{
const rp3d::Array<rp3d::DebugRenderer::DebugTriangle> &triangles = debugRenderer.getTriangles();
auto trianglesSize = triangles.size();
vec3 *evertices = (vec3 *)(*this).operator()<Floating>(Entity::Quanta::Vertex, trianglesSize * 3);
vec4 *ecolors = (vec4 *)(*this).operator()<Floating>(Entity::Quanta::Color, trianglesSize * 3);
ivec3 *eindices = (ivec3*)(*this).operator()<uint32_t>(Entity::Quanta::Indice, trianglesSize);
for (Integer index = 0; index < trianglesSize; index++)
{
auto &triangle = triangles[index];
auto &vertex1 = evertices[index * 3];
auto &vertex2 = evertices[(index * 3) + 1];
auto &vertex3 = evertices[(index * 3) + 2];
vertex1.x = triangle.point1.x;
vertex1.y = triangle.point1.y;
vertex1.z = triangle.point1.z;
vertex2.x = triangle.point2.x;
vertex2.y = triangle.point2.y;
vertex2.z = triangle.point2.z;
vertex3.x = triangle.point3.x;
vertex3.y = triangle.point3.y;
vertex3.z = triangle.point3.z;
auto &color1 = ecolors[index * 3];
auto &color2 = ecolors[(index * 3) + 1];
auto &color3 = ecolors[(index * 3) + 2];
color1.x = getColorComponent('R', triangle.color1) / 255.f;
color1.y = getColorComponent('G', triangle.color1) / 255.f;
color1.z = getColorComponent('B', triangle.color1) / 255.f;
color1.w = 1;
color2.x = getColorComponent('R', triangle.color2) / 255.f;
color2.y = getColorComponent('G', triangle.color2) / 255.f;
color2.z = getColorComponent('B', triangle.color2) / 255.f;
color2.w = 1;
color3.x = getColorComponent('R', triangle.color3) / 255.f;
color3.y = getColorComponent('G', triangle.color3) / 255.f;
color3.z = getColorComponent('B', triangle.color3) / 255.f;
color3.w = 1;
auto &indice = eindices[index];
indice.x = index * 3;
indice.y = (index * 3) + 1;
indice.z = (index * 3) + 2;
}
};
/*
*/
void TrianglesDebugRenderer::preEnsureBuffersAndCopyData()
{
updateFromDebugRenderer();
};
/*
*/
void TrianglesDebugRenderer::createMesh(){
};
/*
*/
After doing:
const reactphysics3d::Transform &transform = body->getTransform();
mat4 matrix;
transform.getOpenGLMatrix(&matrix[0][0]);
shader.setMat4("model", matrix);
The collisions don't overlap in my renderer.
Still unsure why the triangles aren't renderer correctly in my TrianglesDebugRenderer
Great. It seems to be much better. Can I close the issue?
You can, though I have another issue to open regarding memory alignment of your HeapAllocator
on Android
Would be nice knowing what is going on with the TrianglesDebugRenderer
. It's like the triangles use the indices (0,1,2) and (1,2,3) instead of (0,1,2) and (2,3,0).
Would be nice knowing what is going on with the
TrianglesDebugRenderer
. It's like the triangles use the indices (0,1,2) and (1,2,3) instead of (0,1,2) and (2,3,0).
What do you mean exactly? What code are you talking about exactly?