Remove box, cylinder and ellipsoid composite types.

Also, fix a bug with Flex textures that was causing an incorrect allocation of the textures in mjModel. Fixes #2013.

PiperOrigin-RevId: 692510858
Change-Id: If781716216974e085244da27bc3aa57d91c3458c
This commit is contained in:
Alessio Quaglino
2024-11-02 11:13:16 -07:00
committed by Copybara-Service
parent ebe60b9ad5
commit 831d9881d3
12 changed files with 54 additions and 547 deletions
+4 -3
View File
@@ -3566,9 +3566,10 @@ saving the XML:
:at:`texcoord`: :at-val:`real(2*npoint), optional`
Texture coordinates of each point, passed through to the automatically-generated flex. Note that flexcomp does not
generate texture coordinates automatically, except for 2D grids. For all other types, the user can specify explicit
texture coordinates here, even if the points themselves were generated automatically. This requires understanding of
the layout of the automatically-generated points and how they correspond to the texture referenced by the material.
generate texture coordinates automatically, except for 2D grids, box, cylinder and ellipsoid. For all other types,
the user can specify explicit texture coordinates here, even if the points themselves were generated automatically.
This requires understanding of the layout of the automatically-generated points and how they correspond to the
texture referenced by the material.
.. _body-flexcomp-mass:
+3
View File
@@ -17,6 +17,8 @@ General
- Sorting now uses a faster, native sort function (fixes :github:issue:`1638`).
- The PBR texture layers introduced in 3.2.1 were refactored from seperate sub-elements to a single
:ref:`layer<material-layer>` sub-element.
- The composite types box, cylinder, and sphere have been removed. Users should instead use the equivalent types
available in :ref:`flexcomp<body-flexcomp>`.
MJX
^^^
@@ -33,6 +35,7 @@ Bug fixes
several places leading to incorrect computations of constraint inertia, readings of affected force/torque sensors and
runtime enabling/disabling of such constraints.
- Fixed a bug in slider-crank :ref:`transmission<geTransmission>`. The bug was introduced in 3.0.0.
- Fixed a bug in flex texture coordinates that prevented the correct allocation of textures in mjModel.
Documentation
+3 -54
View File
@@ -1280,62 +1280,11 @@ scenario (e.g. a stretched rubber band).
The cloth is deprecated. It is recommended to use 2D flex :ref:`deformable objects <CDeformable>` for simulating thin
elastic structures.
**Box**.
**Box, cylinder and ellipsoid**.
|image14| |image15|
.. code-block:: xml
<body pos="0 0 1">
<freejoint/>
<composite type="box" count="7 7 7" spacing="0.04">
<skin texcoord="true" material="matsponge" rgba=".7 .7 .7 1"/>
<geom type="capsule" size=".015 0.05" rgba=".8 .2 .1 1"/>
</composite>
</body>
The box type, as well as the cylinder and ellipsoid types below, are used to model soft 3D objects. The element bodies
form a grid along the outer shell, thus the number of element bodies scales with the square of the linear dimension.
This is much more efficient than simulating a 3D grid. The parent body within which :el:`composite` appears is at the
center of the soft object. All element bodies are children of the parent. Each element body has a single sliding joint
pointing away from the parent. These joints allow the surface of the soft object to compress and expand at any point.
The joints are equality-constrained to their initial position, so as to maintain the shape. In addition each joint is
equality-constrained to its neighbor joints, so that when the soft objects deforms, the deformation is smooth.
Finally, there is a tendon equality constraint specifying that the sum of all joints should remain constant. This
attempts to preserve the volume of the soft object approximately. If the object is squeezed from all sides it will
compress and the volume will decrease, but otherwise some element bodies will stick out to compensate for squeezing
elsewhere. The plot on the left shows this effect; we are using the capsule probe to compress one corner, and the
opposite sides of the cube expand a bit, while the deformations remain smooth. The :at:`count` attribute determines
the number of element bodies in each dimension, so if the counts are different the resulting object will be a
rectangular box and not a cube. The geoms attached to the element bodies can be spheres, capsules or ellipsoids.
Spheres are faster for collision detection, but they result in a thin shell, allowing other bodies to "get under the
skin" of the soft object. When capsules or ellipsoids are used, they are automatically oriented so that the long axis
points to the outside, thus creating a thicker shell which is harder to penetrate.
**Cylinder and ellipsoid**.
|image16| |image17|
.. code-block:: xml
<body pos="0 0 1">
<freejoint/>
<composite type="ellipsoid" count="5 7 9" spacing="0.05">
<skin texcoord="true" material="matsponge" rgba=".7 .7 .7 1"/>
<geom type="capsule" size=".015 0.05" rgba=".8 .2 .1 1"/>
</composite>
</body>
Cylinders and ellipsoids are created in the same way as boxes. The only difference is that the reference positions of
the element bodies (relative to the parent) are projected on a cylinder or ellipsoid, with size implied by the
:at:`count` attribute. The automatic skin generator is aware of the smooth surfaces, and adjusts the skin normals
accordingly. In the plots we have used the capsule probe to press on each body, then paused the simulation and moved the
probe away (which is possible because the probe is a mocap body which can move independent of the physics). In this way
we can see the indentation made by the probe, and the resulting deformation in the rest of the body. By changing the
solref and solimp attributes of the equality constraints that hold the soft object together, one can adjust the behavior
of the system making it softer or harder, damped or springy, etc. Note that box, cylinder and ellipsoid objects do not
involve long kinematic chains, and can be simulated at large timesteps -- similar to particle and grid, and unlike rope
and cloth.
The box type, as well as the cylinder and ellipsoid types, are now deprecated in favor of 3D flex :ref:`deformable
objects <CDeformable>``. element.
.. _CDeformable:
+7 -10
View File
@@ -14,10 +14,6 @@
-->
<mujoco model="Soft box">
<!-- Degree of Freedom: 224
Actuators: 0
Equality constraints: 651
-->
<include file="scene.xml"/>
<option solver="CG" tolerance="1e-6"/>
@@ -25,13 +21,14 @@
<size memory="30M"/>
<worldbody>
<body pos="0 0 1">
<body pos="0 0 1" name="body">
<freejoint/>
<composite type="box" count="7 7 7" spacing="0.04">
<skin texcoord="true" material="matsponge" rgba=".7 .7 .7 1"/>
<geom type="capsule" size=".015 0.05" rgba=".8 .2 .1 1"/>
<joint kind="main" solreffix="0.03 1" solimpfix="0 .1 .01"/>
</composite>
<geom size=".1" contype="0" conaffinity="0" group="4"/>
<flexcomp name="softbox" type="box" count="7 7 7" spacing=".04 .04 .04"
radius="0.01" dim="3" material="matsponge">
<contact internal="false" selfcollide="none"/>
<edge equality="true"/>
</flexcomp>
</body>
</worldbody>
</mujoco>
-453
View File
@@ -192,25 +192,6 @@ void mjCComposite::SetDefault(void) {
case mjCOMPTYPE_CLOTH: // cloth
break;
case mjCOMPTYPE_BOX: // 3D
case mjCOMPTYPE_CYLINDER:
case mjCOMPTYPE_ELLIPSOID:
// no self-collisions
def[0].spec.geom->contype = 0;
// soft smoothing
AdjustSoft(solrefsmooth, solimpsmooth, 1);
// soft fix everywhere
for (int i=0; i<mjNCOMPKINDS; i++) {
AdjustSoft(def[i].spec.equality->solref, def[i].spec.equality->solimp, 1);
}
// hard main tendon fix
AdjustSoft(def[mjCOMPKIND_TENDON].spec.equality->solref,
def[mjCOMPKIND_TENDON].spec.equality->solimp, 0);
break;
default:
// SHOULD NOT OCCUR
mju_error("Invalid composite type: %d", type);
@@ -347,11 +328,6 @@ bool mjCComposite::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz)
"\"shell\" instead.",
error_sz);
case mjCOMPTYPE_BOX:
case mjCOMPTYPE_CYLINDER:
case mjCOMPTYPE_ELLIPSOID:
return MakeBox(model, body, error, error_sz);
default:
return comperr(error, "Unknown shape in composite", error_sz);
}
@@ -919,166 +895,6 @@ mjsBody* mjCComposite::AddRopeBody(mjCModel* model, mjsBody* body, int ix, int i
// project from box to other shape
void mjCComposite::BoxProject(double* pos) {
// determine sizes
double size[3] = {
0.5*spacing*(count[0]-1),
0.5*spacing*(count[1]-1),
0.5*spacing*(count[2]-1)
};
// box
if (type==mjCOMPTYPE_BOX) {
pos[0] *= size[0];
pos[1] *= size[1];
pos[2] *= size[2];
}
// cylinder
else if (type==mjCOMPTYPE_CYLINDER) {
double L0 = std::max(std::abs(pos[0]), std::abs(pos[1]));
mjuu_normvec(pos, 2);
pos[0] *= size[0]*L0;
pos[1] *= size[1]*L0;
pos[2] *= size[2];
}
// ellipsoid
else if (type==mjCOMPTYPE_ELLIPSOID) {
mjuu_normvec(pos, 3);
pos[0] *= size[0];
pos[1] *= size[1];
pos[2] *= size[2];
}
}
// make 3d box, ellipsoid or cylinder
bool mjCComposite::MakeBox(mjCModel* model, mjsBody* body, char* error, int error_sz) {
char txt[100];
// check dim
if (dim!=3) {
return comperr(error, "Box and ellipsoid must be three-dimensional", error_sz);
}
// center geom: two times bigger
mjsGeom* geom = mjs_addGeom(body, &def[0].spec);
mjs_setDefault(geom->element, mjs_getDefault(body->element));
geom->type = mjGEOM_SPHERE;
mju::sprintf_arr(txt, "%sGcenter", prefix.c_str());
mjs_setString(geom->name, txt);
mjuu_setvec(geom->pos, 0, 0, 0);
geom->size[0] *= 2;
geom->size[1] = 0;
geom->size[2] = 0;
// fixed tendon for all joints
mjCTendon* ten = model->AddTendon(def + mjCOMPKIND_TENDON);
ten->classname = model->Default()->name;
mju::sprintf_arr(txt, "%sT", prefix.c_str());
ten->name = txt;
// create bodies, geoms and joints: outside shell only
for (int ix=0; ix<count[0]; ix++) {
for (int iy=0; iy<count[1]; iy++) {
for (int iz=0; iz<count[2]; iz++) {
if (ix==0 || ix==count[0]-1 ||
iy==0 || iy==count[1]-1 ||
iz==0 || iz==count[2]-1) {
// create body
mjsBody* b = mjs_addBody(body, NULL);
mju::sprintf_arr(txt, "%sB%d_%d_%d", prefix.c_str(), ix, iy, iz);
mjs_setString(b->name, txt);
// set body position (+/- 1)
b->pos[0] = 2.0*ix/(count[0]-1) - 1;
b->pos[1] = 2.0*iy/(count[1]-1) - 1;
b->pos[2] = 2.0*iz/(count[2]-1) - 1;
// reshape
BoxProject(b->pos);
// reorient body
b->alt.type = mjORIENTATION_ZAXIS;
mjuu_copyvec(b->alt.zaxis, b->pos, 3);
mjuu_normvec(b->alt.zaxis, 3);
// add geom
mjsGeom* g = mjs_addGeom(b, &def[0].spec);
mjs_setDefault(g->element, mjs_getDefault(body->element));
mju::sprintf_arr(txt, "%sG%d_%d_%d", prefix.c_str(), ix, iy, iz);
mjs_setString(g->name, txt);
// offset inwards, enforce sphere or capsule
if (g->type==mjGEOM_CAPSULE) {
g->pos[2] = -(g->size[0] + g->size[1]);
} else {
g->type = mjGEOM_SPHERE;
g->pos[2] = -g->size[0];
}
// add slider joint
mjsJoint* jnt = mjs_addJoint(b, &defjoint[mjCOMPKIND_JOINT][0].spec);
mjs_setDefault(jnt->element, mjs_getDefault(body->element));
mju::sprintf_arr(txt, "%sJ%d_%d_%d", prefix.c_str(), ix, iy, iz);
mjs_setString(jnt->name, txt);
jnt->type = mjJNT_SLIDE;
mjuu_setvec(jnt->pos, 0, 0, 0);
mjuu_setvec(jnt->axis, 0, 0, 1);
// add fix constraint
mjsEquality* eq = mjs_addEquality(&model->spec, &def[mjCOMPKIND_JOINT].spec);
mjs_setDefault(eq->element, &model->Default()->spec);
eq->type = mjEQ_JOINT;
mjs_setString(eq->name1, mjs_getString(jnt->name));
// add joint to tendon
ten->WrapJoint(std::string(mjs_getString(jnt->name)), 1);
// add neighbor constraints
for (int i=0; i<3; i++) {
int ix1 = mjMIN(ix+(i==0), count[0]-1);
int iy1 = mjMIN(iy+(i==1), count[1]-1);
int iz1 = mjMIN(iz+(i==2), count[2]-1);
if ((ix1==0 || ix1==count[0]-1 ||
iy1==0 || iy1==count[1]-1 ||
iz1==0 || iz1==count[2]-1) &&
(ix!=ix1 || iy!=iy1 || iz!=iz1)) {
char txt2[200];
mju::sprintf_arr(txt2,
"%sJ%d_%d_%d", prefix.c_str(), ix1, iy1, iz1);
mjsEquality* eqn = mjs_addEquality(&model->spec, 0);
mju_copy(eqn->solref, solrefsmooth, mjNREF);
mju_copy(eqn->solimp, solimpsmooth, mjNIMP);
eqn->type = mjEQ_JOINT;
mjs_setString(eqn->name1, txt);
mjs_setString(eqn->name2, txt2);
}
}
}
}
}
}
// finalize fixed tendon
mjsEquality* eqt = mjs_addEquality(&model->spec, &def[mjCOMPKIND_TENDON].spec);
mjs_setDefault(eqt->element, &model->Default()->spec);
eqt->type = mjEQ_TENDON;
mjs_setString(eqt->name1, ten->name.c_str());
// skin
if (skin) {
MakeSkin3(model);
}
return true;
}
// add shear tendons to 2D
void mjCComposite::MakeShear(mjCModel* model) {
char txt[100], txt1[100], txt2[100];
@@ -1838,272 +1654,3 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) {
mju_free(D);
}
// add skin to 3D
void mjCComposite::MakeSkin3(mjCModel* model) {
int vcnt = 0;
std::map<std::string, int> vmap;
char txt[100], cnt0[10], cnt1[10], cnt2[10];
std::string fmt;
// string counts
mju::sprintf_arr(cnt0, "%d", count[0]-1);
mju::sprintf_arr(cnt1, "%d", count[1]-1);
mju::sprintf_arr(cnt2, "%d", count[2]-1);
// add skin, set name and material
mjsSkin* skin = mjs_addSkin(&model->spec);
mju::sprintf_arr(txt, "%sSkin", prefix.c_str());
mjs_setString(skin->name, txt);
mjs_setString(skin->material, skinmaterial.c_str());
mjuu_copyvec(skin->rgba, skinrgba, 4);
skin->inflate = skininflate;
skin->group = skingroup;
// box
if (type==mjCOMPTYPE_BOX || type==mjCOMPTYPE_PARTICLE) {
// z-faces
MakeSkin3Box(skin, count[0], count[1], 1, vcnt, "%sB%d_%d_0");
fmt = "%sB%d_%d_" + std::string(cnt2);
MakeSkin3Box(skin, count[0], count[1], 0, vcnt, fmt.c_str());
// y-faces
MakeSkin3Box(skin, count[0], count[2], 0, vcnt, "%sB%d_0_%d");
fmt = "%sB%d_" + std::string(cnt1) + "_%d";
MakeSkin3Box(skin, count[0], count[2], 1, vcnt, fmt.c_str());
// x-faces
MakeSkin3Box(skin, count[1], count[2], 1, vcnt, "%sB0_%d_%d");
fmt = "%sB" + std::string(cnt0) + "_%d_%d";
MakeSkin3Box(skin, count[1], count[2], 0, vcnt, fmt.c_str());
}
// cylinder
else if (type==mjCOMPTYPE_CYLINDER) {
// generate vertices in map
for (int ix=0; ix<count[0]; ix++) {
for (int iy=0; iy<count[1]; iy++) {
for (int iz=0; iz<count[2]; iz++) {
bool xedge = (ix==0 || ix==count[0]-1);
bool yedge = (iy==0 || iy==count[1]-1);
if (xedge || yedge) {
// body name
mju::sprintf_arr(txt, "%sB%d_%d_%d", prefix.c_str(), ix, iy, iz);
// add vertex
vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
// texture coordinate
if (skintexcoord) {
float X = 0, Y = 0;
if (xedge) {
X = iy/(float)(count[1]-1);
Y = iz/(float)(count[2]-1);
} else {
X = ix/(float)(count[0]-1);
Y = iz/(float)(count[2]-1);
}
texcoord.push_back(X);
texcoord.push_back(Y);
}
// save vertex id in map
vmap[txt] = vcnt;
vcnt++;
}
}
}
}
// y-faces
MakeSkin3Smooth(skin, count[0], count[2], 0, vmap, "%sB%d_0_%d");
fmt = "%sB%d_" + std::string(cnt1) + "_%d";
MakeSkin3Smooth(skin, count[0], count[2], 1, vmap, fmt.c_str());
// x-faces
MakeSkin3Smooth(skin, count[1], count[2], 1, vmap, "%sB0_%d_%d");
fmt = "%sB" + std::string(cnt0) + "_%d_%d";
MakeSkin3Smooth(skin, count[1], count[2], 0, vmap, fmt.c_str());
// z-faces, boxy-type
MakeSkin3Box(skin, count[0], count[1], 1, vcnt, "%sB%d_%d_0");
fmt = "%sB%d_%d_" + std::string(cnt2);
MakeSkin3Box(skin, count[0], count[1], 0, vcnt, fmt.c_str());
}
// smooth
else {
// generate vertices in map
for (int ix=0; ix<count[0]; ix++) {
for (int iy=0; iy<count[1]; iy++) {
for (int iz=0; iz<count[2]; iz++) {
bool xedge = (ix==0 || ix==count[0]-1);
bool yedge = (iy==0 || iy==count[1]-1);
bool zedge = (iz==0 || iz==count[2]-1);
if (xedge || yedge || zedge) {
// body name
mju::sprintf_arr(txt, "%sB%d_%d_%d", prefix.c_str(), ix, iy, iz);
// add vertex
vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
// texture coordinate
if (skintexcoord) {
float X = 0, Y = 0;
if (xedge) {
X = iy/(float)(count[1]-1);
Y = iz/(float)(count[2]-1);
} else if (yedge) {
X = ix/(float)(count[0]-1);
Y = iz/(float)(count[2]-1);
} else {
X = ix/(float)(count[0]-1);
Y = iy/(float)(count[1]-1);
}
texcoord.push_back(X);
texcoord.push_back(Y);
}
// save vertex id in map
vmap[txt] = vcnt;
vcnt++;
}
}
}
}
// z-faces
MakeSkin3Smooth(skin, count[0], count[1], 1, vmap, "%sB%d_%d_0");
fmt = "%sB%d_%d_" + std::string(cnt2);
MakeSkin3Smooth(skin, count[0], count[1], 0, vmap, fmt.c_str());
// y-faces
MakeSkin3Smooth(skin, count[0], count[2], 0, vmap, "%sB%d_0_%d");
fmt = "%sB%d_" + std::string(cnt1) + "_%d";
MakeSkin3Smooth(skin, count[0], count[2], 1, vmap, fmt.c_str());
// x-faces
MakeSkin3Smooth(skin, count[1], count[2], 1, vmap, "%sB0_%d_%d");
fmt = "%sB" + std::string(cnt0) + "_%d_%d";
MakeSkin3Smooth(skin, count[1], count[2], 0, vmap, fmt.c_str());
}
CopyIntoSkin(skin);
}
// make one face of 3D skin, box
void mjCComposite::MakeSkin3Box(mjsSkin* skin, int c0, int c1, int side,
int& vcnt, const char* format) {
char txt[100];
// loop over bodies/vertices of specified face
for (int i0=0; i0<c0; i0++) {
for (int i1=0; i1<c1; i1++) {
// vertex
vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
// texture coordinate
if (skintexcoord) {
texcoord.push_back(i0/(float)(c0-1));
texcoord.push_back(i1/(float)(c1-1));
}
// face
if (i0<c0-1 && i1<c1-1) {
face.push_back(vcnt + i0*c1+i1);
face.push_back(vcnt + (i0+1)*c1+i1+(side==1));
face.push_back(vcnt + (i0+1)*c1+i1+(side==0));
face.push_back(vcnt + i0*c1+i1);
face.push_back(vcnt + (i0+(side==0))*c1+i1+1);
face.push_back(vcnt + (i0+(side==1))*c1+i1+1);
}
// body name
mju::sprintf_arr(txt, format, prefix.c_str(), i0, i1);
// bind pose: origin
mjs_appendString(skin->bodyname, txt);
bindpos.push_back(0);
bindpos.push_back(0);
bindpos.push_back(0);
bindquat.push_back(1);
bindquat.push_back(0);
bindquat.push_back(0);
bindquat.push_back(0);
// vertid and vertweight
vertid.push_back({vcnt + i0*c1+i1});
vertweight.push_back({1});
}
}
// update vertex count
vcnt += c0*c1;
}
// make one face of 3D skin, smooth
void mjCComposite::MakeSkin3Smooth(mjsSkin* skin, int c0, int c1, int side,
const std::map<std::string, int>& vmap,
const char* format) {
char txt00[100], txt01[100], txt10[100], txt11[100];
// loop over bodies/vertices of specified face
for (int i0=0; i0<c0; i0++) {
for (int i1=0; i1<c1; i1++) {
// body names
mju::sprintf_arr(txt00, format, prefix.c_str(), i0, i1);
mju::sprintf_arr(txt01, format, prefix.c_str(), i0, i1+1);
mju::sprintf_arr(txt10, format, prefix.c_str(), i0+1, i1);
mju::sprintf_arr(txt11, format, prefix.c_str(), i0+1, i1+1);
// face
if (i0<c0-1 && i1<c1-1) {
if (side==0) {
face.push_back(vmap.find(txt00)->second);
face.push_back(vmap.find(txt10)->second);
face.push_back(vmap.find(txt11)->second);
face.push_back(vmap.find(txt00)->second);
face.push_back(vmap.find(txt11)->second);
face.push_back(vmap.find(txt01)->second);
} else {
face.push_back(vmap.find(txt00)->second);
face.push_back(vmap.find(txt01)->second);
face.push_back(vmap.find(txt11)->second);
face.push_back(vmap.find(txt00)->second);
face.push_back(vmap.find(txt11)->second);
face.push_back(vmap.find(txt10)->second);
}
}
// bind pose: origin
mjs_appendString(skin->bodyname, txt00);
bindpos.push_back(0);
bindpos.push_back(0);
bindpos.push_back(0);
bindquat.push_back(1);
bindquat.push_back(0);
bindquat.push_back(0);
bindquat.push_back(0);
// vertid and vertweight
vertid.push_back({vmap.find(txt00)->second});
vertweight.push_back({1});
}
}
}
-11
View File
@@ -31,9 +31,6 @@ typedef enum _mjtCompType {
mjCOMPTYPE_ROPE,
mjCOMPTYPE_LOOP,
mjCOMPTYPE_CLOTH,
mjCOMPTYPE_BOX,
mjCOMPTYPE_CYLINDER,
mjCOMPTYPE_ELLIPSOID,
mjNCOMPTYPES
} mjtCompType;
@@ -75,7 +72,6 @@ class mjCComposite {
bool MakeGrid(mjCModel* model, mjsBody* body, char* error, int error_sz);
bool MakeRope(mjCModel* model, mjsBody* body, char* error, int error_sz);
bool MakeCable(mjCModel* model, mjsBody* body, char* error, int error_sz);
bool MakeBox(mjCModel* model, mjsBody* body, char* error, int error_sz);
void MakeShear(mjCModel* model);
void MakeSkin2(mjCModel* model, mjtNum inflate);
@@ -85,13 +81,6 @@ class mjCComposite {
void MakeCableBones(mjCModel* model, mjsSkin* skin);
void MakeCableBonesSubgrid(mjCModel* model, mjsSkin* skin);
void MakeSkin3(mjCModel* model);
void MakeSkin3Box(mjsSkin* skin, int c0, int c1, int side, int& vcnt, const char* format);
void MakeSkin3Smooth(mjsSkin* skin, int c0, int c1, int side,
const std::map<std::string, int>& vmap, const char* format);
void BoxProject(double* pos);
// common properties
std::string prefix; // name prefix
mjtCompType type; // composite type
+25
View File
@@ -763,6 +763,7 @@ bool mjCFlexcomp::MakeSquare(char* error, int error_sz) {
// make 3d box, ellipsoid or cylinder
bool mjCFlexcomp::MakeBox(char* error, int error_sz) {
double pos[3];
bool needtex = texcoord.empty() && !std::string(mjs_getString(def.spec.flex->material)).empty();
// set 3D
def.spec.flex->dim = 3;
@@ -772,6 +773,12 @@ bool mjCFlexcomp::MakeBox(char* error, int error_sz) {
point.push_back(0);
point.push_back(0);
// add texture coordinates, if not specified explicitly
if (needtex) {
texcoord.push_back(0);
texcoord.push_back(0);
}
// iz=0/max
for (int iz=0; iz < count[2]; iz+=count[2]-1) {
for (int ix=0; ix < count[0]; ix++) {
@@ -782,6 +789,12 @@ bool mjCFlexcomp::MakeBox(char* error, int error_sz) {
point.push_back(pos[1]);
point.push_back(pos[2]);
// add texture coordinates, if not specified explicitly
if (needtex) {
texcoord.push_back(ix/(float)std::max(count[0]-1, 1));
texcoord.push_back(iy/(float)std::max(count[1]-1, 1));
}
// add elements
if (ix < count[0]-1 && iy < count[1]-1) {
element.push_back(0);
@@ -808,6 +821,12 @@ bool mjCFlexcomp::MakeBox(char* error, int error_sz) {
point.push_back(pos[0]);
point.push_back(pos[1]);
point.push_back(pos[2]);
// add texture coordinates
if (needtex) {
texcoord.push_back(ix/(float)std::max(count[0]-1, 1));
texcoord.push_back(iz/(float)std::max(count[2]-1, 1));
}
}
// add elements
@@ -836,6 +855,12 @@ bool mjCFlexcomp::MakeBox(char* error, int error_sz) {
point.push_back(pos[0]);
point.push_back(pos[1]);
point.push_back(pos[2]);
// add texture coordinates
if (needtex) {
texcoord.push_back(iy/(float)std::max(count[1]-1, 1));
texcoord.push_back(iz/(float)std::max(count[2]-1, 1));
}
}
// add elements
+1
View File
@@ -1613,6 +1613,7 @@ void mjCModel::SetSizes() {
nflexelemedge += flexes_[i]->nelem * mjCFlex::kNumEdges[flexes_[i]->dim - 1];
nflexshelldata += (int)flexes_[i]->shell.size();
nflexevpair += (int)flexes_[i]->evpair.size()/2;
nflextexcoord += (flexes_[i]->HasTexcoord() ? flexes_[i]->get_texcoord().size()/2 : 0);
}
// mesh counts
+1 -4
View File
@@ -742,10 +742,7 @@ const mjMap comp_map[mjNCOMPTYPES] = {
{"rope", mjCOMPTYPE_ROPE},
{"loop", mjCOMPTYPE_LOOP},
{"cable", mjCOMPTYPE_CABLE},
{"cloth", mjCOMPTYPE_CLOTH},
{"box", mjCOMPTYPE_BOX},
{"cylinder", mjCOMPTYPE_CYLINDER},
{"ellipsoid", mjCOMPTYPE_ELLIPSOID}
{"cloth", mjCOMPTYPE_CLOTH}
};
+4 -6
View File
@@ -27,17 +27,15 @@
<geom type="box" size=".5 .5 .1"/>
</body>
<body pos="1 -1 .6">
<freejoint/>
<composite prefix="B0" type="box" count="4 4 4" spacing=".2">
<composite prefix="B0" type="grid" count="4 4 1" spacing=".2">
<geom group="4" size=".1"/>
<skin rgba="1 1 0 1" group="2"/>
<skin rgba="1 1 0 1" group="2" inflate=".1"/>
</composite>
</body>
<body pos="-1 1 .6">
<freejoint/>
<composite prefix="B1" type="box" count="4 4 4" spacing=".2">
<composite prefix="B1" type="grid" count="4 4 1" spacing=".2">
<geom group="2" size=".1"/>
<skin rgba="0 1 1 1" group="4"/>
<skin rgba="0 1 1 1" group="4" inflate=".1"/>
</composite>
</body>
</worldbody>
+1 -1
View File
@@ -43,7 +43,7 @@ TEST_F(UserCompositeTest, MultipleJointsNotAllowedUnlessParticle) {
<worldbody>
<body>
<freejoint/>
<composite type="box" count="7 7 7" spacing="0.04">
<composite type="grid" count="7 7 1" spacing="0.04">
<joint kind="main" solreffix="0.03 1" solimpfix="0 .1 .01"/>
<joint kind="main" solreffix="0.03 1" solimpfix="0 .1 .01"/>
</composite>
+5 -5
View File
@@ -1681,13 +1681,13 @@ TEST_F(XMLReaderTest, ReadsSkinGroups) {
<mujoco>
<worldbody>
<body>
<composite prefix="B0" type="box" count="4 4 4" spacing=".2">
<composite prefix="B0" type="grid" count="4 4 1" spacing=".2">
<geom size=".1" group="2"/>
<skin group="4"/>
</composite>
</body>
<body>
<composite prefix="B1" type="box" count="4 4 4" spacing=".2">
<composite prefix="B1" type="grid" count="4 4 1" spacing=".2">
<geom size=".1" group="4"/>
<skin group="2"/>
</composite>
@@ -1698,8 +1698,8 @@ TEST_F(XMLReaderTest, ReadsSkinGroups) {
std::array<char, 1024> error;
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
ASSERT_THAT(model, NotNull());
int geomid1 = mj_name2id(model, mjOBJ_GEOM, "B0G0_0_0");
int geomid2 = mj_name2id(model, mjOBJ_GEOM, "B1G0_0_0");
int geomid1 = mj_name2id(model, mjOBJ_GEOM, "B0G0_0");
int geomid2 = mj_name2id(model, mjOBJ_GEOM, "B1G0_0");
EXPECT_THAT(model->geom_group[geomid1], 2);
EXPECT_THAT(model->skin_group[0], 4);
EXPECT_THAT(model->geom_group[geomid2], 4);
@@ -1712,7 +1712,7 @@ TEST_F(XMLReaderTest, InvalidSkinGroup) {
<mujoco>
<worldbody>
<body>
<composite prefix="B0" type="box" count="6 6 6" spacing=".2">
<composite prefix="B0" type="grid" count="6 6 1" spacing=".2">
<geom size=".1"/>
<skin group="6"/>
</composite>