Add mjmMesh to C API.
PiperOrigin-RevId: 606642150 Change-Id: Iae69ce8426729b1e2394d9da9f349a2f0f7ccf98
This commit is contained in:
committed by
Copybara-Service
parent
06505f49f9
commit
9ecd700923
@@ -137,6 +137,16 @@ mjmFrame* mjm_addFrame(mjmBody* bodyspec, mjmFrame* parentframe) {
|
||||
|
||||
|
||||
|
||||
// add mesh to model
|
||||
mjmMesh* mjm_addMesh(void* model, void* defspec) {
|
||||
mjCDef* def = defspec ? reinterpret_cast<mjCDef*>(defspec) : 0;
|
||||
mjCModel* modelC = static_cast<mjCModel*>(model);
|
||||
mjCMesh* mesh = modelC->AddMesh(def);
|
||||
return &mesh->spec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// add texture to model
|
||||
mjmTexture* mjm_addTexture(void* model) {
|
||||
mjCModel* modelC = static_cast<mjCModel*>(model);
|
||||
|
||||
@@ -325,6 +325,27 @@ typedef struct _mjmFlex {
|
||||
} mjmFlex;
|
||||
|
||||
|
||||
typedef struct _mjmMesh { // mesh specification
|
||||
mjElement element; // internal, do not modify
|
||||
mjString name; // name
|
||||
mjString classname; // class name
|
||||
mjString content_type; // content type of file
|
||||
mjString file; // mesh file
|
||||
double refpos[3]; // reference position
|
||||
double refquat[4]; // reference orientation
|
||||
double scale[3]; // rescale mesh
|
||||
mjtByte smoothnormal; // do not exclude large-angle faces from normals
|
||||
mjFloatVec uservert; // user vertex data
|
||||
mjFloatVec usernormal; // user normal data
|
||||
mjFloatVec usertexcoord; // user texcoord data
|
||||
mjIntVec userface; // user vertex indices
|
||||
mjIntVec userfacenormal; // user normal indices
|
||||
mjIntVec userfacetexcoord; // user texcoord indices
|
||||
mjmPlugin plugin; // sdf plugin
|
||||
mjString info; // message appended to compiler errors
|
||||
} mjmMesh;
|
||||
|
||||
|
||||
typedef struct _mjmTexture { // texture specification
|
||||
mjElement element; // internal, do not modify
|
||||
mjString name; // name
|
||||
@@ -558,6 +579,9 @@ MJAPI mjmFrame* mjm_addFrame(mjmBody* body, mjmFrame* parentframe);
|
||||
// Add flex to model.
|
||||
MJAPI mjmFlex* mjm_addFlex(void* model);
|
||||
|
||||
// Add mesh to model.
|
||||
MJAPI mjmMesh* mjm_addMesh(void* model, void* defspec);
|
||||
|
||||
// Add texture to model.
|
||||
MJAPI mjmTexture* mjm_addTexture(void* model);
|
||||
|
||||
@@ -672,6 +696,9 @@ MJAPI void mjm_defaultLight(mjmLight& light);
|
||||
// Default flex attributes.
|
||||
MJAPI void mjm_defaultFlex(mjmFlex& flex);
|
||||
|
||||
// Default mesh attributes.
|
||||
MJAPI void mjm_defaultMesh(mjmMesh& mesh);
|
||||
|
||||
// Default texture attributes.
|
||||
MJAPI void mjm_defaultTexture(mjmTexture& texture);
|
||||
|
||||
|
||||
@@ -857,13 +857,13 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
|
||||
// LoadOBJ uses userXXX, extra processing needed
|
||||
if (isobj) {
|
||||
// check sizes
|
||||
if (mesh.uservert().empty() || mesh.userface().empty()) {
|
||||
if (mesh.get_uservert().empty() || mesh.get_userface().empty()) {
|
||||
return comperr(error, "Vertex and face data required", error_sz);
|
||||
}
|
||||
if (mesh.uservert().size()%3) {
|
||||
if (mesh.get_uservert().size()%3) {
|
||||
return comperr(error, "Vertex data must be multiple of 3", error_sz);
|
||||
}
|
||||
if (mesh.userface().size()%3) {
|
||||
if (mesh.get_userface().size()%3) {
|
||||
return comperr(error, "Face data must be multiple of 3", error_sz);
|
||||
}
|
||||
|
||||
|
||||
@@ -192,6 +192,17 @@ void mjm_defaultFlex(mjmFlex& flex) {
|
||||
|
||||
|
||||
|
||||
// default mesh attributes
|
||||
void mjm_defaultMesh(mjmMesh& mesh) {
|
||||
memset(&mesh, 0, sizeof(mjmMesh));
|
||||
mjuu_setvec(mesh.refpos, 0, 0, 0);
|
||||
mjuu_setvec(mesh.refquat, 1, 0, 0, 0);
|
||||
mjuu_setvec(mesh.scale, 1, 1, 1);
|
||||
mesh.smoothnormal = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// default texture attributes
|
||||
void mjm_defaultTexture(mjmTexture& texture) {
|
||||
memset(&texture, 0, sizeof(mjmTexture));
|
||||
|
||||
+65
-116
@@ -129,11 +129,7 @@ static void ReadFromBuffer(T* dst, const char* src) {
|
||||
//------------------ class mjCMesh implementation --------------------------------------------------
|
||||
|
||||
mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) {
|
||||
// set defaults
|
||||
mjuu_setvec(refpos_, 0, 0, 0);
|
||||
mjuu_setvec(refquat_, 1, 0, 0, 0);
|
||||
mjuu_setvec(scale_, 1, 1, 1);
|
||||
smoothnormal_ = false;
|
||||
mjm_defaultMesh(spec);
|
||||
|
||||
// clear internal variables
|
||||
mjuu_setvec(pos_surface_, 0, 0, 0);
|
||||
@@ -179,9 +175,50 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) {
|
||||
model = _model;
|
||||
def = (_def ? _def : (_model ? _model->defaults[0] : 0));
|
||||
|
||||
// in case this body is not compiled
|
||||
CopyFromSpec();
|
||||
|
||||
// point to local (needs to be after defaults)
|
||||
plugin.name = (mjString)&plugin_name;
|
||||
plugin.instance_name = (mjString)&plugin_instance_name;
|
||||
PointToLocal();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::PointToLocal() {
|
||||
spec.element = (mjElement)this;
|
||||
spec.name = (mjString)&name;
|
||||
spec.classname = (mjString)&classname;
|
||||
spec.file = (mjString)&spec_file_;
|
||||
spec.content_type = (mjString)&spec_content_type_;
|
||||
spec.uservert = (mjFloatVec)&spec_uservert_;
|
||||
spec.usernormal = (mjFloatVec)&spec_usernormal_;
|
||||
spec.userface = (mjIntVec)&spec_userface_;
|
||||
spec.usertexcoord = (mjFloatVec)&spec_usertexcoord_;
|
||||
spec.plugin.name = (mjString)&plugin_name;
|
||||
spec.plugin.instance_name = (mjString)&plugin_instance_name;
|
||||
spec.info = (mjString)&info;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::CopyFromSpec() {
|
||||
*static_cast<mjmMesh*>(this) = spec;
|
||||
file_ = spec_file_;
|
||||
content_type_ = spec_content_type_;
|
||||
uservert_ = spec_uservert_;
|
||||
usernormal_ = spec_usernormal_;
|
||||
userface_ = spec_userface_;
|
||||
usertexcoord_ = spec_usertexcoord_;
|
||||
file = (mjString)&file_;
|
||||
content_type = (mjString)&content_type_;
|
||||
uservert = (mjFloatVec)&uservert_;
|
||||
usernormal = (mjFloatVec)&usernormal_;
|
||||
userface = (mjIntVec)&userface_;
|
||||
usertexcoord = (mjFloatVec)&usertexcoord_;
|
||||
plugin.active = spec.plugin.active;
|
||||
plugin.instance = spec.plugin.instance;
|
||||
plugin.name = spec.plugin.name;
|
||||
plugin.instance_name = spec.plugin.instance_name;
|
||||
}
|
||||
|
||||
|
||||
@@ -199,96 +236,6 @@ mjCMesh::~mjCMesh() {
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_content_type(std::optional<std::string>&& content_type) {
|
||||
if (content_type.has_value()) {
|
||||
content_type_ = std::move(content_type.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_file(std::optional<std::string>&& file) {
|
||||
if (file.has_value()) {
|
||||
file_ = std::move(file.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_refpos(std::optional<std::array<double, 3>> refpos) {
|
||||
if (refpos.has_value()) {
|
||||
std::copy(refpos.value().begin(), refpos.value().end(), refpos_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_refquat(std::optional<std::array<double, 4>> refquat) {
|
||||
if (refquat.has_value()) {
|
||||
std::copy(refquat.value().begin(), refquat.value().end(), refquat_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_scale(std::optional<std::array<double, 3>> scale) {
|
||||
if (scale.has_value()) {
|
||||
set_scale(scale.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_uservert(std::optional<std::vector<float>>&& uservert) {
|
||||
if (uservert.has_value()) {
|
||||
uservert_ = std::move(uservert.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_usernormal(std::optional<std::vector<float>>&& usernormal) {
|
||||
if (usernormal.has_value()) {
|
||||
usernormal_ = std::move(usernormal.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_usertexcoord(std::optional<std::vector<float>>&& usertexcoord) {
|
||||
if (usertexcoord.has_value()) {
|
||||
usertexcoord_ = std::move(usertexcoord.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_userface(std::optional<std::vector<int>>&& userface) {
|
||||
if (userface.has_value()) {
|
||||
userface_ = std::move(userface.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_file(const std::string& file) {
|
||||
file_ = file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_scale(std::array<double, 3> scale) {
|
||||
std::copy(scale.begin(), scale.end(), scale_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_smoothnormal(bool smoothnormal) {
|
||||
smoothnormal_ = smoothnormal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMesh::set_needhull(bool needhull) {
|
||||
needhull_ = needhull;
|
||||
}
|
||||
@@ -303,7 +250,7 @@ void mjCMesh::LoadSDF() {
|
||||
name.c_str(), id);
|
||||
}
|
||||
|
||||
if (scale_[0] != 1 || scale_[1] != 1 || scale_[2] != 1) {
|
||||
if (scale[0] != 1 || scale[1] != 1 || scale[2] != 1) {
|
||||
throw mjCError(this, "attribute scale is not compatible with SDFs in mesh '%s', (id = %d)",
|
||||
name.c_str(), id);
|
||||
}
|
||||
@@ -371,9 +318,9 @@ void mjCMesh::LoadSDF() {
|
||||
userface.push_back(mesh.indices.at(i));
|
||||
}
|
||||
|
||||
set_uservert(uservert);
|
||||
set_usernormal(usernormal);
|
||||
set_userface(userface);
|
||||
uservert_ = std::move(uservert);
|
||||
usernormal_ = std::move(usernormal);
|
||||
userface_ = std::move(userface);
|
||||
delete[] field;
|
||||
}
|
||||
|
||||
@@ -381,6 +328,8 @@ void mjCMesh::LoadSDF() {
|
||||
|
||||
// compiler
|
||||
void mjCMesh::Compile(const mjVFS* vfs) {
|
||||
CopyFromSpec();
|
||||
|
||||
// load file
|
||||
if (!file_.empty()) {
|
||||
// remove path from file if necessary
|
||||
@@ -957,7 +906,7 @@ void mjCMesh::LoadOBJ(mjResource* resource) {
|
||||
|
||||
if (!objReader.GetShapes().empty()) {
|
||||
const auto& mesh = objReader.GetShapes()[0].mesh;
|
||||
bool righthand = (scale_[0]*scale_[1]*scale_[2] > 0);
|
||||
bool righthand = (scale[0]*scale[1]*scale[2] > 0);
|
||||
|
||||
// iterate over mesh faces
|
||||
std::vector<tinyobj::index_t> face_indices;
|
||||
@@ -1005,7 +954,7 @@ void mjCMesh::LoadOBJ(mjResource* resource) {
|
||||
|
||||
// load STL binary mesh
|
||||
void mjCMesh::LoadSTL(mjResource* resource) {
|
||||
bool righthand = (scale_[0]*scale_[1]*scale_[2]>0);
|
||||
bool righthand = (scale[0]*scale[1]*scale[2]>0);
|
||||
|
||||
// get file data in buffer
|
||||
char* buffer = 0;
|
||||
@@ -1085,7 +1034,7 @@ void mjCMesh::LoadSTL(mjResource* resource) {
|
||||
|
||||
// load MSH binary mesh
|
||||
void mjCMesh::LoadMSH(mjResource* resource) {
|
||||
bool righthand = (scale_[0]*scale_[1]*scale_[2]>0);
|
||||
bool righthand = (scale[0]*scale[1]*scale[2]>0);
|
||||
|
||||
// get file data in buffer
|
||||
char* buffer = 0;
|
||||
@@ -1193,9 +1142,9 @@ void mjCMesh::ComputeVolume(double CoM[3], mjtGeomInertia type,
|
||||
// apply transformations
|
||||
void mjCMesh::ApplyTransformations() {
|
||||
// translate
|
||||
if (refpos_[0]!=0 || refpos_[1]!=0 || refpos_[2]!=0) {
|
||||
if (refpos[0]!=0 || refpos[1]!=0 || refpos[2]!=0) {
|
||||
// prepare translation
|
||||
float rp[3] = {(float)refpos_[0], (float)refpos_[1], (float)refpos_[2]};
|
||||
float rp[3] = {(float)refpos[0], (float)refpos[1], (float)refpos[2]};
|
||||
|
||||
// process vertices
|
||||
for (int i=0; i<nvert_; i++) {
|
||||
@@ -1206,9 +1155,9 @@ void mjCMesh::ApplyTransformations() {
|
||||
}
|
||||
|
||||
// rotate
|
||||
if (refquat_[0]!=1 || refquat_[1]!=0 || refquat_[2]!=0 || refquat_[3]!=0) {
|
||||
if (refquat[0]!=1 || refquat[1]!=0 || refquat[2]!=0 || refquat[3]!=0) {
|
||||
// prepare rotation
|
||||
mjtNum quat[4] = {refquat_[0], refquat_[1], refquat_[2], refquat_[3]};
|
||||
mjtNum quat[4] = {refquat[0], refquat[1], refquat[2], refquat[3]};
|
||||
mjtNum mat[9];
|
||||
mju_normalize4(quat);
|
||||
mju_quat2Mat(mat, quat);
|
||||
@@ -1233,17 +1182,17 @@ void mjCMesh::ApplyTransformations() {
|
||||
}
|
||||
|
||||
// scale
|
||||
if (scale_[0]!=1 || scale_[1]!=1 || scale_[2]!=1) {
|
||||
if (scale[0]!=1 || scale[1]!=1 || scale[2]!=1) {
|
||||
for (int i=0; i<nvert_; i++) {
|
||||
vert_[3*i] *= scale_[0];
|
||||
vert_[3*i+1] *= scale_[1];
|
||||
vert_[3*i+2] *= scale_[2];
|
||||
vert_[3*i] *= scale[0];
|
||||
vert_[3*i+1] *= scale[1];
|
||||
vert_[3*i+2] *= scale[2];
|
||||
}
|
||||
|
||||
for (int i=0; i<nnormal_; i++) {
|
||||
normal_[3*i] *= scale_[0];
|
||||
normal_[3*i+1] *= scale_[1];
|
||||
normal_[3*i+2] *= scale_[2];
|
||||
normal_[3*i] *= scale[0];
|
||||
normal_[3*i+1] *= scale[1];
|
||||
normal_[3*i+2] *= scale[2];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1764,7 +1713,7 @@ void mjCMesh::MakeNormal(void) {
|
||||
}
|
||||
|
||||
// remove large-angle faces
|
||||
if (!smoothnormal_) {
|
||||
if (!smoothnormal) {
|
||||
// allocate removal and clear
|
||||
float* nremove = (float*) mju_malloc(3*nnormal_*sizeof(float));
|
||||
memset(nremove, 0, 3*nnormal_*sizeof(float));
|
||||
|
||||
@@ -599,6 +599,7 @@ void mjCBody::PointToLocal() {
|
||||
spec.userdata = (mjDoubleVec)&spec_userdata_;
|
||||
spec.plugin.name = (mjString)&plugin_name;
|
||||
spec.plugin.instance_name = (mjString)&plugin_instance_name;
|
||||
spec.info = (mjString)&info;
|
||||
}
|
||||
|
||||
|
||||
@@ -606,7 +607,6 @@ void mjCBody::CopyFromSpec() {
|
||||
*static_cast<mjmBody*>(this) = spec;
|
||||
userdata_ = spec_userdata_;
|
||||
userdata = (mjDoubleVec)&userdata_;
|
||||
spec.info = (mjString)&info;
|
||||
mju_copy4(alt_.axisangle, alt.axisangle);
|
||||
mju_copy(alt_.xyaxes, alt.xyaxes, 6);
|
||||
mju_copy3(alt_.zaxis, alt.zaxis);
|
||||
|
||||
+36
-38
@@ -615,26 +615,36 @@ class mjCFlex: public mjCBase, private mjmFlex {
|
||||
//------------------------- class mjCMesh ----------------------------------------------------------
|
||||
// Describes a mesh
|
||||
|
||||
class mjCMesh: public mjCBase {
|
||||
class mjCMesh: public mjCBase, private mjmMesh {
|
||||
friend class mjCFlexcomp;
|
||||
friend class mjXWriter;
|
||||
public:
|
||||
mjCMesh(mjCModel* = 0, mjCDef* = 0);
|
||||
~mjCMesh();
|
||||
|
||||
// public getters
|
||||
const std::string& content_type() const { return content_type_; }
|
||||
const std::string& file() const { return file_; }
|
||||
mjmMesh spec;
|
||||
using mjCBase::name;
|
||||
using mjCBase::classname;
|
||||
using mjCBase::plugin;
|
||||
using mjCBase::info;
|
||||
|
||||
void CopyFromSpec(void);
|
||||
void PointToLocal(void);
|
||||
|
||||
// public getters and setters
|
||||
const std::string& get_content_type() const { return content_type_; }
|
||||
const std::string& get_file() const { return file_; }
|
||||
const double* refpos() const { return refpos_; }
|
||||
const double* refquat() const { return refquat_; }
|
||||
const double* scale() const { return scale_; }
|
||||
bool smoothnormal() const { return smoothnormal_; }
|
||||
const double* get_refpos() const { return refpos; }
|
||||
const double* get_refquat() const { return refquat; }
|
||||
const double* get_scale() const { return scale; }
|
||||
bool get_smoothnormal() const { return smoothnormal; }
|
||||
void set_needhull(bool needhull);
|
||||
|
||||
// public getters for user data
|
||||
const std::vector<float>& uservert() const { return uservert_; }
|
||||
const std::vector<float>& usernormal() const { return usernormal_; }
|
||||
const std::vector<float>& usertexcoord() const { return usertexcoord_; }
|
||||
const std::vector<int>& userface() const { return userface_; }
|
||||
const std::vector<float>& get_uservert() const { return uservert_; }
|
||||
const std::vector<float>& get_usernormal() const { return usernormal_; }
|
||||
const std::vector<float>& get_usertexcoord() const { return usertexcoord_; }
|
||||
const std::vector<int>& get_userface() const { return userface_; }
|
||||
|
||||
// mesh properties computed by Compile
|
||||
const double* aamm() const { return aamm_; }
|
||||
@@ -651,24 +661,6 @@ class mjCMesh: public mjCBase {
|
||||
// bounding volume hierarchy tree
|
||||
const mjCBoundingVolumeHierarchy& tree() { return tree_; }
|
||||
|
||||
// general setters
|
||||
void set_file(const std::string& file);
|
||||
void set_scale(std::array<double, 3> scale);
|
||||
void set_smoothnormal(bool smoothnormal);
|
||||
void set_needhull(bool needhull);
|
||||
|
||||
// setters used in reading XML attributes (no-op if empty optional)
|
||||
void set_content_type(std::optional<std::string>&& content_type);
|
||||
void set_file(std::optional<std::string>&& file);
|
||||
void set_refpos(std::optional<std::array<double, 3>> refpos);
|
||||
void set_refquat(std::optional<std::array<double, 4>> refquat);
|
||||
void set_scale(std::optional<std::array<double, 3>> scale);
|
||||
|
||||
void set_uservert(std::optional<std::vector<float>>&& uservert);
|
||||
void set_usernormal(std::optional<std::vector<float>>&& usernormal);
|
||||
void set_usertexcoord(std::optional<std::vector<float>>&& usertexcoord);
|
||||
void set_userface(std::optional<std::vector<int>>&& userface);
|
||||
|
||||
void Compile(const mjVFS* vfs); // compiler
|
||||
double* GetPosPtr(mjtGeomInertia type); // get position
|
||||
double* GetQuatPtr(mjtGeomInertia type); // get orientation
|
||||
@@ -694,19 +686,25 @@ 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)
|
||||
double refquat_[4]; // reference orientation (rotate)
|
||||
double scale_[3]; // rescale mesh
|
||||
bool smoothnormal_; // do not exclude large-angle faces from normals
|
||||
|
||||
// variable size attributes
|
||||
std::string content_type_; // content type of file
|
||||
std::string file_; // mesh file
|
||||
std::vector<float> uservert_; // user vertex data
|
||||
std::vector<float> usernormal_; // user normal data
|
||||
std::vector<float> usertexcoord_; // user texcoord data
|
||||
std::vector<int> userface_; // user vertex indices
|
||||
std::vector<int> userfacenormal_; // user normal indices
|
||||
|
||||
std::string spec_content_type_;
|
||||
std::string spec_file_;
|
||||
std::vector<float> spec_uservert_;
|
||||
std::vector<float> spec_usernormal_;
|
||||
std::vector<float> spec_usertexcoord_;
|
||||
std::vector<int> spec_userface_;
|
||||
std::vector<int> spec_userfacenormal_;
|
||||
|
||||
// used by the compiler
|
||||
bool visual_; // true: the mesh is only visual
|
||||
std::vector<int> userfacetexcoord_; // user texcoord indices
|
||||
std::vector< std::pair<int, int> > useredge_; // user half-edge data
|
||||
|
||||
|
||||
Reference in New Issue
Block a user