Remove all visual-only assets if discardvisual is selected, not only the geoms.

PiperOrigin-RevId: 598598250
Change-Id: I12e60ce41ad436d037b4877d197decf6bdce0fc8
This commit is contained in:
Alessio Quaglino
2024-01-15 06:38:11 -08:00
committed by Copybara-Service
parent acf698e2df
commit 1e2e0b3053
11 changed files with 557 additions and 65 deletions
+17
View File
@@ -166,6 +166,7 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) {
valideigenvalue_ = true;
validinequality_ = true;
processed_ = false;
visual_ = true;
// reset to default if given
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
void mjCMesh::FitGeom(mjCGeom* geom, double* 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
void mjCFlex::Compile(const mjVFS* vfs) {
+157 -6
View File
@@ -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
void mjCModel::IndexAssets(void) {
void mjCModel::IndexAssets(bool discard) {
// assets referenced in geoms
for (int i=0; i<geoms.size(); i++) {
mjCGeom* pgeom = geoms[i];
@@ -670,7 +787,19 @@ void mjCModel::IndexAssets(void) {
if (!pgeom->meshname.empty()) {
mjCBase* m = FindObject(mjOBJ_MESH, pgeom->meshname);
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 {
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
for (int i=0; i<npair; i++) {
m->pair_dim[i] = pairs[i]->condim;
m->pair_geom1[i] = pairs[i]->geom1;
m->pair_geom2[i] = pairs[i]->geom2;
m->pair_geom1[i] = pairs[i]->geom1->id;
m->pair_geom2[i] = pairs[i]->geom2->id;
m->pair_signature[i] = pairs[i]->signature;
copyvec(m->pair_solref+mjNREF*i, pairs[i]->solref, 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
IndexAssets();
IndexAssets(false);
// mark meshes that need convex hull
for (int i=0; i<geoms.size(); i++) {
@@ -2811,7 +2962,7 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
reassignid(excludes);
// resolve asset references, compute sizes
IndexAssets();
IndexAssets(discardvisual);
SetSizes();
// fuse static if enabled
if (fusestatic) {
+18 -10
View File
@@ -96,6 +96,14 @@ class mjCModel {
mjCKey* AddKey(void); // keyframe
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)
int NumObjects(mjtObj type); // number of objects in specified list
mjCBase* GetObject(mjtObj type, int id); // pointer to specified object
@@ -185,16 +193,16 @@ class mjCModel {
void SetDefaultNames(std::vector<T*>& assets);
//------------------------ compile phases
void MakeLists(mjCBody* body); // make lists of bodies, geoms, joints, sites
void IndexAssets(void); // convert asset names into indices
void CheckEmptyNames(void); // check empty names
void SetSizes(void); // compute sizes
void AutoSpringDamper(mjModel*);// automatic stiffness and damping computation
void LengthRange(mjModel*, mjData*); // compute actuator lengthrange
void CopyNames(mjModel*); // copy names, compute name addresses
void CopyPaths(mjModel*); // copy paths, compute path addresses
void CopyObjects(mjModel*); // copy objects outside kinematic tree
void CopyTree(mjModel*); // copy objects inside kinematic tree
void MakeLists(mjCBody* body); // make lists of bodies, geoms, joints, sites
void IndexAssets(bool discard); // convert asset names into indices
void CheckEmptyNames(void); // check empty names
void SetSizes(void); // compute sizes
void AutoSpringDamper(mjModel*); // automatic stiffness and damping computation
void LengthRange(mjModel*, mjData*); // compute actuator lengthrange
void CopyNames(mjModel*); // copy names, compute name addresses
void CopyPaths(mjModel*); // copy paths, compute path addresses
void CopyObjects(mjModel*); // copy objects outside kinematic tree
void CopyTree(mjModel*); // copy objects inside kinematic tree
//------------------------ sizes
// sizes set from object list lengths
+68 -27
View File
@@ -314,6 +314,7 @@ int mjCBoundingVolumeHierarchy::MakeBVH(std::vector<const mjCBoundingVolume*>& e
return -1;
}
bool is_visual = true;
int nelements = elements.size();
mjtNum AAMM[6] = {mjMAXVAL, mjMAXVAL, mjMAXVAL, -mjMAXVAL, -mjMAXVAL, -mjMAXVAL};
@@ -325,6 +326,8 @@ int mjCBoundingVolumeHierarchy::MakeBVH(std::vector<const mjCBoundingVolume*>& e
// skip visual objects
if (elements[i]->conaffinity==0 && elements[i]->contype==0) {
continue;
} else {
is_visual = false;
}
// 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
for (int i=0; i<3; i++) {
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);
}
}
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;
mesh = nullptr;
hfield = nullptr;
visual_ = false;
// reset to default if given
if (_def) {
@@ -1737,6 +1758,9 @@ void mjCGeom::Compile(void) {
name.c_str(), id);
}
// check if can collide
visual_ = !contype && !conaffinity;
// normalize quaternion
mjuu_normvec(quat, 4);
@@ -3145,7 +3169,9 @@ mjCPair::mjCPair(mjCModel* _model, mjCDef* _def) {
friction[4] = 0.0001;
// clear internal variables
geom1 = geom2 = signature = -1;
geom1 = nullptr;
geom2 = nullptr;
signature = -1;
// reset to default if given
if (_def) {
@@ -3167,46 +3193,48 @@ void mjCPair::Compile(void) {
}
// find geom 1
mjCGeom* pg1 = (mjCGeom*)model->FindObject(mjOBJ_GEOM, geomname1);
if (!pg1) {
geom1 = (mjCGeom*)model->FindObject(mjOBJ_GEOM, geomname1);
if (!geom1) {
throw mjCError(this, "geom '%s' not found in collision %d", geomname1.c_str(), id);
}
// find geom 2
mjCGeom* pg2 = (mjCGeom*)model->FindObject(mjOBJ_GEOM, geomname2);
if (!pg2) {
geom2 = (mjCGeom*)model->FindObject(mjOBJ_GEOM, geomname2);
if (!geom2) {
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
if (pg1->body->id > pg2->body->id) {
if (geom1->body->id > geom2->body->id) {
string nametmp = geomname1;
geomname1 = geomname2;
geomname2 = nametmp;
mjCGeom* geomtmp = pg1;
pg1 = pg2;
pg2 = geomtmp;
mjCGeom* geomtmp = geom1;
geom1 = geom2;
geom2 = geomtmp;
}
// get geom ids and body signature
geom1 = pg1->id;
geom2 = pg2->id;
signature = ((pg1->body->id)<<16) + pg2->body->id;
signature = ((geom1->body->id)<<16) + geom2->body->id;
// set undefined margin: max
if (!mjuu_defined(margin)) {
margin = mjMAX(pg1->margin, pg2->margin);
margin = mjMAX(geom1->margin, geom2->margin);
}
// set undefined gap: max
if (!mjuu_defined(gap)) {
gap = mjMAX(pg1->gap, pg2->gap);
gap = mjMAX(geom1->gap, geom2->gap);
}
// set undefined condim, friction, solref, solimp: different priority
if (pg1->priority!=pg2->priority) {
mjCGeom* pgh = (pg1->priority>pg2->priority ? pg1 : pg2);
if (geom1->priority!=geom2->priority) {
mjCGeom* pgh = (geom1->priority>geom2->priority ? geom1 : geom2);
// condim
if (condim<0) {
@@ -3239,23 +3267,23 @@ void mjCPair::Compile(void) {
else {
// condim: max
if (condim<0) {
condim = mjMAX(pg1->condim, pg2->condim);
condim = mjMAX(geom1->condim, geom2->condim);
}
// friction: max
if (!mjuu_defined(friction[0])) {
friction[0] = friction[1] = mju_max(pg1->friction[0], pg2->friction[0]);
friction[2] = mju_max(pg1->friction[1], pg2->friction[1]);
friction[3] = friction[4] = mju_max(pg1->friction[2], pg2->friction[2]);
friction[0] = friction[1] = mju_max(geom1->friction[0], geom2->friction[0]);
friction[2] = mju_max(geom1->friction[1], geom2->friction[1]);
friction[3] = friction[4] = mju_max(geom1->friction[2], geom2->friction[2]);
}
// solver mix factor
double mix;
if (pg1->solmix>=mjMINVAL && pg2->solmix>=mjMINVAL) {
mix = pg1->solmix / (pg1->solmix + pg2->solmix);
} else if (pg1->solmix<mjMINVAL && pg2->solmix<mjMINVAL) {
if (geom1->solmix>=mjMINVAL && geom2->solmix>=mjMINVAL) {
mix = geom1->solmix / (geom1->solmix + geom2->solmix);
} else if (geom1->solmix<mjMINVAL && geom2->solmix<mjMINVAL) {
mix = 0.5;
} else if (pg1->solmix<mjMINVAL) {
} else if (geom1->solmix<mjMINVAL) {
mix = 0.0;
} else {
mix = 1.0;
@@ -3266,14 +3294,14 @@ void mjCPair::Compile(void) {
// standard: mix
if (solref[0]>0) {
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
else {
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
if (!mjuu_defined(solimp[0])) {
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",
name.c_str(), id, i);
}
// mark geoms as non visual
model->geoms[path[i]->obj->id]->SetNotVisual();
break;
case mjWRAP_JOINT:
@@ -4107,6 +4138,11 @@ void mjCSensor::Compile(void) {
name.c_str(), id);
}
// if geom mark it as non visual
if (objtype == mjOBJ_GEOM) {
((mjCGeom*)obj)->SetNotVisual();
}
// get sensorized object id
} 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);
@@ -4579,6 +4615,11 @@ void mjCTuple::Compile(void) {
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
obj[i] = res;
}
+14 -3
View File
@@ -381,6 +381,8 @@ class mjCGeom : public mjCBase {
public:
double GetVolume(void); // compute geom volume
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.
void SetFluidCoefs(void);
@@ -432,6 +434,7 @@ class mjCGeom : public mjCBase {
double GetRBound(void); // compute bounding sphere radius
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
mjCMesh* mesh; // geom's mesh
mjCHField* hfield; // geom's hfield
@@ -591,6 +594,9 @@ class mjCFlex: public mjCBase {
std::vector<int> elem; // element vertex ids
std::vector<float> texcoord; // vertex texture coordinates
bool HasTexcoord() const; // texcoord not null
void DelTexcoord(); // delete texcoord
private:
mjCFlex(mjCModel* = 0); // constructor
void Compile(const mjVFS* vfs); // compiler
@@ -680,6 +686,9 @@ class mjCMesh: public mjCBase {
double& GetVolumeRef(mjtMeshType type); // get volume
void FitGeom(mjCGeom* geom, double* meshpos); // approximate mesh with simple geom
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 CopyNormal(float* arr) const; // copy normal data into array
@@ -693,6 +702,7 @@ class mjCMesh: public mjCBase {
void SetBoundingVolume(int faceid);
private:
bool visual_; // true: the mesh is only visual
std::string content_type_; // content type of file
std::string file_; // mesh file
double refpos_[3]; // reference position (translate)
@@ -847,6 +857,8 @@ class mjCTexture : public mjCBase {
friend class mjXWriter;
public:
~mjCTexture(); // destructor
std::string get_file() const { return file; }
mjtTexture type; // texture type
@@ -876,7 +888,6 @@ class mjCTexture : public mjCBase {
private:
mjCTexture(mjCModel*); // constructor
~mjCTexture(); // destructior
void Compile(const mjVFS* vfs); // compiler
void Builtin2D(void); // make builtin 2D
@@ -959,8 +970,8 @@ class mjCPair : public mjCBase {
mjCPair(mjCModel* = 0, mjCDef* = 0); // constructor
void Compile(void); // compiler
int geom1; // id of geom1
int geom2; // id of geom2
mjCGeom* geom1; // geom1
mjCGeom* geom2; // geom2
int signature; // body1<<16 + body2
};
-6
View File
@@ -3019,12 +3019,6 @@ void mjXReader::Body(XMLElement* section, mjCBody* pbody, mjCFrame* frame) {
mjCGeom* pgeom = pbody->AddGeom(def);
OneGeom(elem, pgeom);
pgeom->SetFrame(frame);
// discard visual
if (!pgeom->contype && !pgeom->conaffinity && model->discardvisual) {
delete pbody->geoms.back();
pbody->geoms.pop_back();
}
}
// site sub-element