Remove grid from composite types.

Replaced it with flexcomp in the models.

PiperOrigin-RevId: 730070619
Change-Id: Icbc69e4c6784c6252743f689a1eafb6482d0c393
This commit is contained in:
Alessio Quaglino
2025-02-23 01:29:20 -08:00
committed by Copybara-Service
parent b90ff3f0b1
commit 0fcd20f0da
14 changed files with 191 additions and 568 deletions
+1 -36
View File
@@ -2982,7 +2982,7 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
.. _body-composite-type:
:at:`type`: :at-val:`[particle, grid, cable, rope, loop, cloth, box, cylinder, ellipsoid], required`
:at:`type`: :at-val:`[particle, cable], required`
This attribute determines the type of composite object. The remaining attributes and sub-elements are then
interpreted according to the type. Default settings are also adjusted depending on the type.
@@ -2993,13 +2993,6 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
and replace the default sphere with a custom geom. Note that the particle composite type is deprecated and might be
removed in a future version. Instead of particle, it is recommended to use :ref:`replicate`.
The **grid** type creates a 1D or 2D grid of bodies, each having a sphere geom, a sphere site, and 3 orthogonal
sliding joints by default. The :el:`pin` sub-element can be used to specify that some bodies should not have joints,
and instead should be pinned to the parent body. Unlike the particle type, here each two neighboring bodies are
connected with a spatial tendon whose length is equality-constrained to its initial value (the sites are needed to
define the tendons). The "main" tendons are parallel to the axes of the grid. In addition one can create diagonal
"shear" tendons, using the :el:`tendon` sub-element. This type is suitable for simulating strings as well as cloth.
The **cable** type creates a 1D chain of bodies connected with ball joints, each having a geom with user-defined type
(cylinder, capsule or box). The geometry can either be defined with an array of 3D vertex coordinates :at:`vertex`
or with prescribed functions with the option :at:`curve`. Currently, only linear and trigonometric functions are
@@ -3007,34 +3000,6 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui
:at:`size`, resulting in :math:`f(s)=\{\text{size}[1]\cdot\cos(2\pi\cdot\text{size}[2]),\;
\text{size}[1]\cdot\sin(2\pi\cdot\text{size}[2]),\; \text{size}[0]\cdot s\}`.
The **cloth** type is a different way to model cloth, beyond type="grid". Here the elements are connected with
universal joints and form a kinematic spanning tree. The root of the tree is the parent body, and its coordinates in
the grid are inferred from its name - similar to rope but here the naming format is "CB2_0". Neighboring bodies that
are not connected with joints are then connected with equality-constrained spatial tendons. The resulting cloth is
non-homogeneous, because the kinematic constraints cannot be violated while the tendon equality constraints are soft.
One can make it more homogeneous by adding stretch and twist joints (similar to rope) and adjusting the strength of
their equality constraints. Shear tendons can also be added. In addition to the different physics, cloth can do
things that a 2D grid cannot do. This is because the elements of cloth have both position and orientation, while the
elements of grid can only translate. The geoms used in cloth can be ellipsoids and capsules in addition to spheres.
When elongated geoms are used, they are rotated and interleaved in a pattern that fills the holes, preventing objects
from penetrating the cloth. Furthermore the inertia of the cloth elements can be modified with the flatinertia
attribute, and can then be used with lift and drag forces to simulate ripple effects.
The **box** type creates a 3D arrangement of bodies forming the outer shell of a (soft) box. The parent body is at
the center of the box. Each element body has a geom (sphere, ellipsoid or capsule) and a single sliding joint
pointing away from the center of the box. The sliding joints are equality-constrained to their initial value.
Furthermore, to achieve smooth deformations of the sides of the box, each joint is equality-constrained to remain
equal to its neighbor joints. To preserve the volume of the soft box approximately, a fixed tendon is used to
constrain the sum of all joints to remain constant. When the user specifies elongated geoms (capsules or ellipsoids)
their long axis is aligned with the sliding joint axis. This makes the shell thicker for collision detection
purposes, preventing objects from penetrating the box. It is important to disable contacts between the elements of
the box. This is done by setting the default geom contype to 0. The user can change it of course, but if the geoms
comprising the soft box are allowed to contact each other the model will not work as intended.
The **cylinder** and **ellipsoid** types are the same as box, except the elements are projected on the surface of an
ellipsoid or a cylinder respectively. Thus the composite soft body shape is different, while everything else is the
same as in the box type.
.. _body-composite-count:
:at:`count`: :at-val:`int(3), required`
+1
View File
@@ -48,6 +48,7 @@ General
Previously, if the volumetric inertia computation failed (for example due to a very flat mesh), the compiler
would silently fall back to surface inertia computation. Now, the compiler will throw an informative error.
- Removed the composite type ``grid``. Users should instead use :ref:`flexcomp<body-flexcomp>`.
MJX
^^^
+3 -40
View File
@@ -1193,47 +1193,10 @@ a more complete treatment, see again the :ref:`deformable <CDeformable>` section
flex, see the folder `elasticity/ <https://github.com/google-deepmind/mujoco/tree/main/model/plugin/elasticity>`__ for
several examples.
**1D grid**.
**Grid**.
|image6| |image7|
.. code-block:: xml
<composite type="grid" count="20 1 1" spacing="0.045" offset="0 0 1">
<joint kind="main" damping="0.001"/>
<tendon kind="main" width="0.01"/>
<geom size=".02" rgba=".8 .2 .1 1"/>
<pin coord="1"/>
<pin coord="13"/>
</composite>
The grid type can create 1D or 2D grids, depending on the :at:`count` attribute. Here we illustrate 1D grids. These
are strings of spheres connected with tendons whose length is soft-equality-constrained. The softness can be adjusted.
Similar to particles, the element bodies here have slider joints but no rotational joints. The plot on the right
illustrates pinning. The :el:`pin` sub-element is used to specify the grid coordinates of the pinned bodies, and the
model compiler does not generate joints for these bodies, thereby fixing them rigidly to the parent body (in this case
the world). This makes the string in the right plot hang in space. The same mechanism can be used to model a whip for
example; in that case the parent body would be moving, and the first element body would be pinned to the parent.
**2D grid**.
|image8| |image9|
.. code-block:: xml
<composite type="grid" count="9 9 1" spacing="0.05" offset="0 0 1">
<skin material="matcarpet" inflate="0.001" subgrid="3" texcoord="true"/>
<geom size=".02"/>
<pin coord="0 0"/>
<pin coord="8 0"/>
</composite>
A 2D grid can be used to simulate cloth. What it really simulates is a 2D grid of spheres connected with
equality-constrained tendons (not shown). The model compiler can also generate skin, enabled with the :el:`skin`
sub-element in the above XML. Some of the element bodies can also be pinned, similar to 1D grids but using two grid
coordinates. The plot on the right shows a cloth pinned to the world body at the two corners, and draping over our
capsule probe. The skin on the right is subdivided using bi-cubic interpolation, which increases visual quality in the
absence of textures. When textures are present (left) the benefits of subdivision are less visible.
The grid composite type has been removed. It is recommended to use 2D flex :ref:`deformable objects <CDeformable>` for
simulating thin elastic structures.
**Cable**.
-29
View File
@@ -1,29 +0,0 @@
<!-- Copyright 2021 DeepMind Technologies Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mujoco model="2D grid with pins">
<include file="scene.xml"/>
<size memory="10M"/>
<worldbody>
<composite type="grid" count="9 9 1" spacing="0.05" offset="0 0 1">
<skin rgba=".6 .1 .6 1" inflate="0.001" subgrid="3"/>
<pin coord="0 0"/>
<pin coord="8 0"/>
<geom size=".02"/>
</composite>
</worldbody>
</mujoco>
+11 -12
View File
@@ -22,7 +22,7 @@
Simple humanoid on a hammock, implemented as a 2D grid composite, pinned at the corners.
-->
<option timestep="0.005" solver="CG" iterations="30" tolerance="1e-6"/>
<option timestep="0.001" solver="CG" iterations="30" tolerance="1e-6"/>
<size memory="20M"/>
@@ -41,23 +41,22 @@
width="512" height="512" mark="edge" markrgb=".8 .8 .8"/>
<material name="plane" reflectance="0.3" texture="plane" texrepeat="1 1" texuniform="true"/>
<material name="hammock" texture="hammock"/>
<model name="humanoid" file="../humanoid/humanoid.xml"/>
</asset>
<include file="humanoid_body.xml"/>
<worldbody>
<geom name="floor" pos="0 0 -1" size="0 0 .25" type="plane" material="plane" condim="3"/>
<light directional="true" diffuse=".2 .2 .2" specular="0 0 0" pos="0 0 5" dir="0 0 -1" castshadow="false"/>
<light directional="false" diffuse=".8 .8 .8" specular="0.3 0.3 0.3" pos="0 0 4" dir="0 0 -1"/>
<composite type="grid" count="11 9 1" spacing="0.2" offset="0. 0. 0">
<skin texcoord="true" material="hammock" inflate="0.01" subgrid="3"/>
<pin coord="0 0"/>
<pin coord="10 0"/>
<pin coord="0 8"/>
<pin coord="10 8"/>
<geom size=".095"/>
<joint kind="main" damping="10"/>
</composite>
<flexcomp name="hammock" type="grid" count="11 9 1" spacing="0.2 0.2 0.2" material="hammock"
radius="0.04" dim="2">
<pin id="0 8 90 98"/>
<edge equality="true" solref="0.002 5"/>
<contact selfcollide="none" internal="false" solimp=".99 .999 .00001"/>
</flexcomp>
<frame euler="0 180 -15" pos="-.4 -.2 2">
<attach model="humanoid" body="torso" prefix="humanoid_"/>
</frame>
</worldbody>
</mujoco>
-157
View File
@@ -1,157 +0,0 @@
<!-- Copyright 2021 DeepMind Technologies Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<mujoco model="Humanoid body">
<!-- Degree of Freedom: 27
Actuators: 21
This simplified humanoid model, introduced in [1], is designed for bipedal locomotion
behaviours. While several variants of it exist in the wild, this version is based on the model
in the DeepMind Control Suite [2], which has fairly realistic actuator gains.
[1] Synthesis and Stabilization of Complex Behaviors through Online Trajectory Optimization.
https://doi.org/10.1109/IROS.2012.6386025
[2] DeepMind Control Suite, Tassa et al. https://arxiv.org/abs/1801.00690
-->
<asset>
<texture type="skybox" builtin="gradient" rgb1=".3 .5 .7" rgb2="0 0 0" width="512" height="512"/>
<texture name="body" type="cube" builtin="flat" mark="cross" width="128" height="128"
rgb1="0.8 0.6 0.4" rgb2="0.8 0.6 0.4" markrgb="1 1 1"/>
<material name="body" texture="body" texuniform="true" rgba="0.8 0.6 .4 1"/>
<texture name="grid" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
<material name="grid" texture="grid" texrepeat="1 1" texuniform="true" reflectance=".2"/>
</asset>
<default>
<motor ctrlrange="-1 1" ctrllimited="true"/>
<default class="body">
<geom type="capsule" condim="1" friction=".7" solimp=".9 .99 .003" solref=".015 1" material="body"/>
<joint type="hinge" damping=".2" stiffness="1" armature=".01" limited="true" solimplimit="0 .99 .01"/>
<default class="big_joint">
<joint damping="5" stiffness="10"/>
<default class="big_stiff_joint">
<joint stiffness="20"/>
</default>
</default>
</default>
</default>
<visual>
<map force="0.1" zfar="30"/>
<rgba haze="0.15 0.25 0.35 1"/>
<quality shadowsize="4096"/>
<global offwidth="800" offheight="800"/>
</visual>
<worldbody>
<body name="torso" pos="0 0 1.5" childclass="body">
<camera name="back" pos="-3 0 1" xyaxes="0 -1 0 1 0 2" mode="trackcom"/>
<camera name="side" pos="0 -3 1" xyaxes="1 0 0 0 1 2" mode="trackcom"/>
<freejoint name="root"/>
<geom name="torso" fromto="0 -.07 0 0 .07 0" size=".07"/>
<geom name="upper_waist" fromto="-.01 -.06 -.12 -.01 .06 -.12" size=".06"/>
<body name="head" pos="0 0 .19">
<geom name="head" type="sphere" size=".09"/>
<camera name="egocentric" pos=".09 0 0" xyaxes="0 -1 0 .1 0 1" fovy="80"/>
</body>
<body name="lower_waist" pos="-.01 0 -.26">
<geom name="lower_waist" fromto="0 -.06 0 0 .06 0" size=".06"/>
<joint name="abdomen_z" pos="0 0 .065" axis="0 0 1" range="-45 45" class="big_stiff_joint"/>
<joint name="abdomen_y" pos="0 0 .065" axis="0 1 0" range="-75 30" class="big_joint"/>
<body name="pelvis" pos="0 0 -.165">
<joint name="abdomen_x" pos="0 0 .1" axis="1 0 0" range="-35 35" class="big_joint"/>
<geom name="butt" fromto="-.02 -.07 0 -.02 .07 0" size=".09"/>
<body name="right_thigh" pos="0 -.1 -.04">
<joint name="right_hip_x" axis="1 0 0" range="-25 5" class="big_joint"/>
<joint name="right_hip_z" axis="0 0 1" range="-60 35" class="big_joint"/>
<joint name="right_hip_y" axis="0 1 0" range="-110 20" class="big_stiff_joint"/>
<geom name="right_thigh" fromto="0 0 0 0 .01 -.34" size=".06"/>
<body name="right_shin" pos="0 .01 -.403">
<joint name="right_knee" pos="0 0 .02" axis="0 -1 0" range="-160 2"/>
<geom name="right_shin" fromto="0 0 0 0 0 -.3" size=".049"/>
<body name="right_foot" pos="0 0 -.39">
<joint name="right_ankle_y" pos="0 0 .08" axis="0 1 0" range="-50 50" stiffness="6"/>
<joint name="right_ankle_x" pos="0 0 .04" axis="1 0 .5" range="-50 50" stiffness="3"/>
<geom name="right_right_foot" fromto="-.07 -.02 0 .14 -.04 0" size=".027"/>
<geom name="left_right_foot" fromto="-.07 0 0 .14 .02 0" size=".027"/>
</body>
</body>
</body>
<body name="left_thigh" pos="0 .1 -.04">
<joint name="left_hip_x" axis="-1 0 0" range="-25 5" class="big_joint"/>
<joint name="left_hip_z" axis="0 0 -1" range="-60 35" class="big_joint"/>
<joint name="left_hip_y" axis="0 1 0" range="-110 20" class="big_stiff_joint"/>
<geom name="left_thigh" fromto="0 0 0 0 -.01 -.34" size=".06"/>
<body name="left_shin" pos="0 -.01 -.403">
<joint name="left_knee" pos="0 0 .02" axis="0 -1 0" range="-160 2"/>
<geom name="left_shin" fromto="0 0 0 0 0 -.3" size=".049"/>
<body name="left_foot" pos="0 0 -.39">
<joint name="left_ankle_y" pos="0 0 .08" axis="0 1 0" range="-50 50" stiffness="6"/>
<joint name="left_ankle_x" pos="0 0 .04" axis="1 0 .5" range="-50 50" stiffness="3"/>
<geom name="left_left_foot" fromto="-.07 .02 0 .14 .04 0" size=".027"/>
<geom name="right_left_foot" fromto="-.07 0 0 .14 -.02 0" size=".027"/>
</body>
</body>
</body>
</body>
</body>
<body name="right_upper_arm" pos="0 -.17 .06">
<joint name="right_shoulder1" axis="2 1 1" range="-85 60"/>
<joint name="right_shoulder2" axis="0 -1 1" range="-85 60"/>
<geom name="right_upper_arm" fromto="0 0 0 .16 -.16 -.16" size=".04 .16"/>
<body name="right_lower_arm" pos=".18 -.18 -.18">
<joint name="right_elbow" axis="0 -1 1" range="-90 50" stiffness="0"/>
<geom name="right_lower_arm" fromto=".01 .01 .01 .17 .17 .17" size=".031"/>
<body name="right_hand" pos=".18 .18 .18">
<geom name="right_hand" type="sphere" size=".04" zaxis="1 1 1"/>
</body>
</body>
</body>
<body name="left_upper_arm" pos="0 .17 .06">
<joint name="left_shoulder1" axis="2 -1 1" range="-60 85"/>
<joint name="left_shoulder2" axis="0 1 1" range="-60 85"/>
<geom name="left_upper_arm" fromto="0 0 0 .16 .16 -.16" size=".04 .16"/>
<body name="left_lower_arm" pos=".18 .18 -.18">
<joint name="left_elbow" axis="0 -1 -1" range="-90 50" stiffness="0"/>
<geom name="left_lower_arm" fromto=".01 -.01 .01 .17 -.17 .17" size=".031"/>
<body name="left_hand" pos=".18 -.18 .18">
<geom name="left_hand" type="sphere" size=".04" zaxis="1 -1 1"/>
</body>
</body>
</body>
</body>
</worldbody>
<actuator>
<motor name="abdomen_y" gear="40" joint="abdomen_y"/>
<motor name="abdomen_z" gear="40" joint="abdomen_z"/>
<motor name="abdomen_x" gear="40" joint="abdomen_x"/>
<motor name="right_hip_x" gear="40" joint="right_hip_x"/>
<motor name="right_hip_z" gear="40" joint="right_hip_z"/>
<motor name="right_hip_y" gear="120" joint="right_hip_y"/>
<motor name="right_knee" gear="80" joint="right_knee"/>
<motor name="right_ankle_x" gear="20" joint="right_ankle_x"/>
<motor name="right_ankle_y" gear="20" joint="right_ankle_y"/>
<motor name="left_hip_x" gear="40" joint="left_hip_x"/>
<motor name="left_hip_z" gear="40" joint="left_hip_z"/>
<motor name="left_hip_y" gear="120" joint="left_hip_y"/>
<motor name="left_knee" gear="80" joint="left_knee"/>
<motor name="left_ankle_x" gear="20" joint="left_ankle_x"/>
<motor name="left_ankle_y" gear="20" joint="left_ankle_y"/>
<motor name="right_shoulder1" gear="20" joint="right_shoulder1"/>
<motor name="right_shoulder2" gear="20" joint="right_shoulder2"/>
<motor name="right_elbow" gear="40" joint="right_elbow"/>
<motor name="left_shoulder1" gear="20" joint="left_shoulder1"/>
<motor name="left_shoulder2" gear="20" joint="left_shoulder2"/>
<motor name="left_elbow" gear="40" joint="left_elbow"/>
</actuator>
</mujoco>
+7 -205
View File
@@ -59,9 +59,7 @@ mjCComposite::mjCComposite(void) {
count[0] = count[1] = count[2] = 1;
spacing = 0;
mjuu_setvec(offset, 0, 0, 0);
pin.clear();
flatinertia = 0;
mj_defaultSolRefImp(solrefsmooth, solimpsmooth);
// plugin variables
mjs_defaultPlugin(&plugin);
@@ -95,23 +93,6 @@ mjCComposite::mjCComposite(void) {
// adjust constraint softness
void mjCComposite::AdjustSoft(mjtNum* solref, mjtNum* solimp, int level) {
switch (level) {
case 0:
solref[0] = 0.01;
solimp[0] = solimp[1] = 0.99;
break;
case 1:
solref[0] = 0.02;
solimp[0] = solimp[1] = 0.9;
break;
}
}
// create the array of default joint options, append new elements only for particles type
bool mjCComposite::AddDefaultJoint(char* error, int error_sz) {
for (int i=0; i<mjNCOMPKINDS; i++) {
@@ -131,14 +112,6 @@ bool mjCComposite::AddDefaultJoint(char* error, int error_sz) {
// set defaults, after reading top-level info and skin
void mjCComposite::SetDefault(void) {
// determine dimensionality
int tmpdim = 0;
for (int i=0; i<3; i++) {
if (count[i]>1) {
tmpdim++;
}
}
// set all default groups to 3
for (int i=0; i<mjNCOMPKINDS; i++) {
def[i].spec.geom->group = 3;
@@ -152,10 +125,7 @@ void mjCComposite::SetDefault(void) {
// set default geom and tendon group to 0 if needed to be visible
if (!skin ||
type==mjCOMPTYPE_PARTICLE ||
type==mjCOMPTYPE_ROPE ||
type==mjCOMPTYPE_LOOP ||
type==mjCOMPTYPE_CABLE ||
(type==mjCOMPTYPE_GRID && tmpdim==1)) {
type==mjCOMPTYPE_CABLE) {
for (int i=0; i<mjNCOMPKINDS; i++) {
def[i].spec.geom->group = 0;
def[i].spec.tendon->group = 0;
@@ -171,25 +141,7 @@ void mjCComposite::SetDefault(void) {
def[0].spec.geom->priority = 1;
break;
case mjCOMPTYPE_GRID: // grid
// hard main tendon fix
AdjustSoft(def[mjCOMPKIND_TENDON].spec.equality->solref,
def[mjCOMPKIND_TENDON].spec.equality->solimp, 0);
break;
case mjCOMPTYPE_CABLE: // cable
case mjCOMPTYPE_ROPE: // rope
break;
case mjCOMPTYPE_LOOP: // loop
// hard smoothing
AdjustSoft(solrefsmooth, solimpsmooth, 0);
break;
case mjCOMPTYPE_CLOTH: // cloth
break;
default:
@@ -213,11 +165,6 @@ bool mjCComposite::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz)
return comperr(error, "Composite geom type must be sphere, capsule or ellipsoid", error_sz);
}
// check pin coord number
if (pin.size()%2) {
return comperr(error, "Pin coordinate number of must be multiple of 2", error_sz);
}
// check counts
for (int i=0; i<3; i++) {
if (count[i]<1) {
@@ -305,7 +252,10 @@ bool mjCComposite::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz)
return MakeParticle(model, body, error, error_sz);
case mjCOMPTYPE_GRID:
return MakeGrid(model, body, error, error_sz);
return comperr(error,
"The \"grid\" composite type is deprecated. Please use "
"\"flex\" instead.",
error_sz);
case mjCOMPTYPE_ROPE:
return comperr(error,
@@ -413,123 +363,6 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjsBody* body, char* error, int
// make grid connected with tendons
bool mjCComposite::MakeGrid(mjCModel* model, mjsBody* body, char* error, int error_sz) {
char txt[100], txt1[100], txt2[100];
// check dimensionality
if (dim>2) {
return comperr(error, "Grid can only be 1D or 2D", error_sz);
}
// check shear dimensionality
if (add[mjCOMPKIND_SHEAR] && dim!=2) {
return comperr(error, "Shear requires 2D grid", error_sz);
}
// check skin dimensionality
if (skin && dim!=2) {
return comperr(error, "Skin requires 2D grid", error_sz);
}
// create bodies, joints, geoms, sites
for (int ix=0; ix<count[0]; ix++) {
for (int iy=0; iy<count[1]; iy++) {
// create body
mjsBody* b = mjs_addBody(body, NULL);
mju::sprintf_arr(txt, "%sB%d_%d", prefix.c_str(), ix, iy);
mjs_setString(b->name, txt);
// set body position
b->pos[0] = offset[0] + spacing*(ix - 0.5*count[0]);
b->pos[1] = offset[1] + spacing*(iy - 0.5*count[1]);
b->pos[2] = offset[2];
// add geom
mjsGeom* g = mjs_addGeom(b, &def[0].spec);
mjs_setDefault(g->element, mjs_getDefault(body->element));
g->type = mjGEOM_SPHERE;
mju::sprintf_arr(txt, "%sG%d_%d", prefix.c_str(), ix, iy);
mjs_setString(g->name, txt);
// add site
mjsSite* s = mjs_addSite(b, &def[0].spec);
mjs_setDefault(s->element, mjs_getDefault(body->element));
s->type = mjGEOM_SPHERE;
mju::sprintf_arr(txt, "%sS%d_%d", prefix.c_str(), ix, iy);
mjs_setString(s->name, txt);
// skip pinned elements
bool skip = false;
for (int ip=0; ip<pin.size(); ip+=2) {
if (pin[ip]==ix && pin[ip+1]==iy) {
skip = true;
break;
}
}
if (skip) {
continue;
}
// add slider joint
mjsJoint* jnt[3];
for (int i=0; i<3; i++) {
jnt[i] = mjs_addJoint(b, &defjoint[mjCOMPKIND_JOINT][0].spec);
mjs_setDefault(jnt[i]->element, mjs_getDefault(body->element));
mju::sprintf_arr(txt, "%sJ%d_%d_%d", prefix.c_str(), i, ix, iy);
mjs_setString(jnt[i]->name, txt);
jnt[i]->type = mjJNT_SLIDE;
mjuu_setvec(jnt[i]->pos, 0, 0, 0);
mjuu_setvec(jnt[i]->axis, 0, 0, 0);
jnt[i]->axis[i] = 1;
}
}
}
// create tendons and equality constraints
for (int i=0; i<2; i++) {
for (int ix=0; ix<count[0]-(i==0); ix++) {
for (int iy=0; iy<count[1]-(i==1); iy++) {
// recover site names
mju::sprintf_arr(txt1, "%sS%d_%d", prefix.c_str(), ix, iy);
mju::sprintf_arr(txt2, "%sS%d_%d", prefix.c_str(), ix+(i==0), iy+(i==1));
// create tendon
mjCTendon* ten = model->AddTendon(def + mjCOMPKIND_TENDON);
ten->classname = model->Default()->name;
mju::sprintf_arr(txt, "%sT%d_%d_%d", prefix.c_str(), i, ix, iy);
ten->name = txt;
ten->WrapSite(txt1);
ten->WrapSite(txt2);
// add equality constraint
mjsEquality* eq = mjs_addEquality(&model->spec, &def[mjCOMPKIND_TENDON].spec);
mjs_setDefault(eq->element, &model->Default()->spec);
eq->type = mjEQ_TENDON;
mjs_setString(eq->name1, ten->name.c_str());
}
}
}
// shear for 2D
if (add[mjCOMPKIND_SHEAR]) {
MakeShear(model);
}
// skin
if (skin) {
if (skinsubgrid>0) {
MakeSkin2Subgrid(model, skininflate);
} else {
MakeSkin2(model, skininflate);
}
}
return true;
}
bool mjCComposite::MakeCable(mjCModel* model, mjsBody* body, char* error, int error_sz) {
// check dim
if (dim!=1) {
@@ -730,37 +563,6 @@ mjsBody* mjCComposite::AddCableBody(mjCModel* model, mjsBody* body, int ix,
// add shear tendons to 2D
void mjCComposite::MakeShear(mjCModel* model) {
char txt[100], txt1[100], txt2[100];
for (int ix=0; ix<count[0]-1; ix++) {
for (int iy=0; iy<count[1]-1; iy++) {
// recover site names
mju::sprintf_arr(txt1, "%sS%d_%d", prefix.c_str(), ix, iy);
mju::sprintf_arr(txt2, "%sS%d_%d", prefix.c_str(), ix+1, iy+1);
// create tendon
mjCTendon* ten = model->AddTendon(def + mjCOMPKIND_SHEAR);
ten->classname = model->Default()->name;
ten->WrapSite(txt1);
ten->WrapSite(txt2);
// name tendon
mju::sprintf_arr(txt, "%sTS%d_%d", prefix.c_str(), ix, iy);
ten->name = txt;
// equality constraint
mjsEquality* eq = mjs_addEquality(&model->spec, &def[mjCOMPKIND_SHEAR].spec);
mjs_setDefault(eq->element, &model->Default()->spec);
eq->type = mjEQ_TENDON;
mjs_setString(eq->name1, txt);
}
}
}
// copy local vectors to skin
void mjCComposite::CopyIntoSkin(mjsSkin* skin) {
mjs_setInt(skin->face, face.data(), face.size());
@@ -875,7 +677,7 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) {
}
// couple with bones
if (type==mjCOMPTYPE_PARTICLE || type==mjCOMPTYPE_GRID) {
if (type==mjCOMPTYPE_PARTICLE) {
MakeClothBones(model, skin);
} else if (type==mjCOMPTYPE_CABLE) {
MakeCableBones(model, skin);
@@ -1434,7 +1236,7 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) {
face.push_back(NN + iy+1 + (C0-1)*C1);
}
if (type==mjCOMPTYPE_PARTICLE || type==mjCOMPTYPE_GRID) {
if (type==mjCOMPTYPE_PARTICLE) {
MakeClothBonesSubgrid(model, skin);
} else if (type==mjCOMPTYPE_CABLE) {
MakeCableBonesSubgrid(model, skin);
-7
View File
@@ -64,14 +64,10 @@ class mjCComposite {
void SetDefault(void);
bool AddDefaultJoint(char* error = NULL, int error_sz = 0);
void AdjustSoft(mjtNum* solref, mjtNum* solimp, int level);
bool Make(mjSpec* spec, mjsBody* body, char* error, int error_sz);
bool MakeParticle(mjCModel* model, mjsBody* body, char* error, int error_sz);
bool MakeGrid(mjCModel* model, mjsBody* body, char* error, int error_sz);
bool MakeCable(mjCModel* model, mjsBody* body, char* error, int error_sz);
void MakeShear(mjCModel* model);
void MakeSkin2(mjCModel* model, mjtNum inflate);
void MakeSkin2Subgrid(mjCModel* model, mjtNum inflate);
@@ -86,10 +82,7 @@ class mjCComposite {
int count[3]; // geom count in each dimension
double spacing; // spacing between elements
double offset[3]; // position offset for particle and grid
std::vector<int> pin; // pin elements of grid (do not create main joint)
double flatinertia; // flatten ineria of cloth elements; 0: disable
mjtNum solrefsmooth[mjNREF]; // solref for smoothing equality
mjtNum solimpsmooth[mjNIMP]; // solimp for smoothing equality
// currently used only for cable
std::string initial; // root boundary type
-19
View File
@@ -2466,10 +2466,6 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, const mjsDefault*
// set type-specific defaults
comp.SetDefault();
// parse smooth solver parameters after type-specific defaults are set
ReadAttr(elem, "solrefsmooth", mjNREF, comp.solrefsmooth, text, false, false);
ReadAttr(elem, "solimpsmooth", mjNIMP, comp.solimpsmooth, text, false, false);
// geom
XMLElement* egeom = FirstChildElement(elem, "geom");
if (egeom) {
@@ -2601,21 +2597,6 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, const mjsDefault*
eten = NextSiblingElement(eten, "tendon");
}
// pin
XMLElement* epin = FirstChildElement(elem, "pin");
while (epin) {
// read
int coord[2] = {0, 0};
ReadAttr(epin, "coord", 2, coord, text, true, false);
// insert 2 coordinates (2nd may be unused)
comp.pin.push_back(coord[0]);
comp.pin.push_back(coord[1]);
// advance
epin = NextSiblingElement(epin, "pin");
}
// make composite
char error[200];
bool res = comp.Make(spec, body, error, 200);
+11 -12
View File
@@ -22,7 +22,7 @@
Simple humanoid on a hammock, implemented as a 2D grid composite, pinned at the corners.
-->
<option timestep="0.005" solver="CG" iterations="30" tolerance="1e-6"/>
<option timestep="0.001" solver="CG" iterations="30" tolerance="1e-6"/>
<size memory="20M"/>
@@ -41,23 +41,22 @@
width="512" height="512" mark="edge" markrgb=".8 .8 .8"/>
<material name="plane" reflectance="0.3" texture="plane" texrepeat="1 1" texuniform="true"/>
<material name="hammock" texture="hammock"/>
<model name="humanoid" file="humanoid_body.xml"/>
</asset>
<include file="humanoid_body.xml"/>
<worldbody>
<geom name="floor" pos="0 0 -1" size="0 0 .25" type="plane" material="plane" condim="3"/>
<light directional="true" diffuse=".2 .2 .2" specular="0 0 0" pos="0 0 5" dir="0 0 -1" castshadow="false"/>
<light directional="false" diffuse=".8 .8 .8" specular="0.3 0.3 0.3" pos="0 0 4" dir="0 0 -1"/>
<composite type="grid" count="11 9 1" spacing="0.2" offset="0. 0. 0">
<skin texcoord="true" material="hammock" inflate="0.01" subgrid="3"/>
<pin coord="0 0"/>
<pin coord="10 0"/>
<pin coord="0 8"/>
<pin coord="10 8"/>
<geom size=".095"/>
<joint kind="main" damping="10"/>
</composite>
<flexcomp name="hammock" type="grid" count="11 9 1" spacing="0.2 0.2 0.2" material="hammock"
radius="0.04" dim="2">
<pin id="0 8 90 98"/>
<edge equality="true" damping="10" solimp=".95 .99"/>
<contact selfcollide="none" internal="false" solimp=".99 .999 .00001"/>
</flexcomp>
<frame euler="0 180 0" pos="-.4 -.2 2">
<attach model="humanoid" body="torso" prefix="humanoid_"/>
</frame>
</worldbody>
</mujoco>
+52 -10
View File
@@ -26,17 +26,59 @@
<joint limited="true" range="-45 45"/>
<geom type="box" size=".5 .5 .1"/>
</body>
<body pos="1 -1 .6">
<composite prefix="B0" type="grid" count="4 4 1" spacing=".2">
<geom group="4" size=".1"/>
<skin rgba="1 1 0 1" group="2" inflate=".1"/>
</composite>
<body pos="1 -1 .6" name="B0_parent">
<flexcomp name="B0" type="grid" count="4 4 1" spacing=".2 .2 .2" group="4" radius=".1" dim="2">
<edge equality="true"/>
<contact internal="false" selfcollide="none"/>
</flexcomp>
</body>
<body pos="-1 1 .6">
<composite prefix="B1" type="grid" count="4 4 1" spacing=".2">
<geom group="2" size=".1"/>
<skin rgba="0 1 1 1" group="4" inflate=".1"/>
</composite>
<body pos="-1 1 .6" name="B1_parent">
<flexcomp name="B1" type="grid" count="4 4 1" spacing=".2 .2 .2" group="2" radius=".1" dim="2">
<edge equality="true"/>
<contact internal="false" selfcollide="none"/>
</flexcomp>
</body>
</worldbody>
<deformable>
<skin name="B0Skin" group="2" rgba="1 1 0 1" inflate="0.1"
vertex="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"
face="0 4 5 0 5 1 1 5 6 1 6 2 2 6 7 2 7 3 4 8 9 4 9 5 5 9 10 5 10 6 6 10 11 6 11 7 8 12 13 8 13 9 9 13 14 9 14 10 10 14 15 10 15 11 16 21 20 16 17 21 17 22 21 17 18 22 18 23 22 18 19 23 20 25 24 20 21 25 21 26 25 21 22 26 22 27 26 22 23 27 24 29 28 24 25 29 25 30 29 25 26 30 26 31 30 26 27 31 0 20 4 0 16 20 4 24 8 4 20 24 8 28 12 8 24 28 3 7 23 3 23 19 7 11 27 7 27 23 11 15 31 11 31 27 0 1 17 0 17 16 1 2 18 1 18 17 2 3 19 2 19 18 12 29 13 12 28 29 13 30 14 13 29 30 14 31 15 14 30 31">
<bone body="B0_0" bindpos="0 0 0" bindquat="1 0 0 0" vertid="0 16" vertweight="1 1"/>
<bone body="B0_1" bindpos="0 0 0" bindquat="1 0 0 0" vertid="1 17" vertweight="1 1"/>
<bone body="B0_2" bindpos="0 0 0" bindquat="1 0 0 0" vertid="2 18" vertweight="1 1"/>
<bone body="B0_3" bindpos="0 0 0" bindquat="1 0 0 0" vertid="3 19" vertweight="1 1"/>
<bone body="B0_4" bindpos="0 0 0" bindquat="1 0 0 0" vertid="4 20" vertweight="1 1"/>
<bone body="B0_5" bindpos="0 0 0" bindquat="1 0 0 0" vertid="5 21" vertweight="1 1"/>
<bone body="B0_6" bindpos="0 0 0" bindquat="1 0 0 0" vertid="6 22" vertweight="1 1"/>
<bone body="B0_7" bindpos="0 0 0" bindquat="1 0 0 0" vertid="7 23" vertweight="1 1"/>
<bone body="B0_8" bindpos="0 0 0" bindquat="1 0 0 0" vertid="8 24" vertweight="1 1"/>
<bone body="B0_9" bindpos="0 0 0" bindquat="1 0 0 0" vertid="9 25" vertweight="1 1"/>
<bone body="B0_10" bindpos="0 0 0" bindquat="1 0 0 0" vertid="10 26" vertweight="1 1"/>
<bone body="B0_11" bindpos="0 0 0" bindquat="1 0 0 0" vertid="11 27" vertweight="1 1"/>
<bone body="B0_12" bindpos="0 0 0" bindquat="1 0 0 0" vertid="12 28" vertweight="1 1"/>
<bone body="B0_13" bindpos="0 0 0" bindquat="1 0 0 0" vertid="13 29" vertweight="1 1"/>
<bone body="B0_14" bindpos="0 0 0" bindquat="1 0 0 0" vertid="14 30" vertweight="1 1"/>
<bone body="B0_15" bindpos="0 0 0" bindquat="1 0 0 0" vertid="15 31" vertweight="1 1"/>
</skin>
<skin name="B1Skin" group="4" rgba="0 1 1 1" inflate="0.1"
vertex="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"
face="0 4 5 0 5 1 1 5 6 1 6 2 2 6 7 2 7 3 4 8 9 4 9 5 5 9 10 5 10 6 6 10 11 6 11 7 8 12 13 8 13 9 9 13 14 9 14 10 10 14 15 10 15 11 16 21 20 16 17 21 17 22 21 17 18 22 18 23 22 18 19 23 20 25 24 20 21 25 21 26 25 21 22 26 22 27 26 22 23 27 24 29 28 24 25 29 25 30 29 25 26 30 26 31 30 26 27 31 0 20 4 0 16 20 4 24 8 4 20 24 8 28 12 8 24 28 3 7 23 3 23 19 7 11 27 7 27 23 11 15 31 11 31 27 0 1 17 0 17 16 1 2 18 1 18 17 2 3 19 2 19 18 12 29 13 12 28 29 13 30 14 13 29 30 14 31 15 14 30 31">
<bone body="B1_0" bindpos="0 0 0" bindquat="1 0 0 0" vertid="0 16" vertweight="1 1"/>
<bone body="B1_1" bindpos="0 0 0" bindquat="1 0 0 0" vertid="1 17" vertweight="1 1"/>
<bone body="B1_2" bindpos="0 0 0" bindquat="1 0 0 0" vertid="2 18" vertweight="1 1"/>
<bone body="B1_3" bindpos="0 0 0" bindquat="1 0 0 0" vertid="3 19" vertweight="1 1"/>
<bone body="B1_4" bindpos="0 0 0" bindquat="1 0 0 0" vertid="4 20" vertweight="1 1"/>
<bone body="B1_5" bindpos="0 0 0" bindquat="1 0 0 0" vertid="5 21" vertweight="1 1"/>
<bone body="B1_6" bindpos="0 0 0" bindquat="1 0 0 0" vertid="6 22" vertweight="1 1"/>
<bone body="B1_7" bindpos="0 0 0" bindquat="1 0 0 0" vertid="7 23" vertweight="1 1"/>
<bone body="B1_8" bindpos="0 0 0" bindquat="1 0 0 0" vertid="8 24" vertweight="1 1"/>
<bone body="B1_9" bindpos="0 0 0" bindquat="1 0 0 0" vertid="9 25" vertweight="1 1"/>
<bone body="B1_10" bindpos="0 0 0" bindquat="1 0 0 0" vertid="10 26" vertweight="1 1"/>
<bone body="B1_11" bindpos="0 0 0" bindquat="1 0 0 0" vertid="11 27" vertweight="1 1"/>
<bone body="B1_12" bindpos="0 0 0" bindquat="1 0 0 0" vertid="12 28" vertweight="1 1"/>
<bone body="B1_13" bindpos="0 0 0" bindquat="1 0 0 0" vertid="13 29" vertweight="1 1"/>
<bone body="B1_14" bindpos="0 0 0" bindquat="1 0 0 0" vertid="14 30" vertweight="1 1"/>
<bone body="B1_15" bindpos="0 0 0" bindquat="1 0 0 0" vertid="15 31" vertweight="1 1"/>
</skin>
</deformable>
</mujoco>
+2 -23
View File
@@ -37,32 +37,11 @@ using UserCompositeTest = MujocoTest;
// ------------- test automatic inference of nuser_xxx -------------------------
TEST_F(UserCompositeTest, MultipleJointsNotAllowedUnlessParticle) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<freejoint/>
<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>
</body>
</worldbody>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, IsNull());
EXPECT_THAT(error.data(),
HasSubstr("Only particles are allowed to have multiple joints"));
}
TEST_F(UserCompositeTest, SpacingGreaterThanGeometry) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<composite type="grid" count="282 2">
<composite type="particle" count="282 2">
<geom size="8"/>
</composite>
</worldbody>
@@ -79,7 +58,7 @@ TEST_F(UserCompositeTest, SpacingEqualToGeometry) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<composite type="grid" count="282 2" spacing="8">
<composite type="particle" count="282 2" spacing="8">
<geom size="8"/>
</composite>
</worldbody>
+70 -14
View File
@@ -1809,29 +1809,85 @@ TEST_F(XMLReaderTest, ReadsSkinGroups) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<body>
<composite prefix="B0" type="grid" count="4 4 1" spacing=".2">
<geom size=".1" group="2"/>
<skin group="4"/>
</composite>
<body pos="1 -1 .6" name="B0_parent">
<flexcomp name="B0" type="grid" count="4 4 1" spacing=".2 .2 .2" group="2" radius=".1" dim="2">
<edge equality="true"/>
<contact internal="false" selfcollide="none"/>
</flexcomp>
</body>
<body>
<composite prefix="B1" type="grid" count="4 4 1" spacing=".2">
<geom size=".1" group="4"/>
<skin group="2"/>
</composite>
<body pos="-1 1 .6" name="B1_parent">
<flexcomp name="B1" type="grid" count="4 4 1" spacing=".2 .2 .2" group="4" radius=".1" dim="2">
<edge equality="true"/>
<contact internal="false" selfcollide="none"/>
</flexcomp>
</body>
</worldbody>
<deformable>
<skin name="B0Skin" group="4" rgba="1 1 0 1" inflate="0.1"
vertex="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"
face="0 4 5 0 5 1 1 5 6 1 6 2 2 6 7 2 7 3 4 8 9 4 9 5 5 9 10 5 10 6 6 10 11 6 11 7 8
12 13 8 13 9 9 13 14 9 14 10 10 14 15 10 15 11 16 21 20 16 17 21 17 22 21 17 18
22 18 23 22 18 19 23 20 25 24 20 21 25 21 26 25 21 22 26 22 27 26 22 23 27 24 29
28 24 25 29 25 30 29 25 26 30 26 31 30 26 27 31 0 20 4 0 16 20 4 24 8 4 20 24 8
28 12 8 24 28 3 7 23 3 23 19 7 11 27 7 27 23 11 15 31 11 31 27 0 1 17 0 17 16 1
2 18 1 18 17 2 3 19 2 19 18 12 29 13 12 28 29 13 30 14 13 29 30 14 31 15 14 30 31">
<bone body="B0_0" bindpos="0 0 0" bindquat="1 0 0 0" vertid="0 16" vertweight="1 1"/>
<bone body="B0_1" bindpos="0 0 0" bindquat="1 0 0 0" vertid="1 17" vertweight="1 1"/>
<bone body="B0_2" bindpos="0 0 0" bindquat="1 0 0 0" vertid="2 18" vertweight="1 1"/>
<bone body="B0_3" bindpos="0 0 0" bindquat="1 0 0 0" vertid="3 19" vertweight="1 1"/>
<bone body="B0_4" bindpos="0 0 0" bindquat="1 0 0 0" vertid="4 20" vertweight="1 1"/>
<bone body="B0_5" bindpos="0 0 0" bindquat="1 0 0 0" vertid="5 21" vertweight="1 1"/>
<bone body="B0_6" bindpos="0 0 0" bindquat="1 0 0 0" vertid="6 22" vertweight="1 1"/>
<bone body="B0_7" bindpos="0 0 0" bindquat="1 0 0 0" vertid="7 23" vertweight="1 1"/>
<bone body="B0_8" bindpos="0 0 0" bindquat="1 0 0 0" vertid="8 24" vertweight="1 1"/>
<bone body="B0_9" bindpos="0 0 0" bindquat="1 0 0 0" vertid="9 25" vertweight="1 1"/>
<bone body="B0_10" bindpos="0 0 0" bindquat="1 0 0 0" vertid="10 26" vertweight="1 1"/>
<bone body="B0_11" bindpos="0 0 0" bindquat="1 0 0 0" vertid="11 27" vertweight="1 1"/>
<bone body="B0_12" bindpos="0 0 0" bindquat="1 0 0 0" vertid="12 28" vertweight="1 1"/>
<bone body="B0_13" bindpos="0 0 0" bindquat="1 0 0 0" vertid="13 29" vertweight="1 1"/>
<bone body="B0_14" bindpos="0 0 0" bindquat="1 0 0 0" vertid="14 30" vertweight="1 1"/>
<bone body="B0_15" bindpos="0 0 0" bindquat="1 0 0 0" vertid="15 31" vertweight="1 1"/>
</skin>
<skin name="B1Skin" group="2" rgba="0 1 1 1" inflate="0.1"
vertex="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"
face="0 4 5 0 5 1 1 5 6 1 6 2 2 6 7 2 7 3 4 8 9 4 9 5 5 9 10 5 10 6 6 10 11 6 11 7 8
12 13 8 13 9 9 13 14 9 14 10 10 14 15 10 15 11 16 21 20 16 17 21 17 22 21 17 18
22 18 23 22 18 19 23 20 25 24 20 21 25 21 26 25 21 22 26 22 27 26 22 23 27 24 29
28 24 25 29 25 30 29 25 26 30 26 31 30 26 27 31 0 20 4 0 16 20 4 24 8 4 20 24 8
28 12 8 24 28 3 7 23 3 23 19 7 11 27 7 27 23 11 15 31 11 31 27 0 1 17 0 17 16 1
2 18 1 18 17 2 3 19 2 19 18 12 29 13 12 28 29 13 30 14 13 29 30 14 31 15 14 30 31">
<bone body="B1_0" bindpos="0 0 0" bindquat="1 0 0 0" vertid="0 16" vertweight="1 1"/>
<bone body="B1_1" bindpos="0 0 0" bindquat="1 0 0 0" vertid="1 17" vertweight="1 1"/>
<bone body="B1_2" bindpos="0 0 0" bindquat="1 0 0 0" vertid="2 18" vertweight="1 1"/>
<bone body="B1_3" bindpos="0 0 0" bindquat="1 0 0 0" vertid="3 19" vertweight="1 1"/>
<bone body="B1_4" bindpos="0 0 0" bindquat="1 0 0 0" vertid="4 20" vertweight="1 1"/>
<bone body="B1_5" bindpos="0 0 0" bindquat="1 0 0 0" vertid="5 21" vertweight="1 1"/>
<bone body="B1_6" bindpos="0 0 0" bindquat="1 0 0 0" vertid="6 22" vertweight="1 1"/>
<bone body="B1_7" bindpos="0 0 0" bindquat="1 0 0 0" vertid="7 23" vertweight="1 1"/>
<bone body="B1_8" bindpos="0 0 0" bindquat="1 0 0 0" vertid="8 24" vertweight="1 1"/>
<bone body="B1_9" bindpos="0 0 0" bindquat="1 0 0 0" vertid="9 25" vertweight="1 1"/>
<bone body="B1_10" bindpos="0 0 0" bindquat="1 0 0 0" vertid="10 26" vertweight="1 1"/>
<bone body="B1_11" bindpos="0 0 0" bindquat="1 0 0 0" vertid="11 27" vertweight="1 1"/>
<bone body="B1_12" bindpos="0 0 0" bindquat="1 0 0 0" vertid="12 28" vertweight="1 1"/>
<bone body="B1_13" bindpos="0 0 0" bindquat="1 0 0 0" vertid="13 29" vertweight="1 1"/>
<bone body="B1_14" bindpos="0 0 0" bindquat="1 0 0 0" vertid="14 30" vertweight="1 1"/>
<bone body="B1_15" bindpos="0 0 0" bindquat="1 0 0 0" vertid="15 31" vertweight="1 1"/>
</skin>
</deformable>
</mujoco>
)";
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");
int geomid2 = mj_name2id(model, mjOBJ_GEOM, "B1G0_0");
EXPECT_THAT(model->geom_group[geomid1], 2);
int flexid1 = mj_name2id(model, mjOBJ_FLEX, "B0");
int flexid2 = mj_name2id(model, mjOBJ_FLEX, "B1");
EXPECT_THAT(model->flex_group[flexid1], 2);
EXPECT_THAT(model->skin_group[0], 4);
EXPECT_THAT(model->geom_group[geomid2], 4);
EXPECT_THAT(model->flex_group[flexid2], 4);
EXPECT_THAT(model->skin_group[1], 2);
mj_deleteModel(model);
}
+33 -4
View File
@@ -914,13 +914,42 @@ TEST_F(XMLWriterTest, WritesSkin) {
static constexpr char xml[] = R"(
<mujoco>
<worldbody>
<composite type="grid" count="2 2 1" spacing="0.05">
<skin texcoord="true"/>
<geom size=".01"/>
</composite>
<body pos="1 -1 .6" name="B0_parent">
<flexcomp name="B0" type="grid" count="4 4 1" spacing=".2 .2 .2" radius=".1" dim="2"/>
</body>
</worldbody>
<deformable>
<skin name="B0Skin" rgba="1 1 0 1" inflate="0.1"
vertex="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"
face="0 4 5 0 5 1 1 5 6 1 6 2 2 6 7 2 7 3 4 8 9 4 9 5 5 9 10 5 10 6 6 10 11 6 11 7 8
12 13 8 13 9 9 13 14 9 14 10 10 14 15 10 15 11 16 21 20 16 17 21 17 22 21 17 18
22 18 23 22 18 19 23 20 25 24 20 21 25 21 26 25 21 22 26 22 27 26 22 23 27 24 29
28 24 25 29 25 30 29 25 26 30 26 31 30 26 27 31 0 20 4 0 16 20 4 24 8 4 20 24 8
28 12 8 24 28 3 7 23 3 23 19 7 11 27 7 27 23 11 15 31 11 31 27 0 1 17 0 17 16 1
2 18 1 18 17 2 3 19 2 19 18 12 29 13 12 28 29 13 30 14 13 29 30 14 31 15 14 30 31">
<bone body="B0_0" bindpos="0 0 0" bindquat="1 0 0 0" vertid="0 16" vertweight="1 1"/>
<bone body="B0_1" bindpos="0 0 0" bindquat="1 0 0 0" vertid="1 17" vertweight="1 1"/>
<bone body="B0_2" bindpos="0 0 0" bindquat="1 0 0 0" vertid="2 18" vertweight="1 1"/>
<bone body="B0_3" bindpos="0 0 0" bindquat="1 0 0 0" vertid="3 19" vertweight="1 1"/>
<bone body="B0_4" bindpos="0 0 0" bindquat="1 0 0 0" vertid="4 20" vertweight="1 1"/>
<bone body="B0_5" bindpos="0 0 0" bindquat="1 0 0 0" vertid="5 21" vertweight="1 1"/>
<bone body="B0_6" bindpos="0 0 0" bindquat="1 0 0 0" vertid="6 22" vertweight="1 1"/>
<bone body="B0_7" bindpos="0 0 0" bindquat="1 0 0 0" vertid="7 23" vertweight="1 1"/>
<bone body="B0_8" bindpos="0 0 0" bindquat="1 0 0 0" vertid="8 24" vertweight="1 1"/>
<bone body="B0_9" bindpos="0 0 0" bindquat="1 0 0 0" vertid="9 25" vertweight="1 1"/>
<bone body="B0_10" bindpos="0 0 0" bindquat="1 0 0 0" vertid="10 26" vertweight="1 1"/>
<bone body="B0_11" bindpos="0 0 0" bindquat="1 0 0 0" vertid="11 27" vertweight="1 1"/>
<bone body="B0_12" bindpos="0 0 0" bindquat="1 0 0 0" vertid="12 28" vertweight="1 1"/>
<bone body="B0_13" bindpos="0 0 0" bindquat="1 0 0 0" vertid="13 29" vertweight="1 1"/>
<bone body="B0_14" bindpos="0 0 0" bindquat="1 0 0 0" vertid="14 30" vertweight="1 1"/>
<bone body="B0_15" bindpos="0 0 0" bindquat="1 0 0 0" vertid="15 31" vertweight="1 1"/>
</skin>
</deformable>
</mujoco>
)";
mjModel* model = LoadModelFromString(xml);
ASSERT_THAT(model, NotNull());
EXPECT_THAT(model->nskin, 1);