Store model paths in assets.
This enables to preserve the paths of the child spec during `attach`. PiperOrigin-RevId: 673349237 Change-Id: Ibf075c7ec037ff5d540bc60d6e77c12f60269791
This commit is contained in:
committed by
Copybara-Service
parent
cf721def3a
commit
567793c26f
@@ -72,6 +72,8 @@ Bug fixes
|
|||||||
integrators, wrong derivatives would be computed.
|
integrators, wrong derivatives would be computed.
|
||||||
- Fixed a bug in tendon wrapping around spheres. Before this fix, tendons that wrapped around spheres with an
|
- Fixed a bug in tendon wrapping around spheres. Before this fix, tendons that wrapped around spheres with an
|
||||||
externally-placed :ref:`sidesite<spatial-geom-sidesite>` could jump inside the sphere instead of wrapping around it.
|
externally-placed :ref:`sidesite<spatial-geom-sidesite>` could jump inside the sphere instead of wrapping around it.
|
||||||
|
- Fixed a bug that caused :at:`meshdir` and :at:`texturedir` to be overwritten during model
|
||||||
|
:ref:`attachment<meAttachment>.
|
||||||
|
|
||||||
Python bindings
|
Python bindings
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|||||||
+31
-4
@@ -72,6 +72,7 @@ extern "C" {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
using mujoco::user::VectorToString;
|
using mujoco::user::VectorToString;
|
||||||
|
using mujoco::user::FilePath;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// compute triangle area, surface normal, center
|
// compute triangle area, surface normal, center
|
||||||
@@ -218,6 +219,14 @@ void mjCMesh::PointToLocal() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void mjCMesh::NameSpace(const mjCModel* m) {
|
||||||
|
mjCBase::NameSpace(m);
|
||||||
|
modelfiledir_ = FilePath(m->spec_modelfiledir_);
|
||||||
|
meshdir_ = FilePath(m->spec_meshdir_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void mjCMesh::CopyFromSpec() {
|
void mjCMesh::CopyFromSpec() {
|
||||||
*static_cast<mjsMesh*>(this) = spec;
|
*static_cast<mjsMesh*>(this) = spec;
|
||||||
file_ = spec_file_;
|
file_ = spec_file_;
|
||||||
@@ -388,6 +397,14 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
facenormal_.clear();
|
facenormal_.clear();
|
||||||
facetexcoord_.clear();
|
facetexcoord_.clear();
|
||||||
|
|
||||||
|
// copy paths from model if not already defined
|
||||||
|
if (modelfiledir_.empty()) {
|
||||||
|
modelfiledir_ = FilePath(model->modelfiledir_);
|
||||||
|
}
|
||||||
|
if (meshdir_.empty()) {
|
||||||
|
meshdir_ = FilePath(model->meshdir_);
|
||||||
|
}
|
||||||
|
|
||||||
// remove path from file if necessary
|
// remove path from file if necessary
|
||||||
if (model->strippath) {
|
if (model->strippath) {
|
||||||
file_ = mjuu_strippath(file_);
|
file_ = mjuu_strippath(file_);
|
||||||
@@ -402,8 +419,8 @@ void mjCMesh::Compile(const mjVFS* vfs) {
|
|||||||
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
|
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string filename = mjuu_combinePaths(model->meshdir_, file_);
|
FilePath filename = meshdir_ + FilePath(file_);
|
||||||
resource = LoadResource(model->modelfiledir_, filename, vfs);
|
resource = LoadResource(modelfiledir_.Str(), filename.Str(), vfs);
|
||||||
|
|
||||||
// try loading from cache
|
// try loading from cache
|
||||||
if (cache != nullptr && LoadCachedMesh(cache, resource)) {
|
if (cache != nullptr && LoadCachedMesh(cache, resource)) {
|
||||||
@@ -2016,6 +2033,8 @@ void mjCSkin::NameSpace(const mjCModel* m) {
|
|||||||
for (auto& name : spec_bodyname_) {
|
for (auto& name : spec_bodyname_) {
|
||||||
name = m->prefix + name + m->suffix;
|
name = m->prefix + name + m->suffix;
|
||||||
}
|
}
|
||||||
|
modelfiledir_ = FilePath(m->spec_modelfiledir_);
|
||||||
|
meshdir_ = FilePath(m->spec_meshdir_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2097,8 +2116,16 @@ void mjCSkin::Compile(const mjVFS* vfs) {
|
|||||||
throw mjCError(this, "Unknown skin file type: %s", file_.c_str());
|
throw mjCError(this, "Unknown skin file type: %s", file_.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string filename = mjuu_combinePaths(model->meshdir_, file_);
|
// copy paths from model if not already defined
|
||||||
mjResource* resource = LoadResource(model->modelfiledir_, filename, vfs);
|
if (modelfiledir_.empty()) {
|
||||||
|
modelfiledir_ = FilePath(model->modelfiledir_);
|
||||||
|
}
|
||||||
|
if (meshdir_.empty()) {
|
||||||
|
meshdir_ = FilePath(model->meshdir_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath filename = meshdir_ + FilePath(file_);
|
||||||
|
mjResource* resource = LoadResource(modelfiledir_.Str(), filename.Str(), vfs);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LoadSKN(resource);
|
LoadSKN(resource);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
namespace mju = ::mujoco::util;
|
namespace mju = ::mujoco::util;
|
||||||
|
using mujoco::user::FilePath;
|
||||||
|
|
||||||
class PNGImage {
|
class PNGImage {
|
||||||
public:
|
public:
|
||||||
@@ -3402,6 +3403,14 @@ void mjCHField::CopyFromSpec() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void mjCHField::NameSpace(const mjCModel* m) {
|
||||||
|
mjCBase::NameSpace(m);
|
||||||
|
modelfiledir_ = FilePath(m->spec_modelfiledir_);
|
||||||
|
meshdir_ = FilePath(m->spec_meshdir_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// destructor
|
// destructor
|
||||||
mjCHField::~mjCHField() {
|
mjCHField::~mjCHField() {
|
||||||
data.clear();
|
data.clear();
|
||||||
@@ -3514,8 +3523,16 @@ void mjCHField::Compile(const mjVFS* vfs) {
|
|||||||
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
|
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string filename = mjuu_combinePaths(model->meshdir_, file_);
|
// copy paths from model if not already defined
|
||||||
mjResource* resource = LoadResource(model->modelfiledir_, filename, vfs);
|
if (modelfiledir_.empty()) {
|
||||||
|
modelfiledir_ = FilePath(model->modelfiledir_);
|
||||||
|
}
|
||||||
|
if (meshdir_.empty()) {
|
||||||
|
meshdir_ = FilePath(model->meshdir_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath filename = meshdir_ + FilePath(file_);
|
||||||
|
mjResource* resource = LoadResource(modelfiledir_.Str(), filename.Str(), vfs);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (asset_type == "image/png") {
|
if (asset_type == "image/png") {
|
||||||
@@ -3631,6 +3648,14 @@ void mjCTexture::CopyFromSpec() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void mjCTexture::NameSpace(const mjCModel* m) {
|
||||||
|
mjCBase::NameSpace(m);
|
||||||
|
modelfiledir_ = FilePath(m->spec_modelfiledir_);
|
||||||
|
texturedir_ = FilePath(m->spec_texturedir_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// free data storage allocated by lodepng
|
// free data storage allocated by lodepng
|
||||||
mjCTexture::~mjCTexture() {
|
mjCTexture::~mjCTexture() {
|
||||||
data_.clear();
|
data_.clear();
|
||||||
@@ -3960,7 +3985,7 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
|
|||||||
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
|
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
mjResource* resource = LoadResource(model->modelfiledir_, filename, vfs);
|
mjResource* resource = LoadResource(modelfiledir_.Str(), filename, vfs);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (asset_type == "image/png") {
|
if (asset_type == "image/png") {
|
||||||
@@ -4176,12 +4201,12 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make filename
|
// make filename
|
||||||
std::string filename = mjuu_combinePaths(model->texturedir_, cubefiles_[i]);
|
FilePath filename = texturedir_ + FilePath(cubefiles_[i]);
|
||||||
|
|
||||||
// load PNG or custom
|
// load PNG or custom
|
||||||
unsigned int w, h;
|
unsigned int w, h;
|
||||||
std::vector<unsigned char> image;
|
std::vector<unsigned char> image;
|
||||||
LoadFlip(filename, vfs, image, w, h);
|
LoadFlip(filename.Str(), vfs, image, w, h);
|
||||||
|
|
||||||
// PNG must be square
|
// PNG must be square
|
||||||
if (w != h) {
|
if (w != h) {
|
||||||
@@ -4244,6 +4269,14 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
|
|||||||
void mjCTexture::Compile(const mjVFS* vfs) {
|
void mjCTexture::Compile(const mjVFS* vfs) {
|
||||||
CopyFromSpec();
|
CopyFromSpec();
|
||||||
|
|
||||||
|
// copy paths from model if not already defined
|
||||||
|
if (modelfiledir_.empty()) {
|
||||||
|
modelfiledir_ = FilePath(model->modelfiledir_);
|
||||||
|
}
|
||||||
|
if (texturedir_.empty()) {
|
||||||
|
texturedir_ = FilePath(model->texturedir_);
|
||||||
|
}
|
||||||
|
|
||||||
// buffer from user
|
// buffer from user
|
||||||
if (!data_.empty()) {
|
if (!data_.empty()) {
|
||||||
if (data_.size() != nchannel*width*height) {
|
if (data_.size() != nchannel*width*height) {
|
||||||
@@ -4299,13 +4332,13 @@ void mjCTexture::Compile(const mjVFS* vfs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make filename
|
// make filename
|
||||||
std::string filename = mjuu_combinePaths(model->texturedir_, file_);
|
FilePath filename = texturedir_ + FilePath(file_);
|
||||||
|
|
||||||
// dispatch
|
// dispatch
|
||||||
if (type==mjTEXTURE_2D) {
|
if (type==mjTEXTURE_2D) {
|
||||||
Load2D(filename, vfs);
|
Load2D(filename.Str(), vfs);
|
||||||
} else {
|
} else {
|
||||||
LoadCubeSingle(filename, vfs);
|
LoadCubeSingle(filename.Str(), vfs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -808,6 +808,10 @@ class mjCMesh_ : public mjCBase {
|
|||||||
|
|
||||||
mjCBoundingVolumeHierarchy tree_; // bounding volume hierarchy
|
mjCBoundingVolumeHierarchy tree_; // bounding volume hierarchy
|
||||||
std::vector<double> face_aabb_; // bounding boxes of all faces
|
std::vector<double> face_aabb_; // bounding boxes of all faces
|
||||||
|
|
||||||
|
// paths stored during model attachment
|
||||||
|
mujoco::user::FilePath modelfiledir_;
|
||||||
|
mujoco::user::FilePath meshdir_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class mjCMesh: public mjCMesh_, private mjsMesh {
|
class mjCMesh: public mjCMesh_, private mjsMesh {
|
||||||
@@ -823,6 +827,7 @@ class mjCMesh: public mjCMesh_, private mjsMesh {
|
|||||||
|
|
||||||
void CopyFromSpec(void);
|
void CopyFromSpec(void);
|
||||||
void PointToLocal(void);
|
void PointToLocal(void);
|
||||||
|
void NameSpace(const mjCModel* m);
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
const mjsPlugin& Plugin() const { return plugin; }
|
const mjsPlugin& Plugin() const { return plugin; }
|
||||||
@@ -952,6 +957,10 @@ class mjCSkin_ : public mjCBase {
|
|||||||
|
|
||||||
int matid; // material id
|
int matid; // material id
|
||||||
std::vector<int> bodyid; // body ids
|
std::vector<int> bodyid; // body ids
|
||||||
|
|
||||||
|
// paths stored during model attachment
|
||||||
|
mujoco::user::FilePath modelfiledir_;
|
||||||
|
mujoco::user::FilePath meshdir_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class mjCSkin: public mjCSkin_, private mjsSkin {
|
class mjCSkin: public mjCSkin_, private mjsSkin {
|
||||||
@@ -1005,6 +1014,10 @@ class mjCHField_ : public mjCBase {
|
|||||||
std::string spec_file_;
|
std::string spec_file_;
|
||||||
std::string spec_content_type_;
|
std::string spec_content_type_;
|
||||||
std::vector<float> spec_userdata_;
|
std::vector<float> spec_userdata_;
|
||||||
|
|
||||||
|
// paths stored during model attachment
|
||||||
|
mujoco::user::FilePath modelfiledir_;
|
||||||
|
mujoco::user::FilePath meshdir_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class mjCHField : public mjCHField_, private mjsHField {
|
class mjCHField : public mjCHField_, private mjsHField {
|
||||||
@@ -1024,6 +1037,7 @@ class mjCHField : public mjCHField_, private mjsHField {
|
|||||||
|
|
||||||
void CopyFromSpec(void);
|
void CopyFromSpec(void);
|
||||||
void PointToLocal(void);
|
void PointToLocal(void);
|
||||||
|
void NameSpace(const mjCModel* m);
|
||||||
|
|
||||||
std::string File() const { return file_; }
|
std::string File() const { return file_; }
|
||||||
|
|
||||||
@@ -1052,6 +1066,10 @@ class mjCTexture_ : public mjCBase {
|
|||||||
std::string spec_file_;
|
std::string spec_file_;
|
||||||
std::string spec_content_type_;
|
std::string spec_content_type_;
|
||||||
std::vector<std::string> spec_cubefiles_;
|
std::vector<std::string> spec_cubefiles_;
|
||||||
|
|
||||||
|
// paths stored during model attachment
|
||||||
|
mujoco::user::FilePath modelfiledir_;
|
||||||
|
mujoco::user::FilePath texturedir_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class mjCTexture : public mjCTexture_, private mjsTexture {
|
class mjCTexture : public mjCTexture_, private mjsTexture {
|
||||||
@@ -1071,6 +1089,7 @@ class mjCTexture : public mjCTexture_, private mjsTexture {
|
|||||||
|
|
||||||
void CopyFromSpec(void);
|
void CopyFromSpec(void);
|
||||||
void PointToLocal(void);
|
void PointToLocal(void);
|
||||||
|
void NameSpace(const mjCModel* m);
|
||||||
|
|
||||||
std::string File() const { return file_; }
|
std::string File() const { return file_; }
|
||||||
std::string get_content_type() const { return content_type_; }
|
std::string get_content_type() const { return content_type_; }
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -502,5 +503,47 @@ TEST_F(LengthRangeTest, LengthRangeThreading) {
|
|||||||
mj_deleteSpec(spec);
|
mj_deleteSpec(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------- test modeldir --------------------------------
|
||||||
|
|
||||||
|
TEST_F(MujocoTest, Modeldir) {
|
||||||
|
static constexpr char cube[] = R"(
|
||||||
|
v -1 -1 1
|
||||||
|
v 1 -1 1
|
||||||
|
v -1 1 1
|
||||||
|
v 1 1 1
|
||||||
|
v -1 1 -1
|
||||||
|
v 1 1 -1
|
||||||
|
v -1 -1 -1
|
||||||
|
v 1 -1 -1)";
|
||||||
|
|
||||||
|
auto vfs = std::make_unique<mjVFS>();
|
||||||
|
mj_defaultVFS(vfs.get());
|
||||||
|
mj_addBufferVFS(vfs.get(), "meshdir/cube.obj", cube, sizeof(cube));
|
||||||
|
|
||||||
|
// child with the asset
|
||||||
|
mjSpec* child = mj_makeSpec();
|
||||||
|
mjsMesh* mesh = mjs_addMesh(child, 0);
|
||||||
|
mjsFrame* frame = mjs_addFrame(mjs_findBody(child, "world"), 0);
|
||||||
|
mjsGeom* geom = mjs_addGeom(mjs_findBody(child, "world"), 0);
|
||||||
|
mjs_setString(child->meshdir, "meshdir");
|
||||||
|
mjs_setString(mesh->file, "cube.obj");
|
||||||
|
mjs_setString(mesh->name, "cube");
|
||||||
|
mjs_setString(geom->meshname, "cube");
|
||||||
|
mjs_setFrame(geom->element, frame);
|
||||||
|
geom->type = mjGEOM_MESH;
|
||||||
|
|
||||||
|
// parent attaching the child
|
||||||
|
mjSpec* spec = mj_makeSpec();
|
||||||
|
mjs_setString(spec->meshdir, "asset");
|
||||||
|
mjs_attachFrame(mjs_findBody(spec, "world"), frame, "_", "");
|
||||||
|
mjModel* model = mj_compile(spec, vfs.get());
|
||||||
|
EXPECT_THAT(model, NotNull());
|
||||||
|
|
||||||
|
mj_deleteSpec(child);
|
||||||
|
mj_deleteSpec(spec);
|
||||||
|
mj_deleteModel(model);
|
||||||
|
mj_deleteVFS(vfs.get());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace mujoco
|
} // namespace mujoco
|
||||||
|
|||||||
Reference in New Issue
Block a user