Adds built-in superellipsoid mesh.
PiperOrigin-RevId: 791196831 Change-Id: I1d864f6e620870f016377a4d9e2e26d1a23fd77e
This commit is contained in:
committed by
Copybara-Service
parent
e74cee652f
commit
705ec6d7fb
@@ -1348,6 +1348,15 @@ The full list of processing steps applied by the compiler to each mesh is as fol
|
|||||||
**nvert**: integer >= 3: The number vertices in the polygon.
|
**nvert**: integer >= 3: The number vertices in the polygon.
|
||||||
|br| **radius**: real in [0, 1]: The radius of the top face.
|
|br| **radius**: real in [0, 1]: The radius of the top face.
|
||||||
|
|
||||||
|
:at-val:`supersphere` (resolution, e, n)
|
||||||
|
A generalization of a sphere, also known as a superellipsoid (we use "supersphere" since semiaxis rescaling is
|
||||||
|
performed by the :ref:`scale<asset-mesh-scale>` attribute). If the **n** and **e** parameters are both 1, the
|
||||||
|
shape is a sphere. See `here <https://en.wikipedia.org/wiki/Superellipsoid>`__ for the definition of superspheres.
|
||||||
|
|
||||||
|
**resolution** integer >= 4: The discretization of both major and minor radii.
|
||||||
|
|br| **e**: real >= 0: The "east-west" exponent.
|
||||||
|
|br| **n**: real >= 0: The "north-south" exponent.
|
||||||
|
|
||||||
:at-val:`supertorus` (resolution, radius, s, t)
|
:at-val:`supertorus` (resolution, radius, s, t)
|
||||||
A generalization of a torus with major radius of 1 and given minor radius. If the **s** and **t** parameters are
|
A generalization of a torus with major radius of 1 and given minor radius. If the **s** and **t** parameters are
|
||||||
both 1, the shape is a torus. See `here <https://en.wikipedia.org/wiki/Supertoroid>`__ for details regarding
|
both 1, the shape is a torus. See `here <https://en.wikipedia.org/wiki/Supertoroid>`__ for details regarding
|
||||||
|
|||||||
@@ -1789,6 +1789,7 @@ typedef enum mjtMeshBuiltin_ { // type of built-in procedural mesh
|
|||||||
mjMESH_BUILTIN_SPHERE, // sphere
|
mjMESH_BUILTIN_SPHERE, // sphere
|
||||||
mjMESH_BUILTIN_HEMISPHERE, // hemisphere
|
mjMESH_BUILTIN_HEMISPHERE, // hemisphere
|
||||||
mjMESH_BUILTIN_CONE, // cone
|
mjMESH_BUILTIN_CONE, // cone
|
||||||
|
mjMESH_BUILTIN_SUPERSPHERE, // supersphere
|
||||||
mjMESH_BUILTIN_SUPERTORUS, // supertorus
|
mjMESH_BUILTIN_SUPERTORUS, // supertorus
|
||||||
mjMESH_BUILTIN_WEDGE, // wedge
|
mjMESH_BUILTIN_WEDGE, // wedge
|
||||||
mjMESH_BUILTIN_PLATE, // plate
|
mjMESH_BUILTIN_PLATE, // plate
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ typedef enum mjtMeshBuiltin_ { // type of built-in procedural mesh
|
|||||||
mjMESH_BUILTIN_SPHERE, // sphere
|
mjMESH_BUILTIN_SPHERE, // sphere
|
||||||
mjMESH_BUILTIN_HEMISPHERE, // hemisphere
|
mjMESH_BUILTIN_HEMISPHERE, // hemisphere
|
||||||
mjMESH_BUILTIN_CONE, // cone
|
mjMESH_BUILTIN_CONE, // cone
|
||||||
|
mjMESH_BUILTIN_SUPERSPHERE, // supersphere
|
||||||
mjMESH_BUILTIN_SUPERTORUS, // supertorus
|
mjMESH_BUILTIN_SUPERTORUS, // supertorus
|
||||||
mjMESH_BUILTIN_WEDGE, // wedge
|
mjMESH_BUILTIN_WEDGE, // wedge
|
||||||
mjMESH_BUILTIN_PLATE, // plate
|
mjMESH_BUILTIN_PLATE, // plate
|
||||||
|
|||||||
@@ -801,9 +801,10 @@ ENUMS: Mapping[str, EnumDecl] = dict([
|
|||||||
('mjMESH_BUILTIN_SPHERE', 1),
|
('mjMESH_BUILTIN_SPHERE', 1),
|
||||||
('mjMESH_BUILTIN_HEMISPHERE', 2),
|
('mjMESH_BUILTIN_HEMISPHERE', 2),
|
||||||
('mjMESH_BUILTIN_CONE', 3),
|
('mjMESH_BUILTIN_CONE', 3),
|
||||||
('mjMESH_BUILTIN_SUPERTORUS', 4),
|
('mjMESH_BUILTIN_SUPERSPHERE', 4),
|
||||||
('mjMESH_BUILTIN_WEDGE', 5),
|
('mjMESH_BUILTIN_SUPERTORUS', 5),
|
||||||
('mjMESH_BUILTIN_PLATE', 6),
|
('mjMESH_BUILTIN_WEDGE', 6),
|
||||||
|
('mjMESH_BUILTIN_PLATE', 7),
|
||||||
]),
|
]),
|
||||||
)),
|
)),
|
||||||
('mjtBuiltin',
|
('mjtBuiltin',
|
||||||
|
|||||||
@@ -1041,6 +1041,15 @@ PYBIND11_MODULE(_specs, m) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
py::arg("nedge"), py::arg("radius"));
|
py::arg("nedge"), py::arg("radius"));
|
||||||
|
mjsMesh.def(
|
||||||
|
"make_supersphere",
|
||||||
|
[](raw::MjsMesh* self, int resolution, double e, double n) {
|
||||||
|
double params[3] = {static_cast<double>(resolution), e, n};
|
||||||
|
if (mjs_makeMesh(self, mjMESH_BUILTIN_SUPERSPHERE, params, 3)) {
|
||||||
|
throw pybind11::value_error(mjs_getError(mjs_getSpec(self->element)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
py::arg("resolution"), py::arg("e"), py::arg("n"));
|
||||||
mjsMesh.def(
|
mjsMesh.def(
|
||||||
"make_supertorus",
|
"make_supertorus",
|
||||||
[](raw::MjsMesh* self, int resolution, double radius, double s,
|
[](raw::MjsMesh* self, int resolution, double radius, double s,
|
||||||
|
|||||||
@@ -502,17 +502,21 @@ class SpecsTest(absltest.TestCase):
|
|||||||
mesh = spec.add_mesh(name='sphere')
|
mesh = spec.add_mesh(name='sphere')
|
||||||
mesh.make_sphere(subdivision=2)
|
mesh.make_sphere(subdivision=2)
|
||||||
|
|
||||||
mesh = spec.add_mesh(name='supertoroid')
|
mesh = spec.add_mesh(name='supertorus')
|
||||||
mesh.make_supertorus(resolution=10, radius=0.5, s=1, t=1)
|
mesh.make_supertorus(resolution=10, radius=0.5, s=1, t=1)
|
||||||
|
|
||||||
|
mesh = spec.add_mesh(name='supersphere')
|
||||||
|
mesh.make_supersphere(resolution=20, e=2, n=1)
|
||||||
|
|
||||||
model = spec.compile()
|
model = spec.compile()
|
||||||
self.assertEqual(model.nmesh, 6)
|
self.assertEqual(model.nmesh, 7)
|
||||||
self.assertEqual(model.mesh_vertnum[0], 25 * 25)
|
self.assertEqual(model.mesh_vertnum[0], 25 * 25)
|
||||||
self.assertEqual(model.mesh_vertnum[1], 10)
|
self.assertEqual(model.mesh_vertnum[1], 10)
|
||||||
self.assertEqual(model.mesh_vertnum[2], 7)
|
self.assertEqual(model.mesh_vertnum[2], 7)
|
||||||
self.assertEqual(model.mesh_vertnum[3], 2 * (4 + 1) * (4 + 2) + 2)
|
self.assertEqual(model.mesh_vertnum[3], 2 * (4 + 1) * (4 + 2) + 2)
|
||||||
self.assertEqual(model.mesh_vertnum[4], 2 + 10 * 4**2)
|
self.assertEqual(model.mesh_vertnum[4], 2 + 10 * 4**2)
|
||||||
self.assertEqual(model.mesh_vertnum[5], 100)
|
self.assertEqual(model.mesh_vertnum[5], 100)
|
||||||
|
self.assertEqual(model.mesh_vertnum[6], 20 * (20 -1) + 2)
|
||||||
|
|
||||||
def test_compile_errors_with_line_info(self):
|
def test_compile_errors_with_line_info(self):
|
||||||
spec = mujoco.MjSpec()
|
spec = mujoco.MjSpec()
|
||||||
|
|||||||
@@ -542,6 +542,30 @@ int mjs_makeMesh(mjsMesh* mesh, mjtMeshBuiltin builtin, double* params, int npar
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case mjMESH_BUILTIN_SUPERSPHERE: {
|
||||||
|
if (nparams != 3) {
|
||||||
|
m->SetError(mjCError(0, "Supersphere mesh type requires 3 parameters"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int res = static_cast<int>(params[0]);
|
||||||
|
if (res < 3) {
|
||||||
|
m->SetError(mjCError(0, "Supersphere resolution must be greater than 2"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
double e = params[1];
|
||||||
|
if (e < 0) {
|
||||||
|
m->SetError(mjCError(0, "Supersphere 'e' cannot be negative"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
double n = params[2];
|
||||||
|
if (n < 0) {
|
||||||
|
m->SetError(mjCError(0, "Supersphere 'n' cannot be negative"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
meshC->MakeSupersphere(res, e, n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
case mjMESH_BUILTIN_SUPERTORUS: {
|
case mjMESH_BUILTIN_SUPERTORUS: {
|
||||||
if (nparams != 4) {
|
if (nparams != 4) {
|
||||||
m->SetError(mjCError(0, "Supertorus mesh type requires 4 parameters"));
|
m->SetError(mjCError(0, "Supertorus mesh type requires 4 parameters"));
|
||||||
|
|||||||
@@ -2292,6 +2292,68 @@ void mjCMesh::MakeSphere(int subdiv, bool make_faces) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// make a mesh of a supersphere
|
||||||
|
void mjCMesh::MakeSupersphere(int res, double e, double n) {
|
||||||
|
// allocate vertices and faces
|
||||||
|
int nvert = (res - 1) * res + 2;
|
||||||
|
int nface = 2 * res * (res - 1);
|
||||||
|
std::vector<float> vert;
|
||||||
|
vert.reserve(3 * nvert);
|
||||||
|
std::vector<int> face;
|
||||||
|
face.reserve(3 * nface);
|
||||||
|
|
||||||
|
// south pole
|
||||||
|
vert.insert(vert.end(), {0.0f, 0.0f, -1.0f});
|
||||||
|
|
||||||
|
// rings
|
||||||
|
for (int i = 1; i < res; i++) {
|
||||||
|
double v = -mjPI/2 + i * mjPI / res;
|
||||||
|
for (int j = 0; j < res; j++) {
|
||||||
|
double u = -mjPI + j * 2 * mjPI / res;
|
||||||
|
vert.push_back(aux_c(v, n) * aux_c(u, e));
|
||||||
|
vert.push_back(aux_c(v, n) * aux_s(u, e));
|
||||||
|
vert.push_back(aux_s(v, n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// north pole
|
||||||
|
vert.insert(vert.end(), {0.0f, 0.0f, 1.0f});
|
||||||
|
|
||||||
|
// south pole faces
|
||||||
|
for (int j = 0; j < res; j++) {
|
||||||
|
int v2 = 1 + j;
|
||||||
|
int v3 = 1 + (j + 1) % res;
|
||||||
|
face.insert(face.end(), {0, v3, v2});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ring faces
|
||||||
|
for (int i = 0; i < res - 2; i++) {
|
||||||
|
for (int j = 0; j < res; j++) {
|
||||||
|
int v1 = 1 + i * res + j;
|
||||||
|
int v2 = 1 + i * res + (j + 1) % res;
|
||||||
|
int v4 = 1 + (i + 1) * res + j;
|
||||||
|
int v3 = 1 + (i + 1) * res + (j + 1) % res;
|
||||||
|
face.insert(face.end(), {v1, v2, v4});
|
||||||
|
face.insert(face.end(), {v2, v3, v4});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// north pole faces
|
||||||
|
int north_pole_idx = nvert - 1;
|
||||||
|
int last_ring_start_idx = 1 + (res - 2) * res;
|
||||||
|
for (int j = 0; j < res; j++) {
|
||||||
|
int v1 = last_ring_start_idx + j;
|
||||||
|
int v2 = last_ring_start_idx + (j + 1) % res;
|
||||||
|
face.insert(face.end(), {v1, v2, north_pole_idx});
|
||||||
|
}
|
||||||
|
|
||||||
|
// save vertices and faces
|
||||||
|
mjs_setFloat(spec.uservert, vert.data(), vert.size());
|
||||||
|
mjs_setInt(spec.userface, face.data(), face.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// make a mesh of a torus (subsumed by supertorus, kept for reference only)
|
// make a mesh of a torus (subsumed by supertorus, kept for reference only)
|
||||||
void mjCMesh::MakeTorus(int res, double radius) {
|
void mjCMesh::MakeTorus(int res, double radius) {
|
||||||
// allocate vertices and faces
|
// allocate vertices and faces
|
||||||
|
|||||||
@@ -1055,6 +1055,7 @@ class mjCMesh: public mjCMesh_, private mjsMesh {
|
|||||||
void MakeSphere(int subdiv, bool make_faces);
|
void MakeSphere(int subdiv, bool make_faces);
|
||||||
void MakeTorus(int res, double radius);
|
void MakeTorus(int res, double radius);
|
||||||
void MakeSupertorus(int res, double radius, double s, double t);
|
void MakeSupertorus(int res, double radius, double s, double t);
|
||||||
|
void MakeSupersphere(int res, double e, double n);
|
||||||
void MakeWedge(int resolution[2], double fov[2], double gamma);
|
void MakeWedge(int resolution[2], double fov[2], double gamma);
|
||||||
void MakeRect(int resolution[2]);
|
void MakeRect(int resolution[2]);
|
||||||
void MakeCone(int nedge, double radius);
|
void MakeCone(int nedge, double radius);
|
||||||
|
|||||||
@@ -827,13 +827,14 @@ const mjMap meshinertia_map[4] = {
|
|||||||
|
|
||||||
|
|
||||||
// mesh builtin type
|
// mesh builtin type
|
||||||
const int meshbuiltin_sz = 7;
|
const int meshbuiltin_sz = 8;
|
||||||
const mjMap meshbuiltin_map[meshbuiltin_sz] = {
|
const mjMap meshbuiltin_map[meshbuiltin_sz] = {
|
||||||
{"none", mjMESH_BUILTIN_NONE},
|
{"none", mjMESH_BUILTIN_NONE},
|
||||||
{"sphere", mjMESH_BUILTIN_SPHERE},
|
{"sphere", mjMESH_BUILTIN_SPHERE},
|
||||||
{"hemisphere", mjMESH_BUILTIN_HEMISPHERE},
|
{"hemisphere", mjMESH_BUILTIN_HEMISPHERE},
|
||||||
{"cone", mjMESH_BUILTIN_CONE},
|
{"cone", mjMESH_BUILTIN_CONE},
|
||||||
{"supertorus", mjMESH_BUILTIN_SUPERTORUS},
|
{"supertorus", mjMESH_BUILTIN_SUPERTORUS},
|
||||||
|
{"supersphere", mjMESH_BUILTIN_SUPERSPHERE},
|
||||||
{"wedge", mjMESH_BUILTIN_WEDGE},
|
{"wedge", mjMESH_BUILTIN_WEDGE},
|
||||||
{"plate", mjMESH_BUILTIN_PLATE}
|
{"plate", mjMESH_BUILTIN_PLATE}
|
||||||
};
|
};
|
||||||
|
|||||||
Vendored
+2
@@ -2,6 +2,7 @@
|
|||||||
<asset>
|
<asset>
|
||||||
<mesh name="sphere" builtin="sphere" params="2" scale=".8 .8 .8"/>
|
<mesh name="sphere" builtin="sphere" params="2" scale=".8 .8 .8"/>
|
||||||
<mesh name="hemisphere" builtin="hemisphere" params="4" scale=".8 .8 .8"/>
|
<mesh name="hemisphere" builtin="hemisphere" params="4" scale=".8 .8 .8"/>
|
||||||
|
<mesh name="supersphere" builtin="supersphere" params="50 2 1" scale=".8 .8 .8"/>
|
||||||
<mesh name="toroid" builtin="supertorus" params="50 .5 .42 1.42" scale=".8 .8 .8"/>
|
<mesh name="toroid" builtin="supertorus" params="50 .5 .42 1.42" scale=".8 .8 .8"/>
|
||||||
<mesh name="wedge" builtin="wedge" params="10 10 60 60 0"/>
|
<mesh name="wedge" builtin="wedge" params="10 10 60 60 0"/>
|
||||||
<mesh name="prism3" builtin="cone" params="3 1" scale=".3 .3 .3"/>
|
<mesh name="prism3" builtin="cone" params="3 1" scale=".3 .3 .3"/>
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
<light pos="0 0 10"/>
|
<light pos="0 0 10"/>
|
||||||
<geom mesh="sphere" type="mesh" pos="-3 0 0"/>
|
<geom mesh="sphere" type="mesh" pos="-3 0 0"/>
|
||||||
<geom mesh="hemisphere" type="mesh" pos="-1 0 0"/>
|
<geom mesh="hemisphere" type="mesh" pos="-1 0 0"/>
|
||||||
|
<geom mesh="supersphere" type="mesh" pos="2 0 2"/>
|
||||||
<geom mesh="toroid" type="mesh" pos="-1 0 2"/>
|
<geom mesh="toroid" type="mesh" pos="-1 0 2"/>
|
||||||
<geom mesh="wedge" type="mesh" euler="90 -90 0"/>
|
<geom mesh="wedge" type="mesh" euler="90 -90 0"/>
|
||||||
<geom mesh="prism5" type="mesh" pos="2 0 0" euler="90 0 0"/>
|
<geom mesh="prism5" type="mesh" pos="2 0 0" euler="90 0 0"/>
|
||||||
|
|||||||
@@ -502,9 +502,10 @@ public enum mjtMeshBuiltin : int{
|
|||||||
mjMESH_BUILTIN_SPHERE = 1,
|
mjMESH_BUILTIN_SPHERE = 1,
|
||||||
mjMESH_BUILTIN_HEMISPHERE = 2,
|
mjMESH_BUILTIN_HEMISPHERE = 2,
|
||||||
mjMESH_BUILTIN_CONE = 3,
|
mjMESH_BUILTIN_CONE = 3,
|
||||||
mjMESH_BUILTIN_SUPERTORUS = 4,
|
mjMESH_BUILTIN_SUPERSPHERE = 4,
|
||||||
mjMESH_BUILTIN_WEDGE = 5,
|
mjMESH_BUILTIN_SUPERTORUS = 5,
|
||||||
mjMESH_BUILTIN_PLATE = 6,
|
mjMESH_BUILTIN_WEDGE = 6,
|
||||||
|
mjMESH_BUILTIN_PLATE = 7,
|
||||||
}
|
}
|
||||||
public enum mjtBuiltin : int{
|
public enum mjtBuiltin : int{
|
||||||
mjBUILTIN_NONE = 0,
|
mjBUILTIN_NONE = 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user