Add mjmSkin to C API.

PiperOrigin-RevId: 607295996
Change-Id: I63bf7213d41acbfb98770c097979ce9b889f21ca
This commit is contained in:
Alessio Quaglino
2024-02-15 05:07:51 -08:00
committed by Copybara-Service
parent bafe490ea8
commit 6f958bc404
13 changed files with 630 additions and 420 deletions
+33 -4
View File
@@ -156,6 +156,15 @@ mjmHField* mjm_addHField(void* model) {
// add skin to model
mjmSkin* mjm_addSkin(void* model) {
mjCModel* modelC = static_cast<mjCModel*>(model);
mjCSkin* skin = modelC->AddSkin();
return &skin->spec;
}
// add texture to model
mjmTexture* mjm_addTexture(void* model) {
mjCModel* modelC = static_cast<mjCModel*>(model);
@@ -370,6 +379,7 @@ int mjm_getId(mjElement element) {
}
// set default
void mjm_setDefault(mjElement element, void* defspec) {
mjCBase* baseC = reinterpret_cast<mjCBase*>(element);
@@ -377,6 +387,7 @@ void mjm_setDefault(mjElement element, void* defspec) {
}
// set string
void mjm_setString(mjString dest, const char* text) {
std::string* str = reinterpret_cast<std::string*>(dest);
@@ -405,14 +416,15 @@ void mjm_setStringVec(mjStringVec dest, const char* text) {
}
// add text entry to destination string vector
void mjm_addToStringVec(mjStringVec dest, const char* text) {
void mjm_appendString(mjStringVec dest, const char* text) {
std::vector<std::string>* v = reinterpret_cast<std::vector<std::string>*>(dest);
v->push_back(std::string(text));
}
// set int array
// copy int array to vector
void mjm_setInt(mjIntVec dest, const int* array, int size) {
std::vector<int>* v = reinterpret_cast<std::vector<int>*>(dest);
v->assign(size, 0.0);
@@ -423,7 +435,15 @@ void mjm_setInt(mjIntVec dest, const int* array, int size) {
// set float array
// append int array to vector of arrays
void mjm_appendIntVec(mjIntVecVec dest, const int* array, int size) {
std::vector<std::vector<int>>* v = reinterpret_cast<std::vector<std::vector<int>>*>(dest);
v->push_back(std::vector<int>(array, array + size));
}
// copy float array to vector
void mjm_setFloat(mjFloatVec dest, const float* array, int size) {
std::vector<float>* v = reinterpret_cast<std::vector<float>*>(dest);
v->assign(size, 0.0);
@@ -434,7 +454,16 @@ void mjm_setFloat(mjFloatVec dest, const float* array, int size) {
// set double array
// append float array to vector of arrays
void mjm_appendFloatVec(mjFloatVecVec dest, const float* array, int size) {
std::vector<std::vector<float>>* v = reinterpret_cast<std::vector<std::vector<float>>*>(dest);
v->push_back(std::vector<float>(array, array + size));
}
// copy double array to vector
void mjm_setDouble(mjDoubleVec dest, const double* array, int size) {
std::vector<double>* v = reinterpret_cast<std::vector<double>*>(dest);
v->assign(size, 0.0);
+51 -9
View File
@@ -32,8 +32,10 @@ typedef struct _mjElement* mjElement;
typedef struct _mjString* mjString;
typedef struct _mjStringVec* mjStringVec;
typedef struct _mjIntVec* mjIntVec;
typedef struct _mjDoubleVec* mjDoubleVec;
typedef struct _mjIntVecVec* mjIntVecVec;
typedef struct _mjFloatVec* mjFloatVec;
typedef struct _mjFloatVecVec* mjFloatVecVec;
typedef struct _mjDoubleVec* mjDoubleVec;
//---------------------------------- enum types (mjt) ----------------------------------------------
@@ -366,6 +368,34 @@ typedef struct _mjmHField { // height field specification
} mjmHField;
typedef struct _mjmSkin { // skin specification
mjElement element; // internal, do not modify
mjString name; // name
mjString classname; // class name
mjString file; // skin file
mjString material; // name of material used for rendering
float rgba[4]; // rgba when material is omitted
float inflate; // inflate in normal direction
int group; // group for visualization
// mesh
mjFloatVec vert; // vertex positions
mjFloatVec texcoord; // texture coordinates
mjIntVec face; // faces
// skin
mjStringVec bodyname; // body names
mjFloatVec bindpos; // bind pos
mjFloatVec bindquat; // bind quat
mjIntVecVec vertid; // vertex ids
mjFloatVecVec vertweight; // vertex weights
// other
mjString info; // message appended to compiler errors
} mjmSkin;
typedef struct _mjmTexture { // texture specification
mjElement element; // internal, do not modify
mjString name; // name
@@ -655,6 +685,9 @@ MJAPI mjmMesh* mjm_addMesh(void* model, void* defspec);
// Add height field to model.
MJAPI mjmHField* mjm_addHField(void* model);
// Add skin to model.
MJAPI mjmSkin* mjm_addSkin(void* model);
// Add texture to model.
MJAPI mjmTexture* mjm_addTexture(void* model);
@@ -721,25 +754,31 @@ MJAPI mjmBody* mjm_findChild(mjmBody* body, const char* name);
// Get element id.
MJAPI int mjm_getId(mjElement element);
// Copy text to destination string.
// Copy text to string.
MJAPI void mjm_setString(mjString dest, const char* text);
// Split text to entries and copy to destination string vector.
// Split text to entries and copy to string vector.
MJAPI void mjm_setStringVec(mjStringVec dest, const char* text);
// Set specific entry in destination string vector.
// Set entry in string vector.
MJAPI mjtByte mjm_setInStringVec(mjStringVec dest, int i, const char* text);
// Add text entry to destination string vector.
MJAPI void mjm_addToStringVec(mjStringVec dest, const char* text);
// Append text entry to string vector.
MJAPI void mjm_appendString(mjStringVec dest, const char* text);
// Copy int array to destination vector.
// Copy int array to vector.
MJAPI void mjm_setInt(mjIntVec dest, const int* array, int size);
// Copy float array to destination vector.
// Append int array to vector of arrays.
MJAPI void mjm_appendIntVec(mjIntVecVec dest, const int* array, int size);
// Copy float array to vector.
MJAPI void mjm_setFloat(mjFloatVec dest, const float* array, int size);
// Copy double array to destination vector.
// Append float array to vector of arrays.
MJAPI void mjm_appendFloatVec(mjFloatVecVec dest, const float* array, int size);
// Copy double array to vector.
MJAPI void mjm_setDouble(mjDoubleVec dest, const double* array, int size);
// Get string contents.
@@ -790,6 +829,9 @@ MJAPI void mjm_defaultMesh(mjmMesh& mesh);
// Default height field attributes.
MJAPI void mjm_defaultHField(mjmHField& hfield);
// Default skin attributes.
MJAPI void mjm_defaultSkin(mjmSkin& skin);
// Default texture attributes.
MJAPI void mjm_defaultTexture(mjmTexture& texture);
+253 -231
View File
@@ -279,6 +279,15 @@ bool mjCComposite::Make(mjCModel* model, mjmBody* body, char* error, int error_s
}
}
// clear skin vectors
face.clear();
vert.clear();
bindpos.clear();
bindquat.clear();
texcoord.clear();
vertid.clear();
vertweight.clear();
// require 3x3 for subgrid
if (skin && skinsubgrid>0 && type!=mjCOMPTYPE_CABLE) {
if (count[0]<3 || count[1]<3) {
@@ -1238,57 +1247,80 @@ void mjCComposite::MakeShear(mjCModel* model) {
// copy local vectors to skin
void mjCComposite::CopyIntoSkin(mjmSkin* skin) {
mjm_setInt(skin->face, face.data(), face.size());
mjm_setFloat(skin->vert, vert.data(), vert.size());
mjm_setFloat(skin->bindpos, bindpos.data(), bindpos.size());
mjm_setFloat(skin->bindquat, bindquat.data(), bindquat.size());
mjm_setFloat(skin->texcoord, texcoord.data(), texcoord.size());
for (int i=0; i<vertid.size(); i++) {
mjm_appendIntVec(skin->vertid, vertid[i].data(), vertid[i].size());
}
for (int i=0; i< vertweight.size(); i++) {
mjm_appendFloatVec(skin->vertweight, vertweight[i].data(), vertweight[i].size());
}
face.clear();
vert.clear();
bindpos.clear();
bindquat.clear();
texcoord.clear();
vertid.clear();
vertweight.clear();
}
// add skin to 2D
void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) {
char txt[100];
int N = count[0]*count[1];
// add skin, set name and material
mjCSkin* skin = model->AddSkin();
mjmSkin* skin = mjm_addSkin(model);
mju::sprintf_arr(txt, "%sSkin", prefix.c_str());
skin->name = txt;
skin->set_material(skinmaterial);
mjm_setString(skin->name, txt);
mjm_setString(skin->material, skinmaterial.c_str());
mjuu_copyvec(skin->rgba, skinrgba, 4);
skin->inflate = inflate;
skin->group = skingroup;
// copy skin from existing mesh
if (type==mjCOMPTYPE_PARTICLE && username.empty()) {
std::vector<int> face;
mjXUtil::String2Vector(userface, face);
std::vector<int> skinface;
mjXUtil::String2Vector(userface, skinface);
int nvert = uservert.size()/3;
for (int j=0; j<2; j++) {
for (int i=0; i<nvert; i++) {
skin->vert.push_back(0);
skin->vert.push_back(0);
skin->vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
mju::sprintf_arr(txt, "%sB%d", prefix.c_str(), i);
skin->bodyname.push_back(txt);
skin->bindpos.push_back(0);
skin->bindpos.push_back(0);
skin->bindpos.push_back(0);
skin->bindquat.push_back(1);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
mjm_appendString(skin->bodyname, txt);
bindpos.push_back(0);
bindpos.push_back(0);
bindpos.push_back(0);
bindquat.push_back(1);
bindquat.push_back(0);
bindquat.push_back(0);
bindquat.push_back(0);
vector<int> vertid;
vector<float> vertweight;
vertid.push_back(j*nvert+i);
vertweight.push_back(1);
skin->vertid.push_back(vertid);
skin->vertweight.push_back(vertweight);
vertid.push_back({j*nvert+i});
vertweight.push_back({1});
}
for (int i=0; i<face.size()/3; i++) {
skin->face.push_back(j*nvert+face[3*i]);
skin->face.push_back(j*nvert+face[3*i+(j==0 ? 1 : 2)]);
skin->face.push_back(j*nvert+face[3*i+(j==0 ? 2 : 1)]);
for (int i=0; i<skinface.size()/3; i++) {
face.push_back(j*nvert+skinface[3*i]);
face.push_back(j*nvert+skinface[3*i+(j==0 ? 1 : 2)]);
face.push_back(j*nvert+skinface[3*i+(j==0 ? 2 : 1)]);
}
}
CopyIntoSkin(skin);
return;
}
@@ -1297,25 +1329,25 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) {
for (int ix=0; ix<count[0]; ix++) {
for (int iy=0; iy<count[1]; iy++) {
// vertex
skin->vert.push_back(0);
skin->vert.push_back(0);
skin->vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
// texture coordinate
if (skintexcoord) {
skin->texcoord.push_back(ix/(float)(count[0]-1));
skin->texcoord.push_back(iy/(float)(count[1]-1));
texcoord.push_back(ix/(float)(count[0]-1));
texcoord.push_back(iy/(float)(count[1]-1));
}
// face
if (ix<count[0]-1 && iy<count[1]-1) {
skin->face.push_back(i*N + ix*count[1]+iy);
skin->face.push_back(i*N + (ix+1)*count[1]+iy+(i==1));
skin->face.push_back(i*N + (ix+1)*count[1]+iy+(i==0));
face.push_back(i*N + ix*count[1]+iy);
face.push_back(i*N + (ix+1)*count[1]+iy+(i==1));
face.push_back(i*N + (ix+1)*count[1]+iy+(i==0));
skin->face.push_back(i*N + ix*count[1]+iy);
skin->face.push_back(i*N + (ix+(i==0))*count[1]+iy+1);
skin->face.push_back(i*N + (ix+(i==1))*count[1]+iy+1);
face.push_back(i*N + ix*count[1]+iy);
face.push_back(i*N + (ix+(i==0))*count[1]+iy+1);
face.push_back(i*N + (ix+(i==1))*count[1]+iy+1);
}
}
}
@@ -1323,46 +1355,46 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) {
// add thin triangles: X direction, iy = 0
for (int ix=0; ix<count[0]-1; ix++) {
skin->face.push_back(ix*count[1]);
skin->face.push_back(N + (ix+1)*count[1]);
skin->face.push_back((ix+1)*count[1]);
face.push_back(ix*count[1]);
face.push_back(N + (ix+1)*count[1]);
face.push_back((ix+1)*count[1]);
skin->face.push_back(ix*count[1]);
skin->face.push_back(N + ix*count[1]);
skin->face.push_back(N + (ix+1)*count[1]);
face.push_back(ix*count[1]);
face.push_back(N + ix*count[1]);
face.push_back(N + (ix+1)*count[1]);
}
// add thin triangles: X direction, iy = count[1]-1
for (int ix=0; ix<count[0]-1; ix++) {
skin->face.push_back(ix*count[1] + count[1]-1);
skin->face.push_back((ix+1)*count[1] + count[1]-1);
skin->face.push_back(N + (ix+1)*count[1] + count[1]-1);
face.push_back(ix*count[1] + count[1]-1);
face.push_back((ix+1)*count[1] + count[1]-1);
face.push_back(N + (ix+1)*count[1] + count[1]-1);
skin->face.push_back(ix*count[1] + count[1]-1);
skin->face.push_back(N + (ix+1)*count[1] + count[1]-1);
skin->face.push_back(N + ix*count[1] + count[1]-1);
face.push_back(ix*count[1] + count[1]-1);
face.push_back(N + (ix+1)*count[1] + count[1]-1);
face.push_back(N + ix*count[1] + count[1]-1);
}
// add thin triangles: Y direction, ix = 0
for (int iy=0; iy<count[1]-1; iy++) {
skin->face.push_back(iy);
skin->face.push_back(iy+1);
skin->face.push_back(N + iy+1);
face.push_back(iy);
face.push_back(iy+1);
face.push_back(N + iy+1);
skin->face.push_back(iy);
skin->face.push_back(N + iy+1);
skin->face.push_back(N + iy);
face.push_back(iy);
face.push_back(N + iy+1);
face.push_back(N + iy);
}
// add thin triangles: Y direction, ix = count[0]-1
for (int iy=0; iy<count[1]-1; iy++) {
skin->face.push_back(iy + (count[0]-1)*count[1]);
skin->face.push_back(N + iy+1 + (count[0]-1)*count[1]);
skin->face.push_back(iy+1 + (count[0]-1)*count[1]);
face.push_back(iy + (count[0]-1)*count[1]);
face.push_back(N + iy+1 + (count[0]-1)*count[1]);
face.push_back(iy+1 + (count[0]-1)*count[1]);
skin->face.push_back(iy + (count[0]-1)*count[1]);
skin->face.push_back(N + iy + (count[0]-1)*count[1]);
skin->face.push_back(N + iy+1 + (count[0]-1)*count[1]);
face.push_back(iy + (count[0]-1)*count[1]);
face.push_back(N + iy + (count[0]-1)*count[1]);
face.push_back(N + iy+1 + (count[0]-1)*count[1]);
}
// couple with bones
@@ -1371,12 +1403,14 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) {
} else if (type==mjCOMPTYPE_CABLE) {
MakeCableBones(model, skin);
}
CopyIntoSkin(skin);
}
// add bones in 2D
void mjCComposite::MakeClothBones(mjCModel* model, mjCSkin* skin) {
void mjCComposite::MakeClothBones(mjCModel* model, mjmSkin* skin) {
char txt[100];
int N = count[0]*count[1];
@@ -1391,31 +1425,25 @@ void mjCComposite::MakeClothBones(mjCModel* model, mjCSkin* skin) {
}
// bind pose
skin->bodyname.push_back(txt);
skin->bindpos.push_back(0);
skin->bindpos.push_back(0);
skin->bindpos.push_back(0);
skin->bindquat.push_back(1);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
mjm_appendString(skin->bodyname, txt);
bindpos.push_back(0);
bindpos.push_back(0);
bindpos.push_back(0);
bindquat.push_back(1);
bindquat.push_back(0);
bindquat.push_back(0);
bindquat.push_back(0);
// create vertid and vertweight
vector<int> vertid;
vector<float> vertweight;
vertid.push_back(ix*count[1]+iy);
vertid.push_back(N + ix*count[1]+iy);
vertweight.push_back(1);
vertweight.push_back(1);
skin->vertid.push_back(vertid);
skin->vertweight.push_back(vertweight);
vertid.push_back({ix*count[1]+iy, N + ix*count[1]+iy});
vertweight.push_back({1, 1});
}
}
}
void mjCComposite::MakeClothBonesSubgrid(mjCModel* model, mjCSkin* skin) {
void mjCComposite::MakeClothBonesSubgrid(mjCModel* model, mjmSkin* skin) {
char txt[100];
// populate bones
@@ -1429,20 +1457,18 @@ void mjCComposite::MakeClothBonesSubgrid(mjCModel* model, mjCSkin* skin) {
}
// bind pose
skin->bodyname.push_back(txt);
skin->bindpos.push_back(ix*spacing);
skin->bindpos.push_back(iy*spacing);
skin->bindpos.push_back(0);
skin->bindquat.push_back(1);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
mjm_appendString(skin->bodyname, txt);
bindpos.push_back(ix*spacing);
bindpos.push_back(iy*spacing);
bindpos.push_back(0);
bindquat.push_back(1);
bindquat.push_back(0);
bindquat.push_back(0);
bindquat.push_back(0);
// empty vertid and vertweight
vector<int> vertid;
vector<float> vertweight;
skin->vertid.push_back(vertid);
skin->vertweight.push_back(vertweight);
vertid.push_back({});
vertweight.push_back({});
}
}
}
@@ -1450,7 +1476,7 @@ void mjCComposite::MakeClothBonesSubgrid(mjCModel* model, mjCSkin* skin) {
// add bones to 1D
void mjCComposite::MakeCableBones(mjCModel* model, mjCSkin* skin) {
void mjCComposite::MakeCableBones(mjCModel* model, mjmSkin* skin) {
char this_body[100];
int N = count[0]*count[1];
@@ -1468,31 +1494,31 @@ void mjCComposite::MakeCableBones(mjCModel* model, mjCSkin* skin) {
// bind pose
if (iy==0) {
skin->bodyname.push_back(this_body);
skin->bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
skin->bindpos.push_back(-def[0].geom.spec.size[1]);
skin->bindpos.push_back(0);
skin->bindquat.push_back(1); skin->bindquat.push_back(0);
skin->bindquat.push_back(0); skin->bindquat.push_back(0);
mjm_appendString(skin->bodyname, this_body);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back(-def[0].geom.spec.size[1]);
bindpos.push_back(0);
bindquat.push_back(1); bindquat.push_back(0);
bindquat.push_back(0); bindquat.push_back(0);
} else {
skin->bodyname.push_back(this_body);
skin->bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
skin->bindpos.push_back(def[0].geom.spec.size[1]);
skin->bindpos.push_back(0);
skin->bindquat.push_back(1); skin->bindquat.push_back(0);
skin->bindquat.push_back(0); skin->bindquat.push_back(0);
mjm_appendString(skin->bodyname, this_body);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back(def[0].geom.spec.size[1]);
bindpos.push_back(0);
bindquat.push_back(1); bindquat.push_back(0);
bindquat.push_back(0); bindquat.push_back(0);
}
// create vertid and vertweight
skin->vertid.push_back({ix*count[1]+iy, N + ix*count[1]+iy});
skin->vertweight.push_back({1, 1});
vertid.push_back({ix*count[1]+iy, N + ix*count[1]+iy});
vertweight.push_back({1, 1});
}
}
}
void mjCComposite::MakeCableBonesSubgrid(mjCModel* model, mjCSkin* skin) {
void mjCComposite::MakeCableBonesSubgrid(mjCModel* model, mjmSkin* skin) {
// populate bones
for (int ix=0; ix<count[0]; ix++) {
for (int iy=0; iy<count[1]; iy++) {
@@ -1509,27 +1535,27 @@ void mjCComposite::MakeCableBonesSubgrid(mjCModel* model, mjCSkin* skin) {
// bind pose
if (iy==0) {
skin->bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
skin->bindpos.push_back(-def[0].geom.spec.size[1]);
skin->bindpos.push_back(0);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back(-def[0].geom.spec.size[1]);
bindpos.push_back(0);
} else if (iy==2) {
skin->bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
skin->bindpos.push_back(def[0].geom.spec.size[1]);
skin->bindpos.push_back(0);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back(def[0].geom.spec.size[1]);
bindpos.push_back(0);
} else {
skin->bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
skin->bindpos.push_back(0);
skin->bindpos.push_back(0);
bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0);
bindpos.push_back(0);
bindpos.push_back(0);
}
skin->bodyname.push_back(txt);
skin->bindquat.push_back(1);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
mjm_appendString(skin->bodyname, txt);
bindquat.push_back(1);
bindquat.push_back(0);
bindquat.push_back(0);
bindquat.push_back(0);
// empty vertid and vertweight
skin->vertid.push_back({});
skin->vertweight.push_back({});
vertid.push_back({});
vertweight.push_back({});
}
}
}
@@ -1846,10 +1872,10 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) {
// add skin, set name and material
char txt[100];
mjCSkin* skin = model->AddSkin();
mjmSkin* skin = mjm_addSkin(model);
mju::sprintf_arr(txt, "%sSkin", prefix.c_str());
skin->name = txt;
skin->set_material(skinmaterial);
mjm_setString(skin->name, txt);
mjm_setString(skin->material, skinmaterial.c_str());
mjuu_copyvec(skin->rgba, skinrgba, 4);
skin->inflate = inflate;
skin->group = skingroup;
@@ -1863,25 +1889,25 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) {
for (int ix=0; ix<C0; ix++) {
for (int iy=0; iy<C1; iy++) {
// vertex
skin->vert.push_back(ix*S);
skin->vert.push_back(iy*S);
skin->vert.push_back(0);
vert.push_back(ix*S);
vert.push_back(iy*S);
vert.push_back(0);
// texture coordinate
if (skintexcoord) {
skin->texcoord.push_back(ix/(float)(C0-1));
skin->texcoord.push_back(iy/(float)(C1-1));
texcoord.push_back(ix/(float)(C0-1));
texcoord.push_back(iy/(float)(C1-1));
}
// face
if (ix<C0-1 && iy<C1-1) {
skin->face.push_back(i*NN + ix*C1+iy);
skin->face.push_back(i*NN + (ix+1)*C1+iy+(i==1));
skin->face.push_back(i*NN + (ix+1)*C1+iy+(i==0));
face.push_back(i*NN + ix*C1+iy);
face.push_back(i*NN + (ix+1)*C1+iy+(i==1));
face.push_back(i*NN + (ix+1)*C1+iy+(i==0));
skin->face.push_back(i*NN + ix*C1+iy);
skin->face.push_back(i*NN + (ix+(i==0))*C1+iy+1);
skin->face.push_back(i*NN + (ix+(i==1))*C1+iy+1);
face.push_back(i*NN + ix*C1+iy);
face.push_back(i*NN + (ix+(i==0))*C1+iy+1);
face.push_back(i*NN + (ix+(i==1))*C1+iy+1);
}
}
}
@@ -1889,46 +1915,46 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) {
// add thin triangles: X direction, iy = 0
for (int ix=0; ix<C0-1; ix++) {
skin->face.push_back(ix*C1);
skin->face.push_back(NN + (ix+1)*C1);
skin->face.push_back((ix+1)*C1);
face.push_back(ix*C1);
face.push_back(NN + (ix+1)*C1);
face.push_back((ix+1)*C1);
skin->face.push_back(ix*C1);
skin->face.push_back(NN + ix*C1);
skin->face.push_back(NN + (ix+1)*C1);
face.push_back(ix*C1);
face.push_back(NN + ix*C1);
face.push_back(NN + (ix+1)*C1);
}
// add thin triangles: X direction, iy = C1-1
for (int ix=0; ix<C0-1; ix++) {
skin->face.push_back(ix*C1 + C1-1);
skin->face.push_back((ix+1)*C1 + C1-1);
skin->face.push_back(NN + (ix+1)*C1 + C1-1);
face.push_back(ix*C1 + C1-1);
face.push_back((ix+1)*C1 + C1-1);
face.push_back(NN + (ix+1)*C1 + C1-1);
skin->face.push_back(ix*C1 + C1-1);
skin->face.push_back(NN + (ix+1)*C1 + C1-1);
skin->face.push_back(NN + ix*C1 + C1-1);
face.push_back(ix*C1 + C1-1);
face.push_back(NN + (ix+1)*C1 + C1-1);
face.push_back(NN + ix*C1 + C1-1);
}
// add thin triangles: Y direction, ix = 0
for (int iy=0; iy<C1-1; iy++) {
skin->face.push_back(iy);
skin->face.push_back(iy+1);
skin->face.push_back(NN + iy+1);
face.push_back(iy);
face.push_back(iy+1);
face.push_back(NN + iy+1);
skin->face.push_back(iy);
skin->face.push_back(NN + iy+1);
skin->face.push_back(NN + iy);
face.push_back(iy);
face.push_back(NN + iy+1);
face.push_back(NN + iy);
}
// add thin triangles: Y direction, ix = C0-1
for (int iy=0; iy<C1-1; iy++) {
skin->face.push_back(iy + (C0-1)*C1);
skin->face.push_back(NN + iy+1 + (C0-1)*C1);
skin->face.push_back(iy+1 + (C0-1)*C1);
face.push_back(iy + (C0-1)*C1);
face.push_back(NN + iy+1 + (C0-1)*C1);
face.push_back(iy+1 + (C0-1)*C1);
skin->face.push_back(iy + (C0-1)*C1);
skin->face.push_back(NN + iy + (C0-1)*C1);
skin->face.push_back(NN + iy+1 + (C0-1)*C1);
face.push_back(iy + (C0-1)*C1);
face.push_back(NN + iy + (C0-1)*C1);
face.push_back(NN + iy+1 + (C0-1)*C1);
}
if (type==mjCOMPTYPE_PARTICLE || type==mjCOMPTYPE_GRID) {
@@ -1966,10 +1992,10 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) {
for (int bi=0; bi<16; bi++) {
mjtNum w = Weight[d*N*16 + n*16 + bi];
if (w) {
skin->vertid[boneid[bi]].push_back(vid);
skin->vertid[boneid[bi]].push_back(vid+NN);
skin->vertweight[boneid[bi]].push_back((float)w);
skin->vertweight[boneid[bi]].push_back((float)w);
vertid[boneid[bi]].push_back(vid);
vertid[boneid[bi]].push_back(vid+NN);
vertweight[boneid[bi]].push_back((float)w);
vertweight[boneid[bi]].push_back((float)w);
}
}
}
@@ -1977,6 +2003,8 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) {
}
}
CopyIntoSkin(skin);
// free allocations
mju_free(XY);
mju_free(XY_W);
@@ -1999,10 +2027,10 @@ void mjCComposite::MakeSkin3(mjCModel* model) {
mju::sprintf_arr(cnt2, "%d", count[2]-1);
// add skin, set name and material
mjCSkin* skin = model->AddSkin();
mjmSkin* skin = mjm_addSkin(model);
mju::sprintf_arr(txt, "%sSkin", prefix.c_str());
skin->name = txt;
skin->set_material(skinmaterial);
mjm_setString(skin->name, txt);
mjm_setString(skin->material, skinmaterial.c_str());
mjuu_copyvec(skin->rgba, skinrgba, 4);
skin->inflate = skininflate;
skin->group = skingroup;
@@ -2038,9 +2066,9 @@ void mjCComposite::MakeSkin3(mjCModel* model) {
mju::sprintf_arr(txt, "%sB%d_%d_%d", prefix.c_str(), ix, iy, iz);
// add vertex
skin->vert.push_back(0);
skin->vert.push_back(0);
skin->vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
// texture coordinate
if (skintexcoord) {
@@ -2053,8 +2081,8 @@ void mjCComposite::MakeSkin3(mjCModel* model) {
Y = iz/(float)(count[2]-1);
}
skin->texcoord.push_back(X);
skin->texcoord.push_back(Y);
texcoord.push_back(X);
texcoord.push_back(Y);
}
// save vertex id in map
@@ -2095,9 +2123,9 @@ void mjCComposite::MakeSkin3(mjCModel* model) {
mju::sprintf_arr(txt, "%sB%d_%d_%d", prefix.c_str(), ix, iy, iz);
// add vertex
skin->vert.push_back(0);
skin->vert.push_back(0);
skin->vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
// texture coordinate
if (skintexcoord) {
@@ -2113,8 +2141,8 @@ void mjCComposite::MakeSkin3(mjCModel* model) {
Y = iy/(float)(count[1]-1);
}
skin->texcoord.push_back(X);
skin->texcoord.push_back(Y);
texcoord.push_back(X);
texcoord.push_back(Y);
}
// save vertex id in map
@@ -2140,12 +2168,14 @@ void mjCComposite::MakeSkin3(mjCModel* model) {
fmt = "%sB" + string(cnt0) + "_%d_%d";
MakeSkin3Smooth(skin, count[1], count[2], 0, vmap, fmt.c_str());
}
CopyIntoSkin(skin);
}
// make one face of 3D skin, box
void mjCComposite::MakeSkin3Box(mjCSkin* skin, int c0, int c1, int side,
void mjCComposite::MakeSkin3Box(mjmSkin* skin, int c0, int c1, int side,
int& vcnt, const char* format) {
char txt[100];
@@ -2153,47 +2183,43 @@ void mjCComposite::MakeSkin3Box(mjCSkin* skin, int c0, int c1, int side,
for (int i0=0; i0<c0; i0++) {
for (int i1=0; i1<c1; i1++) {
// vertex
skin->vert.push_back(0);
skin->vert.push_back(0);
skin->vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
vert.push_back(0);
// texture coordinate
if (skintexcoord) {
skin->texcoord.push_back(i0/(float)(c0-1));
skin->texcoord.push_back(i1/(float)(c1-1));
texcoord.push_back(i0/(float)(c0-1));
texcoord.push_back(i1/(float)(c1-1));
}
// face
if (i0<c0-1 && i1<c1-1) {
skin->face.push_back(vcnt + i0*c1+i1);
skin->face.push_back(vcnt + (i0+1)*c1+i1+(side==1));
skin->face.push_back(vcnt + (i0+1)*c1+i1+(side==0));
face.push_back(vcnt + i0*c1+i1);
face.push_back(vcnt + (i0+1)*c1+i1+(side==1));
face.push_back(vcnt + (i0+1)*c1+i1+(side==0));
skin->face.push_back(vcnt + i0*c1+i1);
skin->face.push_back(vcnt + (i0+(side==0))*c1+i1+1);
skin->face.push_back(vcnt + (i0+(side==1))*c1+i1+1);
face.push_back(vcnt + i0*c1+i1);
face.push_back(vcnt + (i0+(side==0))*c1+i1+1);
face.push_back(vcnt + (i0+(side==1))*c1+i1+1);
}
// body name
mju::sprintf_arr(txt, format, prefix.c_str(), i0, i1);
// bind pose: origin
skin->bodyname.push_back(txt);
skin->bindpos.push_back(0);
skin->bindpos.push_back(0);
skin->bindpos.push_back(0);
skin->bindquat.push_back(1);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
mjm_appendString(skin->bodyname, txt);
bindpos.push_back(0);
bindpos.push_back(0);
bindpos.push_back(0);
bindquat.push_back(1);
bindquat.push_back(0);
bindquat.push_back(0);
bindquat.push_back(0);
// vertid and vertweight
vector<int> vertid;
vector<float> vertweight;
vertid.push_back(vcnt + i0*c1+i1);
vertweight.push_back(1);
skin->vertid.push_back(vertid);
skin->vertweight.push_back(vertweight);
vertid.push_back({vcnt + i0*c1+i1});
vertweight.push_back({1});
}
}
@@ -2204,7 +2230,7 @@ void mjCComposite::MakeSkin3Box(mjCSkin* skin, int c0, int c1, int side,
// make one face of 3D skin, smooth
void mjCComposite::MakeSkin3Smooth(mjCSkin* skin, int c0, int c1, int side,
void mjCComposite::MakeSkin3Smooth(mjmSkin* skin, int c0, int c1, int side,
const std::map<string, int>& vmap, const char* format) {
char txt00[100], txt01[100], txt10[100], txt11[100];
@@ -2220,41 +2246,37 @@ void mjCComposite::MakeSkin3Smooth(mjCSkin* skin, int c0, int c1, int side,
// face
if (i0<c0-1 && i1<c1-1) {
if (side==0) {
skin->face.push_back(vmap.find(txt00)->second);
skin->face.push_back(vmap.find(txt10)->second);
skin->face.push_back(vmap.find(txt11)->second);
face.push_back(vmap.find(txt00)->second);
face.push_back(vmap.find(txt10)->second);
face.push_back(vmap.find(txt11)->second);
skin->face.push_back(vmap.find(txt00)->second);
skin->face.push_back(vmap.find(txt11)->second);
skin->face.push_back(vmap.find(txt01)->second);
face.push_back(vmap.find(txt00)->second);
face.push_back(vmap.find(txt11)->second);
face.push_back(vmap.find(txt01)->second);
} else {
skin->face.push_back(vmap.find(txt00)->second);
skin->face.push_back(vmap.find(txt01)->second);
skin->face.push_back(vmap.find(txt11)->second);
face.push_back(vmap.find(txt00)->second);
face.push_back(vmap.find(txt01)->second);
face.push_back(vmap.find(txt11)->second);
skin->face.push_back(vmap.find(txt00)->second);
skin->face.push_back(vmap.find(txt11)->second);
skin->face.push_back(vmap.find(txt10)->second);
face.push_back(vmap.find(txt00)->second);
face.push_back(vmap.find(txt11)->second);
face.push_back(vmap.find(txt10)->second);
}
}
// bind pose: origin
skin->bodyname.push_back(txt00);
skin->bindpos.push_back(0);
skin->bindpos.push_back(0);
skin->bindpos.push_back(0);
skin->bindquat.push_back(1);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
skin->bindquat.push_back(0);
mjm_appendString(skin->bodyname, txt00);
bindpos.push_back(0);
bindpos.push_back(0);
bindpos.push_back(0);
bindquat.push_back(1);
bindquat.push_back(0);
bindquat.push_back(0);
bindquat.push_back(0);
// vertid and vertweight
vector<int> vertid;
vector<float> vertweight;
vertid.push_back(vmap.find(txt00)->second);
vertweight.push_back(1);
skin->vertid.push_back(vertid);
skin->vertweight.push_back(vertweight);
vertid.push_back({vmap.find(txt00)->second});
vertweight.push_back({1});
}
}
}
+17 -6
View File
@@ -20,6 +20,7 @@
#include <vector>
#include <mujoco/mjmodel.h>
#include "user/user_api.h"
#include "user/user_model.h"
#include "user/user_objects.h"
@@ -79,14 +80,14 @@ class mjCComposite {
void MakeSkin2(mjCModel* model, mjtNum inflate);
void MakeSkin2Subgrid(mjCModel* model, mjtNum inflate);
void MakeClothBones(mjCModel* model, mjCSkin* skin);
void MakeClothBonesSubgrid(mjCModel* model, mjCSkin* skin);
void MakeCableBones(mjCModel* model, mjCSkin* skin);
void MakeCableBonesSubgrid(mjCModel* model, mjCSkin* skin);
void MakeClothBones(mjCModel* model, mjmSkin* skin);
void MakeClothBonesSubgrid(mjCModel* model, mjmSkin* skin);
void MakeCableBones(mjCModel* model, mjmSkin* skin);
void MakeCableBonesSubgrid(mjCModel* model, mjmSkin* skin);
void MakeSkin3(mjCModel* model);
void MakeSkin3Box(mjCSkin* skin, int c0, int c1, int side, int& vcnt, const char* format);
void MakeSkin3Smooth(mjCSkin* skin, int c0, int c1, int side,
void MakeSkin3Box(mjmSkin* skin, int c0, int c1, int side, int& vcnt, const char* format);
void MakeSkin3Smooth(mjmSkin* skin, int c0, int c1, int side,
const std::map<std::string, int>& vmap, const char* format);
void BoxProject(double* pos);
@@ -138,6 +139,16 @@ class mjCComposite {
private:
mjmBody* AddRopeBody(mjCModel* model, mjmBody* body, int ix, int ix1);
mjmBody* AddCableBody(mjCModel* model, mjmBody* body, int ix, mjtNum normal[3], mjtNum prev_quat[4]);
// temporary skin vectors
void CopyIntoSkin(mjmSkin* skin);
std::vector<int> face;
std::vector<float> vert;
std::vector<float> bindpos;
std::vector<float> bindquat;
std::vector<float> texcoord;
std::vector<std::vector<int>> vertid;
std::vector<std::vector<float>> vertweight;
};
#endif // MUJOCO_SRC_USER_USER_COMPOSITE_H_
+3 -3
View File
@@ -385,7 +385,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz
// rigid: set parent name, nothing else to do
if (rigid) {
mjm_addToStringVec(pf->vertbody, mjm_getString(body->name));
mjm_appendString(pf->vertbody, mjm_getString(body->name));
return true;
}
@@ -402,7 +402,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz
// pinned: parent body
if (pinned[i]) {
mjm_addToStringVec(pf->vertbody, mjm_getString(body->name));
mjm_appendString(pf->vertbody, mjm_getString(body->name));
// add plugin
if (plugin_instance) {
@@ -459,7 +459,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz
char txt[100];
mju::sprintf_arr(txt, "%s_%d", name.c_str(), i);
mjm_setString(pb->name, txt);
mjm_addToStringVec(pf->vertbody, mjm_getString(pb->name));
mjm_appendString(pf->vertbody, mjm_getString(pb->name));
// clear flex vertex coordinates if allocated
if (!centered) {
+11
View File
@@ -210,6 +210,17 @@ void mjm_defaultHField(mjmHField& hfield) {
// default skin attributes
void mjm_defaultSkin(mjmSkin& skin) {
memset(&skin, 0, sizeof(mjmSkin));
skin.rgba[0] = skin.rgba[1] = skin.rgba[2] = 0.5f;
skin.rgba[3] = 1.0f;
skin.inflate = 0;
skin.group = 0;
}
// default texture attributes
void mjm_defaultTexture(mjmTexture& texture) {
memset(&texture, 0, sizeof(mjmTexture));
+139 -90
View File
@@ -1829,45 +1829,92 @@ void mjCMesh::MakeCenter(void) {
// constructor
mjCSkin::mjCSkin(mjCModel* _model) {
mjm_defaultSkin(spec);
// set model pointer
model = _model;
// clear data
file.clear();
material_.clear();
rgba[0] = rgba[1] = rgba[2] = 0.5f;
rgba[3] = 1.0f;
inflate = 0;
group = 0;
spec_file_.clear();
spec_material_.clear();
spec_vert_.clear();
spec_texcoord_.clear();
spec_face_.clear();
spec_bodyname_.clear();
spec_bindpos_.clear();
spec_bindquat_.clear();
spec_vertid_.clear();
spec_vertweight_.clear();
vert.clear();
texcoord.clear();
face.clear();
bodyname.clear();
bindpos.clear();
bindquat.clear();
vertid.clear();
vertweight.clear();
bodyid.clear();
matid = -1;
// point to local (needs to be after defaults)
PointToLocal();
// in case this camera is not compiled
CopyFromSpec();
}
void mjCSkin::PointToLocal() {
spec.element = (mjElement)this;
spec.name = (mjString)&name;
spec.classname = (mjString)&classname;
spec.file = (mjString)&spec_file_;
spec.material = (mjString)&spec_material_;
spec.vert = (mjFloatVec)&spec_vert_;
spec.texcoord = (mjFloatVec)&spec_texcoord_;
spec.face = (mjIntVec)&spec_face_;
spec.bodyname = (mjStringVec)&spec_bodyname_;
spec.bindpos = (mjFloatVec)&spec_bindpos_;
spec.bindquat = (mjFloatVec)&spec_bindquat_;
spec.vertid = (mjIntVecVec)&spec_vertid_;
spec.vertweight = (mjFloatVecVec)&spec_vertweight_;
spec.info = (mjString)&info;
}
void mjCSkin::CopyFromSpec() {
*static_cast<mjmSkin*>(this) = spec;
file_ = spec_file_;
material_ = spec_material_;
vert_ = spec_vert_;
texcoord_ = spec_texcoord_;
face_ = spec_face_;
bodyname_ = spec_bodyname_;
bindpos_ = spec_bindpos_;
bindquat_ = spec_bindquat_;
vertid_ = spec_vertid_;
vertweight_ = spec_vertweight_;
file = (mjString)&spec_file_;
material = (mjString)&spec_material_;
vert = (mjFloatVec)&spec_vert_;
texcoord = (mjFloatVec)&spec_texcoord_;
face = (mjIntVec)&spec_face_;
bodyname = (mjStringVec)&spec_bodyname_;
bindpos = (mjFloatVec)&spec_bindpos_;
bindquat = (mjFloatVec)&spec_bindquat_;
vertid = (mjIntVecVec)&spec_vertid_;
vertweight = (mjFloatVecVec)&spec_vertweight_;
}
// destructor
mjCSkin::~mjCSkin() {
file.clear();
material_.clear();
vert.clear();
texcoord.clear();
face.clear();
bodyname.clear();
bindpos.clear();
bindquat.clear();
vertid.clear();
vertweight.clear();
spec_file_.clear();
spec_material_.clear();
spec_vert_.clear();
spec_texcoord_.clear();
spec_face_.clear();
spec_bodyname_.clear();
spec_bindpos_.clear();
spec_bindquat_.clear();
spec_vertid_.clear();
spec_vertweight_.clear();
bodyid.clear();
}
@@ -1875,33 +1922,35 @@ mjCSkin::~mjCSkin() {
// compiler
void mjCSkin::Compile(const mjVFS* vfs) {
CopyFromSpec();
// load file
if (!file.empty()) {
if (!file_.empty()) {
// make sure data is not present
if (!vert.empty() ||
!texcoord.empty() ||
!face.empty() ||
!bodyname.empty() ||
!bindpos.empty() ||
!bindquat.empty() ||
!vertid.empty() ||
!vertweight.empty() ||
if (!vert_.empty() ||
!texcoord_.empty() ||
!face_.empty() ||
!bodyname_.empty() ||
!bindpos_.empty() ||
!bindquat_.empty() ||
!vertid_.empty() ||
!vertweight_.empty() ||
!bodyid.empty()) {
throw mjCError(this, "Data already exists, trying to load from skin file: %s", file.c_str());
throw mjCError(this, "Data already exists, trying to load from skin file: %s", file_.c_str());
}
// remove path from file if necessary
if (model->strippath) {
file = mjuu_strippath(file);
file_ = mjuu_strippath(file_);
}
// load SKN
string ext = mjuu_getext(file);
string ext = mjuu_getext(file_);
if (strcasecmp(ext.c_str(), ".skn")) {
throw mjCError(this, "Unknown skin file type: %s", file.c_str());
throw mjCError(this, "Unknown skin file type: %s", file_.c_str());
}
string filename = mjuu_makefullname(model->modelfiledir, model->meshdir, file);
string filename = mjuu_makefullname(model->modelfiledir, model->meshdir, file_);
mjResource* resource = LoadResource(filename, vfs);
try {
@@ -1914,48 +1963,48 @@ void mjCSkin::Compile(const mjVFS* vfs) {
}
// make sure all data is present
if (vert.empty() ||
face.empty() ||
bodyname.empty() ||
bindpos.empty() ||
bindquat.empty() ||
vertid.empty() ||
vertweight.empty()) {
if (vert_.empty() ||
face_.empty() ||
bodyname_.empty() ||
bindpos_.empty() ||
bindquat_.empty() ||
vertid_.empty() ||
vertweight_.empty()) {
throw mjCError(this, "Missing data in skin");
}
// check mesh sizes
if (vert.size()%3) {
if (vert_.size()%3) {
throw mjCError(this, "Vertex data must be multiple of 3");
}
if (!texcoord.empty() && texcoord.size()!=2*vert.size()/3) {
if (!texcoord_.empty() && texcoord_.size()!=2*vert_.size()/3) {
throw mjCError(this, "Vertex and texcoord data incompatible size");
}
if (face.size()%3) {
if (face_.size()%3) {
throw mjCError(this, "Face data must be multiple of 3");
}
// check bone sizes
size_t nbone = bodyname.size();
if (bindpos.size()!=3*nbone) {
size_t nbone = bodyname_.size();
if (bindpos_.size()!=3*nbone) {
throw mjCError(this, "Unexpected bindpos size in skin");
}
if (bindquat.size()!=4*nbone) {
if (bindquat_.size()!=4*nbone) {
throw mjCError(this, "Unexpected bindquat size in skin");
}
if (vertid.size()!=nbone) {
if (vertid_.size()!=nbone) {
throw mjCError(this, "Unexpected vertid size in skin");
}
if (vertweight.size()!=nbone) {
if (vertweight_.size()!=nbone) {
throw mjCError(this, "Unexpected vertweight size in skin");
}
// resolve body names
bodyid.resize(nbone);
for (int i=0; i<nbone; i++) {
mjCBase* pbody = model->FindObject(mjOBJ_BODY, bodyname[i]);
mjCBase* pbody = model->FindObject(mjOBJ_BODY, bodyname_[i]);
if (!pbody) {
throw mjCError(this, "unknown body '%s' in skin", bodyname[i].c_str());
throw mjCError(this, "unknown body '%s' in skin", bodyname_[i].c_str());
}
bodyid[i] = pbody->id;
}
@@ -1970,28 +2019,28 @@ void mjCSkin::Compile(const mjVFS* vfs) {
// set total vertex weights to 0
vector<float> vw;
size_t nvert = vert.size()/3;
size_t nvert = vert_.size()/3;
vw.resize(nvert);
fill(vw.begin(), vw.end(), 0.0f);
// accumulate vertex weights from all bones
for (int i=0; i<nbone; i++) {
// make sure bone has vertices and sizes match
size_t nbv = vertid[i].size();
if (vertweight[i].size()!=nbv || nbv==0) {
size_t nbv = vertid_[i].size();
if (vertweight_[i].size()!=nbv || nbv==0) {
throw mjCError(this, "vertid and vertweight must have same non-zero size in skin");
}
// accumulate weights in global array
for (int j=0; j<nbv; j++) {
// get index and check range
int jj = vertid[i][j];
int jj = vertid_[i][j];
if (jj<0 || jj>=nvert) {
throw mjCError(this, "vertid %d out of range in skin", NULL, jj);
}
// accumulate
vw[jj] += vertweight[i][j];
vw[jj] += vertweight_[i][j];
}
}
@@ -2004,25 +2053,25 @@ void mjCSkin::Compile(const mjVFS* vfs) {
// normalize vertex weights
for (int i=0; i<nbone; i++) {
for (int j=0; j<vertid[i].size(); j++) {
vertweight[i][j] /= vw[vertid[i][j]];
for (int j=0; j<vertid_[i].size(); j++) {
vertweight_[i][j] /= vw[vertid_[i][j]];
}
}
// normalize bindquat
for (int i=0; i<nbone; i++) {
mjtNum quat[4] = {
(mjtNum)bindquat[4*i],
(mjtNum)bindquat[4*i+1],
(mjtNum)bindquat[4*i+2],
(mjtNum)bindquat[4*i+3]
(mjtNum)bindquat_[4*i],
(mjtNum)bindquat_[4*i+1],
(mjtNum)bindquat_[4*i+2],
(mjtNum)bindquat_[4*i+3]
};
mju_normalize4(quat);
bindquat[4*i] = (float) quat[0];
bindquat[4*i+1] = (float) quat[1];
bindquat[4*i+2] = (float) quat[2];
bindquat[4*i+3] = (float) quat[3];
bindquat_[4*i] = (float) quat[0];
bindquat_[4*i+1] = (float) quat[1];
bindquat_[4*i+2] = (float) quat[2];
bindquat_[4*i+3] = (float) quat[3];
}
}
@@ -2066,31 +2115,31 @@ void mjCSkin::LoadSKN(mjResource* resource) {
// copy vert
if (nvert) {
vert.resize(3*nvert);
memcpy(vert.data(), pdata+cnt, 3*nvert*sizeof(float));
vert_.resize(3*nvert);
memcpy(vert_.data(), pdata+cnt, 3*nvert*sizeof(float));
cnt += 3*nvert;
}
// copy texcoord
if (ntexcoord) {
texcoord.resize(2*ntexcoord);
memcpy(texcoord.data(), pdata+cnt, 2*ntexcoord*sizeof(float));
texcoord_.resize(2*ntexcoord);
memcpy(texcoord_.data(), pdata+cnt, 2*ntexcoord*sizeof(float));
cnt += 2*ntexcoord;
}
// copy face
if (nface) {
face.resize(3*nface);
memcpy(face.data(), pdata+cnt, 3*nface*sizeof(int));
face_.resize(3*nface);
memcpy(face_.data(), pdata+cnt, 3*nface*sizeof(int));
cnt += 3*nface;
}
// allocate bone arrays
bodyname.clear();
bindpos.resize(3*nbone);
bindquat.resize(4*nbone);
vertid.resize(nbone);
vertweight.resize(nbone);
bodyname_.clear();
bindpos_.resize(3*nbone);
bindquat_.resize(4*nbone);
vertid_.resize(nbone);
vertweight_.resize(nbone);
// read bones
for (int i=0; i<nbone; i++) {
@@ -2104,14 +2153,14 @@ void mjCSkin::LoadSKN(mjResource* resource) {
strncpy(txt, (char*)(pdata+cnt), 39);
txt[39] = '\0';
cnt += 10;
bodyname.push_back(txt);
bodyname_.push_back(txt);
// read bindpos
memcpy(bindpos.data()+3*i, pdata+cnt, 3*sizeof(float));
memcpy(bindpos_.data()+3*i, pdata+cnt, 3*sizeof(float));
cnt += 3;
// read bind quat
memcpy(bindquat.data()+4*i, pdata+cnt, 4*sizeof(float));
memcpy(bindquat_.data()+4*i, pdata+cnt, 4*sizeof(float));
cnt += 4;
// read vertex count
@@ -2131,13 +2180,13 @@ void mjCSkin::LoadSKN(mjResource* resource) {
}
// read vertid
vertid[i].resize(vcount);
memcpy(vertid[i].data(), (int*)(pdata+cnt), vcount*sizeof(int));
vertid_[i].resize(vcount);
memcpy(vertid_[i].data(), (int*)(pdata+cnt), vcount*sizeof(int));
cnt += vcount;
// read vertweight
vertweight[i].resize(vcount);
memcpy(vertweight[i].data(), (int*)(pdata+cnt), vcount*sizeof(int));
vertweight_[i].resize(vcount);
memcpy(vertweight_[i].data(), (int*)(pdata+cnt), vcount*sizeof(int));
cnt += vcount;
}
+22 -22
View File
@@ -1044,12 +1044,12 @@ void mjCModel::SetSizes(void) {
// skin counts
for (int i=0; i<nskin; i++) {
nskinvert += skins[i]->vert.size()/3;
nskintexvert += skins[i]->texcoord.size()/2;
nskinface += skins[i]->face.size()/3;
nskinvert += skins[i]->get_vert().size()/3;
nskintexvert += skins[i]->get_texcoord().size()/2;
nskinface += skins[i]->get_face().size()/3;
nskinbone += skins[i]->bodyid.size();
for (int j=0; j<skins[i]->bodyid.size(); j++) {
nskinbonevert += skins[i]->vertid[j].size();
nskinbonevert += skins[i]->get_vertid()[j].size();
}
}
@@ -2094,25 +2094,25 @@ void mjCModel::CopyObjects(mjModel* m) {
copyvec(m->skin_rgba+4*i, psk->rgba, 4);
m->skin_inflate[i] = psk->inflate;
m->skin_vertadr[i] = vert_adr;
m->skin_vertnum[i] = psk->vert.size()/3;
m->skin_texcoordadr[i] = (!psk->texcoord.empty() ? texcoord_adr : -1);
m->skin_vertnum[i] = psk->get_vert().size()/3;
m->skin_texcoordadr[i] = (!psk->get_texcoord().empty() ? texcoord_adr : -1);
m->skin_faceadr[i] = face_adr;
m->skin_facenum[i] = psk->face.size()/3;
m->skin_facenum[i] = psk->get_face().size()/3;
m->skin_boneadr[i] = bone_adr;
m->skin_bonenum[i] = psk->bodyid.size();
// copy mesh data
memcpy(m->skin_vert + 3*vert_adr, psk->vert.data(), psk->vert.size()*sizeof(float));
if (!psk->texcoord.empty())
memcpy(m->skin_texcoord + 2*texcoord_adr, psk->texcoord.data(),
psk->texcoord.size()*sizeof(float));
memcpy(m->skin_face + 3*face_adr, psk->face.data(), psk->face.size()*sizeof(int));
memcpy(m->skin_vert + 3*vert_adr, psk->get_vert().data(), psk->get_vert().size()*sizeof(float));
if (!psk->get_texcoord().empty())
memcpy(m->skin_texcoord + 2*texcoord_adr, psk->get_texcoord().data(),
psk->get_texcoord().size()*sizeof(float));
memcpy(m->skin_face + 3*face_adr, psk->get_face().data(), psk->get_face().size()*sizeof(int));
// copy bind poses and body ids
memcpy(m->skin_bonebindpos+3*bone_adr, psk->bindpos.data(),
psk->bindpos.size()*sizeof(float));
memcpy(m->skin_bonebindquat+4*bone_adr, psk->bindquat.data(),
psk->bindquat.size()*sizeof(float));
memcpy(m->skin_bonebindpos+3*bone_adr, psk->get_bindpos().data(),
psk->get_bindpos().size()*sizeof(float));
memcpy(m->skin_bonebindquat+4*bone_adr, psk->get_bindquat().data(),
psk->get_bindquat().size()*sizeof(float));
memcpy(m->skin_bonebodyid+bone_adr, psk->bodyid.data(),
psk->bodyid.size()*sizeof(int));
@@ -2120,13 +2120,13 @@ void mjCModel::CopyObjects(mjModel* m) {
for (int j=0; j<m->skin_bonenum[i]; j++) {
// set fields
m->skin_bonevertadr[bone_adr+j] = bonevert_adr;
m->skin_bonevertnum[bone_adr+j] = (int)psk->vertid[j].size();
m->skin_bonevertnum[bone_adr+j] = (int)psk->get_vertid()[j].size();
// copy data
memcpy(m->skin_bonevertid+bonevert_adr, psk->vertid[j].data(),
psk->vertid[j].size()*sizeof(int));
memcpy(m->skin_bonevertweight+bonevert_adr, psk->vertweight[j].data(),
psk->vertid[j].size()*sizeof(float));
memcpy(m->skin_bonevertid+bonevert_adr, psk->get_vertid()[j].data(),
psk->get_vertid()[j].size()*sizeof(int));
memcpy(m->skin_bonevertweight+bonevert_adr, psk->get_vertweight()[j].data(),
psk->get_vertid()[j].size()*sizeof(float));
// advance counter
bonevert_adr += m->skin_bonevertnum[bone_adr+j];
@@ -2134,7 +2134,7 @@ void mjCModel::CopyObjects(mjModel* m) {
// advance mesh and bone counters
vert_adr += m->skin_vertnum[i];
texcoord_adr += psk->texcoord.size()/2;
texcoord_adr += psk->get_texcoord().size()/2;
face_adr += m->skin_facenum[i];
bone_adr += m->skin_bonenum[i];
}
-1
View File
@@ -3677,7 +3677,6 @@ mjCEquality::mjCEquality(mjCModel* _model, mjCDef* _def) {
model = _model;
def = (_def ? _def : (_model ? _model->defaults[0] : 0));
// point to local (needs to be after defaults)
PointToLocal();
+40 -20
View File
@@ -771,32 +771,30 @@ class mjCMesh: public mjCBase, private mjmMesh {
//------------------------- class mjCSkin ----------------------------------------------------------
// Describes a skin
class mjCSkin: public mjCBase {
class mjCSkin: public mjCBase, private mjmSkin {
friend class mjCModel;
friend class mjXWriter;
public:
std::string get_file() const { return file; }
void set_material(std::string _material) { material_ = _material; }
mjmSkin spec;
using mjCBase::name;
using mjCBase::classname;
using mjCBase::info;
std::string get_file() const { return file_; }
std::string& get_material() { return material_; }
std::vector<float>& get_vert() { return vert_; }
std::vector<float>& get_texcoord() { return texcoord_; }
std::vector<int>& get_face() { return face_; }
std::vector<std::string>& get_bodyname() { return bodyname_; }
std::vector<float>& get_bindpos() { return bindpos_; }
std::vector<float>& get_bindquat() { return bindquat_; }
std::vector<std::vector<int>>& get_vertid() { return vertid_; }
std::vector<std::vector<float>>& get_vertweight() { return vertweight_; }
void del_material() { material_.clear(); }
std::string file; // skin file
float rgba[4]; // rgba when material is omitted
float inflate; // inflate in normal direction
int group; // group for visualization
// mesh
std::vector<float> vert; // vertex positions
std::vector<float> texcoord; // texture coordinates
std::vector<int> face; // faces
// skin
std::vector<std::string> bodyname; // body names
std::vector<float> bindpos; // bind pos
std::vector<float> bindquat; // bind quat
std::vector<std::vector<int>> vertid; // vertex ids
std::vector<std::vector<float>> vertweight; // vertex weights
void CopyFromSpec();
void PointToLocal();
private:
mjCSkin(mjCModel* = 0); // constructor
@@ -804,7 +802,29 @@ class mjCSkin: public mjCBase {
void Compile(const mjVFS* vfs); // compiler
void LoadSKN(mjResource* resource); // load skin in SKN BIN format
std::string material_; // name of material used for rendering
// variable size attributes
std::string file_;
std::string material_;
std::vector<float> vert_;
std::vector<float> texcoord_;
std::vector<int> face_;
std::vector<std::string> bodyname_;
std::vector<float> bindpos_;
std::vector<float> bindquat_;
std::vector<std::vector<int>> vertid_;
std::vector<std::vector<float>> vertweight_;
std::string spec_file_;
std::string spec_material_;
std::vector<float> spec_vert_;
std::vector<float> spec_texcoord_;
std::vector<int> spec_face_;
std::vector<std::string> spec_bodyname_;
std::vector<float> spec_bindpos_;
std::vector<float> spec_bindquat_;
std::vector<std::vector<int>> spec_vertid_;
std::vector<std::vector<float>> spec_vertweight_;
int matid; // material id
std::vector<int> bodyid; // body ids
};
+48 -21
View File
@@ -1416,14 +1416,20 @@ void mjXReader::OneMesh(XMLElement* elem, mjmMesh* pmesh) {
// skin element parser
void mjXReader::OneSkin(XMLElement* elem, mjCSkin* pskin) {
string text;
void mjXReader::OneSkin(XMLElement* elem, mjmSkin* pskin) {
string text, name, file, material;
float data[4];
// read attributes
ReadAttrTxt(elem, "name", pskin->name);
ReadAttrTxt(elem, "file", pskin->file);
ReadAttrTxt(elem, "material", pskin->get_material());
if (ReadAttrTxt(elem, "name", name)) {
mjm_setString(pskin->name, name.c_str());
}
if (ReadAttrTxt(elem, "file", file)) {
mjm_setString(pskin->file, file.c_str());
}
if (ReadAttrTxt(elem, "material", material)) {
mjm_setString(pskin->material, material.c_str());
}
ReadAttrInt(elem, "group", &pskin->group);
if (pskin->group<0 || pskin->group>=mjNGROUP) {
throw mjXError(elem, "skin group must be between 0 and 5");
@@ -1432,51 +1438,72 @@ void mjXReader::OneSkin(XMLElement* elem, mjCSkin* pskin) {
ReadAttr(elem, "inflate", 1, &pskin->inflate, text);
// read vertex data
if (ReadAttrTxt(elem, "vertex", text)) String2Vector(text, pskin->vert);
if (ReadAttrTxt(elem, "vertex", text)) {
std::vector<float> vert;
String2Vector(text, vert);
mjm_setFloat(pskin->vert, vert.data(), vert.size());
}
// read texcoord data
if (ReadAttrTxt(elem, "texcoord", text)) String2Vector(text, pskin->texcoord);
if (ReadAttrTxt(elem, "texcoord", text)) {
std::vector<float> texcoord;
String2Vector(text, texcoord);
mjm_setFloat(pskin->texcoord, texcoord.data(), texcoord.size());
}
// read user face data
if (ReadAttrTxt(elem, "face", text)) String2Vector(text, pskin->face);
if (ReadAttrTxt(elem, "face", text)) {
std::vector<int> face;
String2Vector(text, face);
mjm_setInt(pskin->face, face.data(), face.size());
}
// read bones
XMLElement* bone = FirstChildElement(elem, "bone");
std::vector<float> bindpos;
std::vector<float> bindquat;
while (bone) {
// read body
ReadAttrTxt(bone, "body", text, true);
pskin->bodyname.push_back(text);
mjm_appendString(pskin->bodyname, text.c_str());
// read bindpos
ReadAttr(bone, "bindpos", 3, data, text, true);
pskin->bindpos.push_back(data[0]);
pskin->bindpos.push_back(data[1]);
pskin->bindpos.push_back(data[2]);
bindpos.push_back(data[0]);
bindpos.push_back(data[1]);
bindpos.push_back(data[2]);
// read bindquat
ReadAttr(bone, "bindquat", 4, data, text, true);
pskin->bindquat.push_back(data[0]);
pskin->bindquat.push_back(data[1]);
pskin->bindquat.push_back(data[2]);
pskin->bindquat.push_back(data[3]);
bindquat.push_back(data[0]);
bindquat.push_back(data[1]);
bindquat.push_back(data[2]);
bindquat.push_back(data[3]);
// read vertid
vector<int> tempid;
ReadAttrTxt(bone, "vertid", text, true);
String2Vector(text, tempid);
pskin->vertid.push_back(tempid);
mjm_appendIntVec(pskin->vertid, tempid.data(), tempid.size());
// read vertweight
vector<float> tempweight;
ReadAttrTxt(bone, "vertweight", text, true);
String2Vector(text, tempweight);
pskin->vertweight.push_back(tempweight);
mjm_appendFloatVec(pskin->vertweight, tempweight.data(), tempweight.size());
// advance to next bone
bone = NextSiblingElement(bone, "bone");
}
GetXMLPos(elem, pskin);
// set bind vectors
mjm_setFloat(pskin->bindpos, bindpos.data(), bindpos.size());
mjm_setFloat(pskin->bindquat, bindquat.data(), bindquat.size());
// write error info
mjm_setString(pskin->info,
std::string("line = " + std::to_string(elem->GetLineNum()) + ", column = -1").c_str());
}
@@ -3129,7 +3156,7 @@ void mjXReader::Asset(XMLElement* section) {
// skin sub-element... deprecate ???
else if (name=="skin") {
// create skin and parse
mjCSkin* pskin = model->AddSkin();
mjmSkin* pskin = mjm_addSkin(model);
OneSkin(elem, pskin);
}
@@ -3498,7 +3525,7 @@ void mjXReader::Deformable(XMLElement* section) {
// skin sub-element
else if (name=="skin") {
// create skin and parse
mjCSkin* pskin = model->AddSkin();
mjmSkin* pskin = mjm_addSkin(model);
OneSkin(elem, pskin);
}
+1 -1
View File
@@ -60,7 +60,7 @@ class mjXReader : public mjXBase {
// single element parsers, used in defaults and main body
void OneFlex(tinyxml2::XMLElement* elem, mjmFlex* pflex);
void OneMesh(tinyxml2::XMLElement* elem, mjmMesh* pmesh);
void OneSkin(tinyxml2::XMLElement* elem, mjCSkin* pskin);
void OneSkin(tinyxml2::XMLElement* elem, mjmSkin* pskin);
void OneMaterial(tinyxml2::XMLElement* elem, mjmMaterial* pmaterial);
void OneJoint(tinyxml2::XMLElement* elem, mjmJoint* pjoint);
void OneGeom(tinyxml2::XMLElement* elem, mjmGeom* pgeom);
+12 -12
View File
@@ -205,44 +205,44 @@ void mjXWriter::OneSkin(XMLElement* elem, mjCSkin* pskin) {
// write attributes
WriteAttrTxt(elem, "name", pskin->name);
WriteAttrTxt(elem, "file", pskin->file);
WriteAttrTxt(elem, "file", pskin->get_file());
WriteAttrTxt(elem, "material", pskin->get_material());
WriteAttrInt(elem, "group", pskin->group, 0);
WriteAttr(elem, "rgba", 4, pskin->rgba, mydef.geom.rgba);
WriteAttr(elem, "inflate", 1, &pskin->inflate, &zero);
// write data if no file
if (pskin->file.empty()) {
if (pskin->get_file().empty()) {
// mesh vert
Vector2String(text, pskin->vert);
Vector2String(text, pskin->get_vert());
WriteAttrTxt(elem, "vertex", text);
// mesh texcoord
if (!pskin->texcoord.empty()) {
Vector2String(text, pskin->texcoord);
if (!pskin->get_texcoord().empty()) {
Vector2String(text, pskin->get_texcoord());
WriteAttrTxt(elem, "texcoord", text);
}
// mesh face
Vector2String(text, pskin->face);
Vector2String(text, pskin->get_face());
WriteAttrTxt(elem, "face", text);
// bones
for (size_t i=0; i<pskin->bodyname.size(); i++) {
for (size_t i=0; i<pskin->get_bodyname().size(); i++) {
// make bone
XMLElement* bone = InsertEnd(elem, "bone");
// write attributes
WriteAttrTxt(bone, "body", pskin->bodyname[i]);
WriteAttr(bone, "bindpos", 3, pskin->bindpos.data()+3*i);
WriteAttr(bone, "bindquat", 4, pskin->bindquat.data()+4*i);
WriteAttrTxt(bone, "body", pskin->get_bodyname()[i]);
WriteAttr(bone, "bindpos", 3, pskin->get_bindpos().data()+3*i);
WriteAttr(bone, "bindquat", 4, pskin->get_bindquat().data()+4*i);
// write vertid
Vector2String(text, pskin->vertid[i]);
Vector2String(text, pskin->get_vertid()[i]);
WriteAttrTxt(bone, "vertid", text);
// write vertweight
Vector2String(text, pskin->vertweight[i]);
Vector2String(text, pskin->get_vertweight()[i]);
WriteAttrTxt(bone, "vertweight", text);
}
}