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:
committed by
Copybara-Service
parent
ebe60b9ad5
commit
831d9881d3
@@ -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:
|
||||
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
|
||||
|
||||
Vendored
+4
-6
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user