Remove all visual-only assets if discardvisual is selected, not only the geoms.
PiperOrigin-RevId: 598598250 Change-Id: I12e60ce41ad436d037b4877d197decf6bdce0fc8
This commit is contained in:
committed by
Copybara-Service
parent
acf698e2df
commit
1e2e0b3053
+14
-8
@@ -306,14 +306,20 @@ any effect. The settings here are global and apply to the entire model.
|
|||||||
.. _compiler-discardvisual:
|
.. _compiler-discardvisual:
|
||||||
|
|
||||||
:at:`discardvisual`: :at-val:`[false, true], "false" for MJCF, "true" for URDF`
|
:at:`discardvisual`: :at-val:`[false, true], "false" for MJCF, "true" for URDF`
|
||||||
This attribute instructs the parser to discard "visual geoms", defined as geoms whose contype and conaffinity
|
This attribute instructs the compiler to discard all model elements which are purely visual and have no effect on the
|
||||||
attributes are both set to 0. This functionality is useful for models that contain two sets of geoms, one for
|
physics (with one exception, see below). This often enables smaller :ref:`mjModel` structs and faster simulation.
|
||||||
collisions and the other for visualization. Note that URDF models are usually constructed in this way. It rarely
|
|
||||||
makes sense to have two sets of geoms in the model, especially since MuJoCo uses convex hulls for collisions, so we
|
- All materials are discarded.
|
||||||
recommend using this feature to discard redundant geoms. Keep in mind however that geoms considered visual per the
|
- All textures are discarded.
|
||||||
above definition can still participate in collisions, if they appear in the explicit list of contact
|
- All geoms with :ref:`contype<body-geom-contype>`=:ref:`conaffinity<body-geom-conaffinity>`=0 are discarded, if they
|
||||||
:ref:`pairs <contact-pair>`. The parser does not check this list before discarding geoms; it relies solely on the geom
|
are not referenced in another MJCF element. If a discarded geom was used for inferring body inertia, an explicit
|
||||||
attributes to make the determination.
|
:ref:`inertial<body-inertial>` element is added to the body.
|
||||||
|
- All meshes which are not referenced by any geom (in particular those discarded above) are discarded.
|
||||||
|
|
||||||
|
The resulting compiled model will have exactly the same dynamics as the original model, with the exception of
|
||||||
|
raycasting, as used for example by :ref:`rangefinder<sensor-rangefinder>`, since raycasting reports distances to
|
||||||
|
visual geoms. When visualizing models compiled with this flag, it is important to remember that colliding geoms are
|
||||||
|
often placed in a :ref:`group<body-geom-group>` which is invisible by default.
|
||||||
|
|
||||||
.. _compiler-convexhull:
|
.. _compiler-convexhull:
|
||||||
|
|
||||||
|
|||||||
+11
-5
@@ -5,16 +5,22 @@ Changelog
|
|||||||
Upcoming version (not yet released)
|
Upcoming version (not yet released)
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
|
General
|
||||||
|
^^^^^^^
|
||||||
|
1. Improved the :ref:discardvisual<compiler-discardvisual> compiler flag, which now discards all visual-only assets. See
|
||||||
|
:ref:discardvisual<compiler-discardvisual> for details.
|
||||||
|
|
||||||
MJX
|
MJX
|
||||||
^^^
|
^^^
|
||||||
1. Added :ref:`dyntype<actuator-general-dyntype>` ``filterexact``.
|
2. Added :ref:`dyntype<actuator-general-dyntype>` ``filterexact``.
|
||||||
2. Added :at:`site` transmission.
|
3. Added :at:`site` transmission.
|
||||||
3. Updated MJX colab tutorial with more stable quadruped environment.
|
4. Updated MJX colab tutorial with more stable quadruped environment.
|
||||||
4. Added ``mjx.ray`` which mirrors :ref:`mj_ray` for planes, spheres, capsules, and boxes.
|
5. Added ``mjx.ray`` which mirrors :ref:`mj_ray` for planes, spheres, capsules, and boxes.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
5. Fixed a bug that prevented the use of pins with plugins if flexes are not in the worldbody. Fixes :github:issue:`1270`.
|
6. Fixed a bug that prevented the use of pins with plugins if flexes are not in the worldbody. Fixes
|
||||||
|
:github:issue:`1270`.
|
||||||
|
|
||||||
|
|
||||||
Version 3.1.1 (December 18, 2023)
|
Version 3.1.1 (December 18, 2023)
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) {
|
|||||||
valideigenvalue_ = true;
|
valideigenvalue_ = true;
|
||||||
validinequality_ = true;
|
validinequality_ = true;
|
||||||
processed_ = false;
|
processed_ = false;
|
||||||
|
visual_ = true;
|
||||||
|
|
||||||
// reset to default if given
|
// reset to default if given
|
||||||
if (_def) {
|
if (_def) {
|
||||||
@@ -708,6 +709,13 @@ void mjCMesh::CopyGraph(int* arr) const {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void mjCMesh::DelTexcoord() {
|
||||||
|
if (texcoord_) mju_free(texcoord_);
|
||||||
|
ntexcoord_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// set geom size to match mesh
|
// set geom size to match mesh
|
||||||
void mjCMesh::FitGeom(mjCGeom* geom, double* meshpos) {
|
void mjCMesh::FitGeom(mjCGeom* geom, double* meshpos) {
|
||||||
// copy mesh pos into meshpos
|
// copy mesh pos into meshpos
|
||||||
@@ -2229,6 +2237,15 @@ mjCFlex::mjCFlex(mjCModel* _model) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool mjCFlex::HasTexcoord() const {
|
||||||
|
return !texcoord.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mjCFlex::DelTexcoord() {
|
||||||
|
texcoord.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// compiler
|
// compiler
|
||||||
void mjCFlex::Compile(const mjVFS* vfs) {
|
void mjCFlex::Compile(const mjVFS* vfs) {
|
||||||
|
|||||||
+157
-6
@@ -649,9 +649,126 @@ void mjCModel::MakeLists(mjCBody* body) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// delete material with given name or all materials if the name is omitted
|
||||||
|
template <class T>
|
||||||
|
static void DeleteMaterial(std::vector<T*>& list, std::string_view name = "") {
|
||||||
|
for (T* plist : list) {
|
||||||
|
if (name.empty() || plist->material == name) {
|
||||||
|
plist->material.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// delete texture with given name or all textures if the name is omitted
|
||||||
|
template <class T>
|
||||||
|
static void DeleteTexture(std::vector<T*>& list, std::string_view name = "") {
|
||||||
|
for (T* plist : list) {
|
||||||
|
if (name.empty() || plist->texture == name) {
|
||||||
|
plist->texture.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// delete all texture coordinates
|
||||||
|
template <class T>
|
||||||
|
static void DeleteTexcoord(std::vector<T*>& list) {
|
||||||
|
for (T* plist : list) {
|
||||||
|
if (plist->HasTexcoord()) {
|
||||||
|
plist->DelTexcoord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// returns a vector that stores the reference correction for each entry
|
||||||
|
template <class T>
|
||||||
|
static void DeleteElements(std::vector<T*>& elements,
|
||||||
|
const std::vector<bool>& discard) {
|
||||||
|
if (elements.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> ndiscard(elements.size(), 0);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (int j=0; j<elements.size(); j++) {
|
||||||
|
if (discard[j]) {
|
||||||
|
delete elements[j];
|
||||||
|
} else {
|
||||||
|
elements[i] = elements[j];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// count cumulative discarded elements
|
||||||
|
for (int i=0; i<elements.size()-1; i++) {
|
||||||
|
ndiscard[i+1] = ndiscard[i] + discard[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// erase elements from vector
|
||||||
|
if (i < elements.size()) {
|
||||||
|
elements.erase(elements.begin() + i, elements.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// update elements
|
||||||
|
for (T* element : elements) {
|
||||||
|
if (element->id > 0) {
|
||||||
|
element->id -= ndiscard[element->id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void mjCModel::Delete<mjCGeom>(std::vector<mjCGeom*>& elements,
|
||||||
|
const std::vector<bool>& discard) {
|
||||||
|
// update bodies
|
||||||
|
for (mjCBody* body : bodies) {
|
||||||
|
body->geoms.erase(
|
||||||
|
std::remove_if(body->geoms.begin(), body->geoms.end(),
|
||||||
|
[&discard](mjCGeom* geom) { return discard[geom->id]; }),
|
||||||
|
body->geoms.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove geoms from the main vector
|
||||||
|
DeleteElements(elements, discard);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void mjCModel::Delete<mjCMesh>(std::vector<mjCMesh*>& elements,
|
||||||
|
const std::vector<bool>& discard) {
|
||||||
|
DeleteElements(elements, discard);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void mjCModel::DeleteAll<mjCMaterial>(std::vector<mjCMaterial*>& elements) {
|
||||||
|
DeleteMaterial(geoms);
|
||||||
|
DeleteMaterial(skins);
|
||||||
|
DeleteMaterial(sites);
|
||||||
|
DeleteMaterial(tendons);
|
||||||
|
for (mjCMaterial* element : elements) {
|
||||||
|
delete element;
|
||||||
|
}
|
||||||
|
elements.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void mjCModel::DeleteAll<mjCTexture>(std::vector<mjCTexture*>& elements) {
|
||||||
|
DeleteTexture(materials);
|
||||||
|
for (mjCTexture* element : elements) {
|
||||||
|
delete element;
|
||||||
|
}
|
||||||
|
elements.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// index assets
|
// index assets
|
||||||
void mjCModel::IndexAssets(void) {
|
void mjCModel::IndexAssets(bool discard) {
|
||||||
// assets referenced in geoms
|
// assets referenced in geoms
|
||||||
for (int i=0; i<geoms.size(); i++) {
|
for (int i=0; i<geoms.size(); i++) {
|
||||||
mjCGeom* pgeom = geoms[i];
|
mjCGeom* pgeom = geoms[i];
|
||||||
@@ -670,7 +787,19 @@ void mjCModel::IndexAssets(void) {
|
|||||||
if (!pgeom->meshname.empty()) {
|
if (!pgeom->meshname.empty()) {
|
||||||
mjCBase* m = FindObject(mjOBJ_MESH, pgeom->meshname);
|
mjCBase* m = FindObject(mjOBJ_MESH, pgeom->meshname);
|
||||||
if (m) {
|
if (m) {
|
||||||
pgeom->mesh = (mjCMesh*)m;
|
if (discard && geoms[i]->visual_) {
|
||||||
|
// do not associate with a mesh
|
||||||
|
pgeom->mesh = nullptr;
|
||||||
|
} else {
|
||||||
|
// associate mesh with geom
|
||||||
|
pgeom->mesh = (mjCMesh*)m;
|
||||||
|
|
||||||
|
// mark mesh as not visual
|
||||||
|
// this is irreversible so only performed when IndexAssets is called with discard
|
||||||
|
if (discard) {
|
||||||
|
pgeom->mesh->SetNotVisual();
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw mjCError(pgeom, "mesh '%s' not found in geom %d", pgeom->meshname.c_str(), i);
|
throw mjCError(pgeom, "mesh '%s' not found in geom %d", pgeom->meshname.c_str(), i);
|
||||||
}
|
}
|
||||||
@@ -746,6 +875,20 @@ void mjCModel::IndexAssets(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// discard visual meshes and geoms
|
||||||
|
if (discard) {
|
||||||
|
std::vector<bool> discard_mesh(meshes.size(), false);
|
||||||
|
std::vector<bool> discard_geom(geoms.size(), false);
|
||||||
|
|
||||||
|
std::transform(meshes.begin(), meshes.end(), discard_mesh.begin(),
|
||||||
|
[](const mjCMesh* mesh) { return mesh->IsVisual(); });
|
||||||
|
std::transform(geoms.begin(), geoms.end(), discard_geom.begin(),
|
||||||
|
[](const mjCGeom* geom) { return geom->IsVisual(); });
|
||||||
|
|
||||||
|
Delete(meshes, discard_mesh);
|
||||||
|
Delete(geoms, discard_geom);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2049,8 +2192,8 @@ void mjCModel::CopyObjects(mjModel* m) {
|
|||||||
// geom pairs to include
|
// geom pairs to include
|
||||||
for (int i=0; i<npair; i++) {
|
for (int i=0; i<npair; i++) {
|
||||||
m->pair_dim[i] = pairs[i]->condim;
|
m->pair_dim[i] = pairs[i]->condim;
|
||||||
m->pair_geom1[i] = pairs[i]->geom1;
|
m->pair_geom1[i] = pairs[i]->geom1->id;
|
||||||
m->pair_geom2[i] = pairs[i]->geom2;
|
m->pair_geom2[i] = pairs[i]->geom2->id;
|
||||||
m->pair_signature[i] = pairs[i]->signature;
|
m->pair_signature[i] = pairs[i]->signature;
|
||||||
copyvec(m->pair_solref+mjNREF*i, pairs[i]->solref, mjNREF);
|
copyvec(m->pair_solref+mjNREF*i, pairs[i]->solref, mjNREF);
|
||||||
copyvec(m->pair_solreffriction+mjNREF*i, pairs[i]->solreffriction, mjNREF);
|
copyvec(m->pair_solreffriction+mjNREF*i, pairs[i]->solreffriction, mjNREF);
|
||||||
@@ -2711,8 +2854,16 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete visual assets
|
||||||
|
if (discardvisual) {
|
||||||
|
DeleteAll(materials);
|
||||||
|
DeleteTexcoord(flexes);
|
||||||
|
DeleteTexcoord(meshes);
|
||||||
|
DeleteAll(textures);
|
||||||
|
}
|
||||||
|
|
||||||
// convert names into indices
|
// convert names into indices
|
||||||
IndexAssets();
|
IndexAssets(false);
|
||||||
|
|
||||||
// mark meshes that need convex hull
|
// mark meshes that need convex hull
|
||||||
for (int i=0; i<geoms.size(); i++) {
|
for (int i=0; i<geoms.size(); i++) {
|
||||||
@@ -2811,7 +2962,7 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
|
|||||||
reassignid(excludes);
|
reassignid(excludes);
|
||||||
|
|
||||||
// resolve asset references, compute sizes
|
// resolve asset references, compute sizes
|
||||||
IndexAssets();
|
IndexAssets(discardvisual);
|
||||||
SetSizes();
|
SetSizes();
|
||||||
// fuse static if enabled
|
// fuse static if enabled
|
||||||
if (fusestatic) {
|
if (fusestatic) {
|
||||||
|
|||||||
+18
-10
@@ -96,6 +96,14 @@ class mjCModel {
|
|||||||
mjCKey* AddKey(void); // keyframe
|
mjCKey* AddKey(void); // keyframe
|
||||||
mjCPlugin* AddPlugin(void); // plugin instance
|
mjCPlugin* AddPlugin(void); // plugin instance
|
||||||
|
|
||||||
|
//------------------------ API for deleting model elements
|
||||||
|
template <class T>
|
||||||
|
void Delete(std::vector<T*>& elements,
|
||||||
|
const std::vector<bool>& discard); // delete elements marked as discard=true
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void DeleteAll(std::vector<T*>& elements); // delete all elements
|
||||||
|
|
||||||
//------------------------ API for access to model elements (outside tree)
|
//------------------------ API for access to model elements (outside tree)
|
||||||
int NumObjects(mjtObj type); // number of objects in specified list
|
int NumObjects(mjtObj type); // number of objects in specified list
|
||||||
mjCBase* GetObject(mjtObj type, int id); // pointer to specified object
|
mjCBase* GetObject(mjtObj type, int id); // pointer to specified object
|
||||||
@@ -185,16 +193,16 @@ class mjCModel {
|
|||||||
void SetDefaultNames(std::vector<T*>& assets);
|
void SetDefaultNames(std::vector<T*>& assets);
|
||||||
|
|
||||||
//------------------------ compile phases
|
//------------------------ compile phases
|
||||||
void MakeLists(mjCBody* body); // make lists of bodies, geoms, joints, sites
|
void MakeLists(mjCBody* body); // make lists of bodies, geoms, joints, sites
|
||||||
void IndexAssets(void); // convert asset names into indices
|
void IndexAssets(bool discard); // convert asset names into indices
|
||||||
void CheckEmptyNames(void); // check empty names
|
void CheckEmptyNames(void); // check empty names
|
||||||
void SetSizes(void); // compute sizes
|
void SetSizes(void); // compute sizes
|
||||||
void AutoSpringDamper(mjModel*);// automatic stiffness and damping computation
|
void AutoSpringDamper(mjModel*); // automatic stiffness and damping computation
|
||||||
void LengthRange(mjModel*, mjData*); // compute actuator lengthrange
|
void LengthRange(mjModel*, mjData*); // compute actuator lengthrange
|
||||||
void CopyNames(mjModel*); // copy names, compute name addresses
|
void CopyNames(mjModel*); // copy names, compute name addresses
|
||||||
void CopyPaths(mjModel*); // copy paths, compute path addresses
|
void CopyPaths(mjModel*); // copy paths, compute path addresses
|
||||||
void CopyObjects(mjModel*); // copy objects outside kinematic tree
|
void CopyObjects(mjModel*); // copy objects outside kinematic tree
|
||||||
void CopyTree(mjModel*); // copy objects inside kinematic tree
|
void CopyTree(mjModel*); // copy objects inside kinematic tree
|
||||||
|
|
||||||
//------------------------ sizes
|
//------------------------ sizes
|
||||||
// sizes set from object list lengths
|
// sizes set from object list lengths
|
||||||
|
|||||||
+68
-27
@@ -314,6 +314,7 @@ int mjCBoundingVolumeHierarchy::MakeBVH(std::vector<const mjCBoundingVolume*>& e
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_visual = true;
|
||||||
int nelements = elements.size();
|
int nelements = elements.size();
|
||||||
mjtNum AAMM[6] = {mjMAXVAL, mjMAXVAL, mjMAXVAL, -mjMAXVAL, -mjMAXVAL, -mjMAXVAL};
|
mjtNum AAMM[6] = {mjMAXVAL, mjMAXVAL, mjMAXVAL, -mjMAXVAL, -mjMAXVAL, -mjMAXVAL};
|
||||||
|
|
||||||
@@ -325,6 +326,8 @@ int mjCBoundingVolumeHierarchy::MakeBVH(std::vector<const mjCBoundingVolume*>& e
|
|||||||
// skip visual objects
|
// skip visual objects
|
||||||
if (elements[i]->conaffinity==0 && elements[i]->contype==0) {
|
if (elements[i]->conaffinity==0 && elements[i]->contype==0) {
|
||||||
continue;
|
continue;
|
||||||
|
} else {
|
||||||
|
is_visual = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// transform element aabb to aamm format
|
// transform element aabb to aamm format
|
||||||
@@ -360,6 +363,11 @@ int mjCBoundingVolumeHierarchy::MakeBVH(std::vector<const mjCBoundingVolume*>& e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a body with only visual geoms does not have a bvh
|
||||||
|
if (is_visual) {
|
||||||
|
return nbvh;
|
||||||
|
}
|
||||||
|
|
||||||
// inflate flat AABBs
|
// inflate flat AABBs
|
||||||
for (int i=0; i<3; i++) {
|
for (int i=0; i<3; i++) {
|
||||||
if (mju_abs(AAMM[i]-AAMM[i+3])<mjEPS) {
|
if (mju_abs(AAMM[i]-AAMM[i+3])<mjEPS) {
|
||||||
@@ -1088,6 +1096,18 @@ void mjCBody::Compile(void) {
|
|||||||
throw mjCError(this, "plugin '%s' does not support passive forces", plugin->name);
|
throw mjCError(this, "plugin '%s' does not support passive forces", plugin->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!model->discardvisual) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set inertial to explicit for bodies containing visual geoms
|
||||||
|
for (int j=0; j<geoms.size(); j++) {
|
||||||
|
if (geoms[j]->IsVisual()) {
|
||||||
|
explicitinertial = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1350,6 +1370,7 @@ mjCGeom::mjCGeom(mjCModel* _model, mjCDef* _def) {
|
|||||||
matid = -1;
|
matid = -1;
|
||||||
mesh = nullptr;
|
mesh = nullptr;
|
||||||
hfield = nullptr;
|
hfield = nullptr;
|
||||||
|
visual_ = false;
|
||||||
|
|
||||||
// reset to default if given
|
// reset to default if given
|
||||||
if (_def) {
|
if (_def) {
|
||||||
@@ -1737,6 +1758,9 @@ void mjCGeom::Compile(void) {
|
|||||||
name.c_str(), id);
|
name.c_str(), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if can collide
|
||||||
|
visual_ = !contype && !conaffinity;
|
||||||
|
|
||||||
// normalize quaternion
|
// normalize quaternion
|
||||||
mjuu_normvec(quat, 4);
|
mjuu_normvec(quat, 4);
|
||||||
|
|
||||||
@@ -3145,7 +3169,9 @@ mjCPair::mjCPair(mjCModel* _model, mjCDef* _def) {
|
|||||||
friction[4] = 0.0001;
|
friction[4] = 0.0001;
|
||||||
|
|
||||||
// clear internal variables
|
// clear internal variables
|
||||||
geom1 = geom2 = signature = -1;
|
geom1 = nullptr;
|
||||||
|
geom2 = nullptr;
|
||||||
|
signature = -1;
|
||||||
|
|
||||||
// reset to default if given
|
// reset to default if given
|
||||||
if (_def) {
|
if (_def) {
|
||||||
@@ -3167,46 +3193,48 @@ void mjCPair::Compile(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find geom 1
|
// find geom 1
|
||||||
mjCGeom* pg1 = (mjCGeom*)model->FindObject(mjOBJ_GEOM, geomname1);
|
geom1 = (mjCGeom*)model->FindObject(mjOBJ_GEOM, geomname1);
|
||||||
if (!pg1) {
|
if (!geom1) {
|
||||||
throw mjCError(this, "geom '%s' not found in collision %d", geomname1.c_str(), id);
|
throw mjCError(this, "geom '%s' not found in collision %d", geomname1.c_str(), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// find geom 2
|
// find geom 2
|
||||||
mjCGeom* pg2 = (mjCGeom*)model->FindObject(mjOBJ_GEOM, geomname2);
|
geom2 = (mjCGeom*)model->FindObject(mjOBJ_GEOM, geomname2);
|
||||||
if (!pg2) {
|
if (!geom2) {
|
||||||
throw mjCError(this, "geom '%s' not found in collision %d", geomname2.c_str(), id);
|
throw mjCError(this, "geom '%s' not found in collision %d", geomname2.c_str(), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark geoms as not visual
|
||||||
|
geom1->SetNotVisual();
|
||||||
|
geom2->SetNotVisual();
|
||||||
|
|
||||||
// swap if body1 > body2
|
// swap if body1 > body2
|
||||||
if (pg1->body->id > pg2->body->id) {
|
if (geom1->body->id > geom2->body->id) {
|
||||||
string nametmp = geomname1;
|
string nametmp = geomname1;
|
||||||
geomname1 = geomname2;
|
geomname1 = geomname2;
|
||||||
geomname2 = nametmp;
|
geomname2 = nametmp;
|
||||||
|
|
||||||
mjCGeom* geomtmp = pg1;
|
mjCGeom* geomtmp = geom1;
|
||||||
pg1 = pg2;
|
geom1 = geom2;
|
||||||
pg2 = geomtmp;
|
geom2 = geomtmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get geom ids and body signature
|
// get geom ids and body signature
|
||||||
geom1 = pg1->id;
|
signature = ((geom1->body->id)<<16) + geom2->body->id;
|
||||||
geom2 = pg2->id;
|
|
||||||
signature = ((pg1->body->id)<<16) + pg2->body->id;
|
|
||||||
|
|
||||||
// set undefined margin: max
|
// set undefined margin: max
|
||||||
if (!mjuu_defined(margin)) {
|
if (!mjuu_defined(margin)) {
|
||||||
margin = mjMAX(pg1->margin, pg2->margin);
|
margin = mjMAX(geom1->margin, geom2->margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set undefined gap: max
|
// set undefined gap: max
|
||||||
if (!mjuu_defined(gap)) {
|
if (!mjuu_defined(gap)) {
|
||||||
gap = mjMAX(pg1->gap, pg2->gap);
|
gap = mjMAX(geom1->gap, geom2->gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set undefined condim, friction, solref, solimp: different priority
|
// set undefined condim, friction, solref, solimp: different priority
|
||||||
if (pg1->priority!=pg2->priority) {
|
if (geom1->priority!=geom2->priority) {
|
||||||
mjCGeom* pgh = (pg1->priority>pg2->priority ? pg1 : pg2);
|
mjCGeom* pgh = (geom1->priority>geom2->priority ? geom1 : geom2);
|
||||||
|
|
||||||
// condim
|
// condim
|
||||||
if (condim<0) {
|
if (condim<0) {
|
||||||
@@ -3239,23 +3267,23 @@ void mjCPair::Compile(void) {
|
|||||||
else {
|
else {
|
||||||
// condim: max
|
// condim: max
|
||||||
if (condim<0) {
|
if (condim<0) {
|
||||||
condim = mjMAX(pg1->condim, pg2->condim);
|
condim = mjMAX(geom1->condim, geom2->condim);
|
||||||
}
|
}
|
||||||
|
|
||||||
// friction: max
|
// friction: max
|
||||||
if (!mjuu_defined(friction[0])) {
|
if (!mjuu_defined(friction[0])) {
|
||||||
friction[0] = friction[1] = mju_max(pg1->friction[0], pg2->friction[0]);
|
friction[0] = friction[1] = mju_max(geom1->friction[0], geom2->friction[0]);
|
||||||
friction[2] = mju_max(pg1->friction[1], pg2->friction[1]);
|
friction[2] = mju_max(geom1->friction[1], geom2->friction[1]);
|
||||||
friction[3] = friction[4] = mju_max(pg1->friction[2], pg2->friction[2]);
|
friction[3] = friction[4] = mju_max(geom1->friction[2], geom2->friction[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// solver mix factor
|
// solver mix factor
|
||||||
double mix;
|
double mix;
|
||||||
if (pg1->solmix>=mjMINVAL && pg2->solmix>=mjMINVAL) {
|
if (geom1->solmix>=mjMINVAL && geom2->solmix>=mjMINVAL) {
|
||||||
mix = pg1->solmix / (pg1->solmix + pg2->solmix);
|
mix = geom1->solmix / (geom1->solmix + geom2->solmix);
|
||||||
} else if (pg1->solmix<mjMINVAL && pg2->solmix<mjMINVAL) {
|
} else if (geom1->solmix<mjMINVAL && geom2->solmix<mjMINVAL) {
|
||||||
mix = 0.5;
|
mix = 0.5;
|
||||||
} else if (pg1->solmix<mjMINVAL) {
|
} else if (geom1->solmix<mjMINVAL) {
|
||||||
mix = 0.0;
|
mix = 0.0;
|
||||||
} else {
|
} else {
|
||||||
mix = 1.0;
|
mix = 1.0;
|
||||||
@@ -3266,14 +3294,14 @@ void mjCPair::Compile(void) {
|
|||||||
// standard: mix
|
// standard: mix
|
||||||
if (solref[0]>0) {
|
if (solref[0]>0) {
|
||||||
for (int i=0; i<mjNREF; i++) {
|
for (int i=0; i<mjNREF; i++) {
|
||||||
solref[i] = mix*pg1->solref[i] + (1-mix)*pg2->solref[i];
|
solref[i] = mix*geom1->solref[i] + (1-mix)*geom2->solref[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// direct: min
|
// direct: min
|
||||||
else {
|
else {
|
||||||
for (int i=0; i<mjNREF; i++) {
|
for (int i=0; i<mjNREF; i++) {
|
||||||
solref[i] = mju_min(pg1->solref[i], pg2->solref[i]);
|
solref[i] = mju_min(geom1->solref[i], geom2->solref[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3281,7 +3309,7 @@ void mjCPair::Compile(void) {
|
|||||||
// impedance
|
// impedance
|
||||||
if (!mjuu_defined(solimp[0])) {
|
if (!mjuu_defined(solimp[0])) {
|
||||||
for (int i=0; i<mjNIMP; i++) {
|
for (int i=0; i<mjNIMP; i++) {
|
||||||
solimp[i] = mix*pg1->solimp[i] + (1-mix)*pg2->solimp[i];
|
solimp[i] = mix*geom1->solimp[i] + (1-mix)*geom2->solimp[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3666,6 +3694,9 @@ void mjCTendon::Compile(void) {
|
|||||||
"tendon '%s' (id = %d): geom at pos %d not bracketed by sites",
|
"tendon '%s' (id = %d): geom at pos %d not bracketed by sites",
|
||||||
name.c_str(), id, i);
|
name.c_str(), id, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark geoms as non visual
|
||||||
|
model->geoms[path[i]->obj->id]->SetNotVisual();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case mjWRAP_JOINT:
|
case mjWRAP_JOINT:
|
||||||
@@ -4107,6 +4138,11 @@ void mjCSensor::Compile(void) {
|
|||||||
name.c_str(), id);
|
name.c_str(), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if geom mark it as non visual
|
||||||
|
if (objtype == mjOBJ_GEOM) {
|
||||||
|
((mjCGeom*)obj)->SetNotVisual();
|
||||||
|
}
|
||||||
|
|
||||||
// get sensorized object id
|
// get sensorized object id
|
||||||
} else if (type != mjSENS_CLOCK && type != mjSENS_PLUGIN && type != mjSENS_USER) {
|
} else if (type != mjSENS_CLOCK && type != mjSENS_PLUGIN && type != mjSENS_USER) {
|
||||||
throw mjCError(this, "invalid type in sensor '%s' (id = %d)", name.c_str(), id);
|
throw mjCError(this, "invalid type in sensor '%s' (id = %d)", name.c_str(), id);
|
||||||
@@ -4579,6 +4615,11 @@ void mjCTuple::Compile(void) {
|
|||||||
throw mjCError(this, "unrecognized object '%s' in tuple %d", objname[i].c_str(), id);
|
throw mjCError(this, "unrecognized object '%s' in tuple %d", objname[i].c_str(), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if geom mark it as non visual
|
||||||
|
if (objtype[i] == mjOBJ_GEOM) {
|
||||||
|
((mjCGeom*)res)->SetNotVisual();
|
||||||
|
}
|
||||||
|
|
||||||
// assign id
|
// assign id
|
||||||
obj[i] = res;
|
obj[i] = res;
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-3
@@ -381,6 +381,8 @@ class mjCGeom : public mjCBase {
|
|||||||
public:
|
public:
|
||||||
double GetVolume(void); // compute geom volume
|
double GetVolume(void); // compute geom volume
|
||||||
void SetInertia(void); // compute and set geom inertia
|
void SetInertia(void); // compute and set geom inertia
|
||||||
|
bool IsVisual(void) const { return visual_; }
|
||||||
|
void SetNotVisual(void) { visual_ = false; }
|
||||||
|
|
||||||
// Compute all coefs modeling the interaction with the surrounding fluid.
|
// Compute all coefs modeling the interaction with the surrounding fluid.
|
||||||
void SetFluidCoefs(void);
|
void SetFluidCoefs(void);
|
||||||
@@ -432,6 +434,7 @@ class mjCGeom : public mjCBase {
|
|||||||
double GetRBound(void); // compute bounding sphere radius
|
double GetRBound(void); // compute bounding sphere radius
|
||||||
void ComputeAABB(void); // compute axis-aligned bounding box
|
void ComputeAABB(void); // compute axis-aligned bounding box
|
||||||
|
|
||||||
|
bool visual_; // true: geom does not collide and is unreferenced
|
||||||
int matid; // id of geom's material
|
int matid; // id of geom's material
|
||||||
mjCMesh* mesh; // geom's mesh
|
mjCMesh* mesh; // geom's mesh
|
||||||
mjCHField* hfield; // geom's hfield
|
mjCHField* hfield; // geom's hfield
|
||||||
@@ -591,6 +594,9 @@ class mjCFlex: public mjCBase {
|
|||||||
std::vector<int> elem; // element vertex ids
|
std::vector<int> elem; // element vertex ids
|
||||||
std::vector<float> texcoord; // vertex texture coordinates
|
std::vector<float> texcoord; // vertex texture coordinates
|
||||||
|
|
||||||
|
bool HasTexcoord() const; // texcoord not null
|
||||||
|
void DelTexcoord(); // delete texcoord
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mjCFlex(mjCModel* = 0); // constructor
|
mjCFlex(mjCModel* = 0); // constructor
|
||||||
void Compile(const mjVFS* vfs); // compiler
|
void Compile(const mjVFS* vfs); // compiler
|
||||||
@@ -680,6 +686,9 @@ class mjCMesh: public mjCBase {
|
|||||||
double& GetVolumeRef(mjtMeshType type); // get volume
|
double& GetVolumeRef(mjtMeshType type); // get volume
|
||||||
void FitGeom(mjCGeom* geom, double* meshpos); // approximate mesh with simple geom
|
void FitGeom(mjCGeom* geom, double* meshpos); // approximate mesh with simple geom
|
||||||
bool HasTexcoord() const; // texcoord not null
|
bool HasTexcoord() const; // texcoord not null
|
||||||
|
void DelTexcoord(); // delete texcoord
|
||||||
|
bool IsVisual(void) const { return visual_; } // is geom visual
|
||||||
|
void SetNotVisual(void) { visual_ = false; } // mark mesh as not visual
|
||||||
|
|
||||||
void CopyVert(float* arr) const; // copy vert data into array
|
void CopyVert(float* arr) const; // copy vert data into array
|
||||||
void CopyNormal(float* arr) const; // copy normal data into array
|
void CopyNormal(float* arr) const; // copy normal data into array
|
||||||
@@ -693,6 +702,7 @@ class mjCMesh: public mjCBase {
|
|||||||
void SetBoundingVolume(int faceid);
|
void SetBoundingVolume(int faceid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool visual_; // true: the mesh is only visual
|
||||||
std::string content_type_; // content type of file
|
std::string content_type_; // content type of file
|
||||||
std::string file_; // mesh file
|
std::string file_; // mesh file
|
||||||
double refpos_[3]; // reference position (translate)
|
double refpos_[3]; // reference position (translate)
|
||||||
@@ -847,6 +857,8 @@ class mjCTexture : public mjCBase {
|
|||||||
friend class mjXWriter;
|
friend class mjXWriter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
~mjCTexture(); // destructor
|
||||||
|
|
||||||
std::string get_file() const { return file; }
|
std::string get_file() const { return file; }
|
||||||
|
|
||||||
mjtTexture type; // texture type
|
mjtTexture type; // texture type
|
||||||
@@ -876,7 +888,6 @@ class mjCTexture : public mjCBase {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
mjCTexture(mjCModel*); // constructor
|
mjCTexture(mjCModel*); // constructor
|
||||||
~mjCTexture(); // destructior
|
|
||||||
void Compile(const mjVFS* vfs); // compiler
|
void Compile(const mjVFS* vfs); // compiler
|
||||||
|
|
||||||
void Builtin2D(void); // make builtin 2D
|
void Builtin2D(void); // make builtin 2D
|
||||||
@@ -959,8 +970,8 @@ class mjCPair : public mjCBase {
|
|||||||
mjCPair(mjCModel* = 0, mjCDef* = 0); // constructor
|
mjCPair(mjCModel* = 0, mjCDef* = 0); // constructor
|
||||||
void Compile(void); // compiler
|
void Compile(void); // compiler
|
||||||
|
|
||||||
int geom1; // id of geom1
|
mjCGeom* geom1; // geom1
|
||||||
int geom2; // id of geom2
|
mjCGeom* geom2; // geom2
|
||||||
int signature; // body1<<16 + body2
|
int signature; // body1<<16 + body2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3019,12 +3019,6 @@ void mjXReader::Body(XMLElement* section, mjCBody* pbody, mjCFrame* frame) {
|
|||||||
mjCGeom* pgeom = pbody->AddGeom(def);
|
mjCGeom* pgeom = pbody->AddGeom(def);
|
||||||
OneGeom(elem, pgeom);
|
OneGeom(elem, pgeom);
|
||||||
pgeom->SetFrame(frame);
|
pgeom->SetFrame(frame);
|
||||||
|
|
||||||
// discard visual
|
|
||||||
if (!pgeom->contype && !pgeom->conaffinity && model->discardvisual) {
|
|
||||||
delete pbody->geoms.back();
|
|
||||||
pbody->geoms.pop_back();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// site sub-element
|
// site sub-element
|
||||||
|
|||||||
Vendored
+73
@@ -0,0 +1,73 @@
|
|||||||
|
<mujoco>
|
||||||
|
<compiler discardvisual="true"/>
|
||||||
|
|
||||||
|
<asset>
|
||||||
|
<texture name="discarded_skybox" type="skybox" builtin="gradient"
|
||||||
|
rgb1=".3 .5 .7" rgb2="0 0 0" width="32" height="512"/>
|
||||||
|
|
||||||
|
<texture name="discarded" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
|
||||||
|
<material name="discarded" texture="discarded" texrepeat="1 1" texuniform="true" reflectance=".2"/>
|
||||||
|
|
||||||
|
<mesh name="kept" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||||
|
<mesh name="discarded0" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||||
|
<mesh name="discarded1" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||||
|
</asset>
|
||||||
|
|
||||||
|
<worldbody>
|
||||||
|
<geom name="kept_floor" size="0 0 .05" type="plane" material="discarded"/>
|
||||||
|
|
||||||
|
<body pos="0 0 -.5">
|
||||||
|
<freejoint/>
|
||||||
|
<geom name="discarded0" type="mesh" mesh="discarded0" contype="0" conaffinity="0"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<site name="tendon0" pos=".1 0 1.5"/>
|
||||||
|
<geom name="kept_tendon" size="0.2" contype="0" conaffinity="0" pos="0 0 1"/>
|
||||||
|
<body pos=".1 0 -.5">
|
||||||
|
<site name="tendon1" pos="0 0 1"/>
|
||||||
|
<freejoint/>
|
||||||
|
<geom name="discarded1" type="mesh" mesh="kept" contype="0" conaffinity="0"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body pos=".2 0 -.5">
|
||||||
|
<geom name="kept0" type="mesh" mesh="kept"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body pos=".3 0 -.5">
|
||||||
|
<freejoint/>
|
||||||
|
<geom name="kept1" type="mesh" mesh="kept"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body pos=".4 0 -.5">
|
||||||
|
<geom name="discarded2" type="mesh" mesh="kept" contype="0" conaffinity="0"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<geom name="kept_sensor" size="0.2" contype="0" conaffinity="0"/>
|
||||||
|
|
||||||
|
<geom name="kept_pair" size="0.2" contype="0" conaffinity="0" pos=".3 0 .4"/>
|
||||||
|
|
||||||
|
<geom name="kept_tuple" size="0.2" contype="0" conaffinity="0"/>
|
||||||
|
</worldbody>
|
||||||
|
|
||||||
|
<contact>
|
||||||
|
<pair geom1="kept1" geom2="kept_pair"/>
|
||||||
|
</contact>
|
||||||
|
|
||||||
|
<tendon>
|
||||||
|
<spatial range="0 1">
|
||||||
|
<site site="tendon0"/>
|
||||||
|
<geom geom="kept_tendon"/>
|
||||||
|
<site site="tendon1"/>
|
||||||
|
</spatial>
|
||||||
|
</tendon>
|
||||||
|
|
||||||
|
<sensor>
|
||||||
|
<framepos objtype="geom" objname="kept_sensor"/>
|
||||||
|
</sensor>
|
||||||
|
|
||||||
|
<custom>
|
||||||
|
<tuple name="tuple">
|
||||||
|
<element objtype="geom" objname="kept_tuple"/>
|
||||||
|
</tuple>
|
||||||
|
</custom>
|
||||||
|
</mujoco>
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
<mujoco>
|
||||||
|
<compiler discardvisual="false"/>
|
||||||
|
|
||||||
|
<asset>
|
||||||
|
<texture name="discarded_skybox" type="skybox" builtin="gradient"
|
||||||
|
rgb1=".3 .5 .7" rgb2="0 0 0" width="32" height="512"/>
|
||||||
|
|
||||||
|
<texture name="discarded" type="2d" builtin="checker" width="512" height="512" rgb1=".1 .2 .3" rgb2=".2 .3 .4"/>
|
||||||
|
<material name="discarded" texture="discarded" texrepeat="1 1" texuniform="true" reflectance=".2"/>
|
||||||
|
|
||||||
|
<mesh name="kept" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||||
|
<mesh name="discarded0" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||||
|
<mesh name="discarded1" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||||
|
</asset>
|
||||||
|
|
||||||
|
<worldbody>
|
||||||
|
<geom name="kept_floor" size="0 0 .05" type="plane" material="discarded"/>
|
||||||
|
|
||||||
|
<body pos="0 0 -.5">
|
||||||
|
<freejoint/>
|
||||||
|
<geom name="discarded0" type="mesh" mesh="discarded0" contype="0" conaffinity="0"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<site name="tendon0" pos=".1 0 1.5"/>
|
||||||
|
<geom name="kept_tendon" size="0.2" contype="0" conaffinity="0" pos="0 0 1"/>
|
||||||
|
<body pos=".1 0 -.5">
|
||||||
|
<site name="tendon1" pos="0 0 1"/>
|
||||||
|
<freejoint/>
|
||||||
|
<geom name="discarded1" type="mesh" mesh="kept" contype="0" conaffinity="0"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body pos=".2 0 -.5">
|
||||||
|
<geom name="kept0" type="mesh" mesh="kept"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body pos=".3 0 -.5">
|
||||||
|
<freejoint/>
|
||||||
|
<geom name="kept1" type="mesh" mesh="kept"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<body pos=".4 0 -.5">
|
||||||
|
<geom name="discarded2" type="mesh" mesh="kept" contype="0" conaffinity="0"/>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<geom name="kept_sensor" size="0.2" contype="0" conaffinity="0"/>
|
||||||
|
|
||||||
|
<geom name="kept_pair" size="0.2" contype="0" conaffinity="0" pos=".3 0 .4"/>
|
||||||
|
|
||||||
|
<geom name="kept_tuple" size="0.2" contype="0" conaffinity="0"/>
|
||||||
|
</worldbody>
|
||||||
|
|
||||||
|
<contact>
|
||||||
|
<pair geom1="kept1" geom2="kept_pair"/>
|
||||||
|
</contact>
|
||||||
|
|
||||||
|
<tendon>
|
||||||
|
<spatial range="0 1">
|
||||||
|
<site site="tendon0"/>
|
||||||
|
<geom geom="kept_tendon"/>
|
||||||
|
<site site="tendon1"/>
|
||||||
|
</spatial>
|
||||||
|
</tendon>
|
||||||
|
|
||||||
|
<sensor>
|
||||||
|
<framepos objtype="geom" objname="kept_sensor"/>
|
||||||
|
</sensor>
|
||||||
|
|
||||||
|
<custom>
|
||||||
|
<tuple name="tuple">
|
||||||
|
<element objtype="geom" objname="kept_tuple"/>
|
||||||
|
</tuple>
|
||||||
|
</custom>
|
||||||
|
</mujoco>
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
// Tests for user/user_model.cc.
|
// Tests for user/user_model.cc.
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
@@ -283,5 +284,116 @@ TEST_F(FuseStaticTest, FuseStaticEquivalent) {
|
|||||||
mj_deleteModel(m_no_fuse);
|
mj_deleteModel(m_no_fuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------- test discardvisual --------------------------------------------
|
||||||
|
|
||||||
|
using DiscardVisualTest = MujocoTest;
|
||||||
|
TEST_F(DiscardVisualTest, DiscardVisualKeepsInertia) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<compiler discardvisual="true"/>
|
||||||
|
|
||||||
|
<asset>
|
||||||
|
<mesh name="visual_mesh"
|
||||||
|
vertex="0 0 0 1 0 0 0 1 0 0 0 1"
|
||||||
|
normal="1 0 0 0 1 0 0 0 1 0.707 0 0.707"
|
||||||
|
face="0 2 1 0 3 2" />
|
||||||
|
|
||||||
|
<mesh name="collision_mesh"
|
||||||
|
vertex="0 0 0 1 0 0 0 1 0 0 0 1"
|
||||||
|
normal="1 0 0 0 1 0 0 0 1 0.707 0 0.707"
|
||||||
|
face="0 2 1 0 3 2" />
|
||||||
|
</asset>
|
||||||
|
|
||||||
|
<worldbody>
|
||||||
|
<body>
|
||||||
|
<geom type="mesh" mesh="visual_mesh" contype="0" conaffinity="0"/>
|
||||||
|
</body>
|
||||||
|
<body>
|
||||||
|
<geom type="mesh" mesh="collision_mesh"/>
|
||||||
|
</body>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
|
||||||
|
std::array<char, 1024> error;
|
||||||
|
mjModel* model = LoadModelFromString(xml, error.data(), error.size());
|
||||||
|
EXPECT_THAT(model, NotNull()) << error.data();
|
||||||
|
EXPECT_THAT(model->nmesh, 1);
|
||||||
|
EXPECT_THAT(model->body_inertia[3], model->body_inertia[6]);
|
||||||
|
EXPECT_THAT(model->body_inertia[4], model->body_inertia[7]);
|
||||||
|
EXPECT_THAT(model->body_inertia[5], model->body_inertia[8]);
|
||||||
|
mj_deleteModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DiscardVisualTest, DiscardVisualEquivalent) {
|
||||||
|
char error[1024];
|
||||||
|
size_t error_sz = 1024;
|
||||||
|
|
||||||
|
static const char* const kDiscardvisualPath =
|
||||||
|
"user/testdata/discardvisual.xml";
|
||||||
|
static const char* const kDiscardvisualFalsePath =
|
||||||
|
"user/testdata/discardvisual_false.xml";
|
||||||
|
|
||||||
|
const std::string xml_path1 = GetTestDataFilePath(kDiscardvisualPath);
|
||||||
|
mjModel* model1 = mj_loadXML(xml_path1.c_str(), 0, error, error_sz);
|
||||||
|
EXPECT_THAT(model1, NotNull()) << error;
|
||||||
|
|
||||||
|
const std::string xml_path2 = GetTestDataFilePath(kDiscardvisualFalsePath);
|
||||||
|
mjModel* model2 = mj_loadXML(xml_path2.c_str(), 0, error, error_sz);
|
||||||
|
EXPECT_THAT(model2, NotNull()) << error;
|
||||||
|
|
||||||
|
EXPECT_THAT(model1->nq, model2->nq);
|
||||||
|
EXPECT_THAT(model1->nmat, 0);
|
||||||
|
EXPECT_THAT(model1->ntex, 0);
|
||||||
|
EXPECT_THAT(model2->ngeom-model1->ngeom, 3);
|
||||||
|
EXPECT_THAT(model2->nmesh-model1->nmesh, 2);
|
||||||
|
EXPECT_THAT(model1->npair, model2->npair);
|
||||||
|
EXPECT_THAT(model1->nsensor, model2->nsensor);
|
||||||
|
EXPECT_THAT(model1->nwrap, model2->nwrap);
|
||||||
|
|
||||||
|
for (int i = 0; i < model1->ngeom; i++) {
|
||||||
|
std::string name = std::string(model1->names + model1->name_geomadr[i]);
|
||||||
|
EXPECT_NE(name.find("kept"), std::string::npos);
|
||||||
|
EXPECT_EQ(name.find("discard"), std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < model1->npair; i++) {
|
||||||
|
int adr1 = model1->name_geomadr[model1->pair_geom1[i]];
|
||||||
|
int adr2 = model2->name_geomadr[model2->pair_geom1[i]];
|
||||||
|
EXPECT_STREQ(model1->names + adr1, model2->names + adr2);
|
||||||
|
adr1 = model1->name_geomadr[model1->pair_geom2[i]];
|
||||||
|
adr2 = model2->name_geomadr[model2->pair_geom2[i]];
|
||||||
|
EXPECT_STREQ(model1->names + adr1, model2->names + adr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < model1->nsensor; i++) {
|
||||||
|
int adr1 = model1->name_geomadr[model1->sensor_objid[i]];
|
||||||
|
int adr2 = model2->name_geomadr[model2->sensor_objid[i]];
|
||||||
|
EXPECT_STREQ(model1->names + adr1, model2->names + adr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < model1->nwrap; i++) {
|
||||||
|
int adr1 = model1->name_geomadr[model1->wrap_objid[i]];
|
||||||
|
int adr2 = model2->name_geomadr[model2->wrap_objid[i]];
|
||||||
|
EXPECT_STREQ(model1->names + adr1, model2->names + adr2);
|
||||||
|
}
|
||||||
|
|
||||||
|
mjData *d1 = mj_makeData(model1);
|
||||||
|
mjData *d2 = mj_makeData(model2);
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
mj_step(model1, d1);
|
||||||
|
mj_step(model2, d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < model1->nq; i++) {
|
||||||
|
EXPECT_THAT(d1->qpos[i], d2->qpos[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mj_deleteModel(model1);
|
||||||
|
mj_deleteModel(model2);
|
||||||
|
mj_deleteData(d1);
|
||||||
|
mj_deleteData(d2);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace mujoco
|
} // namespace mujoco
|
||||||
|
|||||||
Reference in New Issue
Block a user