Skip to content

Commit 7651cb1

Browse files
quaglacopybara-github
authored andcommitted
Copy texture coordinates from OBJ into flex. Fixes #2464.
PiperOrigin-RevId: 732109960 Change-Id: I506b3540ab5d489ce8f10d0c473919611ccb654a
1 parent 06e217d commit 7651cb1

19 files changed

+117
-15
lines changed

doc/XMLreference.rst

+8-3
Original file line numberDiff line numberDiff line change
@@ -3916,9 +3916,14 @@ cases, the user will specify a :el:`flexcomp` which will then automatically cons
39163916

39173917
.. _deformable-flex-texcoord:
39183918

3919-
:at:`texcoord`: :at-val:`real(2*nvert), optional`
3920-
Texture coordinates for each vertex. If omitted, texture mapping for this flex is disabled, even if a texture is
3921-
specified in the material.
3919+
:at:`texcoord`: :at-val:`real(2*vert or ntexcoord), optional`
3920+
Texture coordinates. If omitted, texture mapping for this flex is disabled, even if a texture is specified in the
3921+
material.
3922+
3923+
.. _deformable-flex-facetexcoord:
3924+
3925+
:at:`facetexcoord`: :at-val:`int((dim+1)*nelem), optional`
3926+
Texture indices for each face. If omitted, texture are assumed to be vertex-based.
39223927

39233928
.. _deformable-flex-element:
39243929

doc/XMLschema.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,9 @@
485485
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
486486
| | | | :ref:`material<deformable-flex-material>` | :ref:`rgba<deformable-flex-rgba>` | :ref:`flatskin<deformable-flex-flatskin>` | :ref:`body<deformable-flex-body>` | |
487487
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
488-
| | | | :ref:`vertex<deformable-flex-vertex>` | :ref:`element<deformable-flex-element>` | :ref:`texcoord<deformable-flex-texcoord>` | :ref:`node<deformable-flex-node>` | |
488+
| | | | :ref:`vertex<deformable-flex-vertex>` | :ref:`element<deformable-flex-element>` | :ref:`texcoord<deformable-flex-texcoord>` | :ref:`facetexcoord<deformable-flex-facetexcoord>` | |
489+
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
490+
| | | | :ref:`node<deformable-flex-node>` | | | | |
489491
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
490492
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
491493
| |_2| flex |br| |_2| |L| | | .. table:: |

doc/includes/references.h

+3
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,7 @@ struct mjModel_ {
11771177
int* flex_vertbodyid; // vertex body ids (nflexvert x 1)
11781178
int* flex_edge; // edge vertex ids (2 per edge) (nflexedge x 2)
11791179
int* flex_elem; // element vertex ids (dim+1 per elem) (nflexelemdata x 1)
1180+
int* flex_elemtexcoord; // element texture coordinates (dim+1) (nflexelemdata x 1)
11801181
int* flex_elemedge; // element edge ids (nflexelemedge x 1)
11811182
int* flex_elemlayer; // element distance from surface, 3D only (nflexelem x 1)
11821183
int* flex_shell; // shell fragment vertex ids (dim per frag) (nflexshelldata x 1)
@@ -2009,6 +2010,7 @@ typedef struct mjsFlex_ { // flex specification
20092010
mjDoubleVec* vert; // vertex positions
20102011
mjIntVec* elem; // element vertex ids
20112012
mjFloatVec* texcoord; // vertex texture coordinates
2013+
mjIntVec* facetexcoord; // face texture coordinates
20122014

20132015
// other
20142016
mjString* info; // message appended to compiler errors
@@ -2997,6 +2999,7 @@ struct mjvSceneState_ {
29972999
int* flex_vertadr;
29983000
int* flex_vertnum;
29993001
int* flex_elem;
3002+
int* flex_elemtexcoord;
30003003
int* flex_elemlayer;
30013004
int* flex_elemadr;
30023005
int* flex_elemnum;

include/mujoco/mjmodel.h

+1
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,7 @@ struct mjModel_ {
885885
int* flex_vertbodyid; // vertex body ids (nflexvert x 1)
886886
int* flex_edge; // edge vertex ids (2 per edge) (nflexedge x 2)
887887
int* flex_elem; // element vertex ids (dim+1 per elem) (nflexelemdata x 1)
888+
int* flex_elemtexcoord; // element texture coordinates (dim+1) (nflexelemdata x 1)
888889
int* flex_elemedge; // element edge ids (nflexelemedge x 1)
889890
int* flex_elemlayer; // element distance from surface, 3D only (nflexelem x 1)
890891
int* flex_shell; // shell fragment vertex ids (dim per frag) (nflexshelldata x 1)

include/mujoco/mjspec.h

+1
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ typedef struct mjsFlex_ { // flex specification
446446
mjDoubleVec* vert; // vertex positions
447447
mjIntVec* elem; // element vertex ids
448448
mjFloatVec* texcoord; // vertex texture coordinates
449+
mjIntVec* facetexcoord; // face texture coordinates
449450

450451
// other
451452
mjString* info; // message appended to compiler errors

include/mujoco/mjvisualize.h

+1
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ struct mjvSceneState_ {
523523
int* flex_vertadr;
524524
int* flex_vertnum;
525525
int* flex_elem;
526+
int* flex_elemtexcoord;
526527
int* flex_elemlayer;
527528
int* flex_elemadr;
528529
int* flex_elemnum;

include/mujoco/mjxmacro.h

+1
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@
350350
X ( int, flex_vertbodyid, nflexvert, 1 ) \
351351
X ( int, flex_edge, nflexedge, 2 ) \
352352
XMJV( int, flex_elem, nflexelemdata, 1 ) \
353+
XMJV( int, flex_elemtexcoord, nflexelemdata, 1 ) \
353354
X ( int, flex_elemedge, nflexelemedge, 1 ) \
354355
XMJV( int, flex_elemlayer, nflexelem, 1 ) \
355356
XMJV( int, flex_shell, nflexshelldata,1 ) \

python/mujoco/introspect/structs.py

+22
Original file line numberDiff line numberDiff line change
@@ -2620,6 +2620,14 @@
26202620
doc='element vertex ids (dim+1 per elem)',
26212621
array_extent=('nflexelemdata',),
26222622
),
2623+
StructFieldDecl(
2624+
name='flex_elemtexcoord',
2625+
type=PointerType(
2626+
inner_type=ValueType(name='int'),
2627+
),
2628+
doc='element texture coordinates (dim+1)',
2629+
array_extent=('nflexelemdata',),
2630+
),
26232631
StructFieldDecl(
26242632
name='flex_elemedge',
26252633
type=PointerType(
@@ -7636,6 +7644,13 @@
76367644
),
76377645
doc='',
76387646
),
7647+
StructFieldDecl(
7648+
name='flex_elemtexcoord',
7649+
type=PointerType(
7650+
inner_type=ValueType(name='int'),
7651+
),
7652+
doc='',
7653+
),
76397654
StructFieldDecl(
76407655
name='flex_elemlayer',
76417656
type=PointerType(
@@ -10440,6 +10455,13 @@
1044010455
),
1044110456
doc='vertex texture coordinates',
1044210457
),
10458+
StructFieldDecl(
10459+
name='facetexcoord',
10460+
type=PointerType(
10461+
inner_type=ValueType(name='mjIntVec'),
10462+
),
10463+
doc='face texture coordinates',
10464+
),
1044310465
StructFieldDecl(
1044410466
name='info',
1044510467
type=PointerType(

src/engine/engine_vis_visualize.c

+10-8
Original file line numberDiff line numberDiff line change
@@ -2527,38 +2527,39 @@ void mjv_updateActiveFlex(const mjModel* m, mjData* d, mjvScene* scn, const mjvO
25272527
if (dim == 2 || m->flex_elemlayer[m->flex_elemadr[f]+e] == opt->flex_layer) {
25282528
// get element data
25292529
const int* edata = m->flex_elem + m->flex_elemdataadr[f] + e*(dim+1);
2530+
const int* tdata = m->flex_elemtexcoord + m->flex_elemdataadr[f] + e*(dim+1);
25302531

25312532
// triangles: two faces per element
25322533
if (dim == 2) {
25332534
makeFace(face, normal, radius, vertxpos, nface, edata[0], edata[1], edata[2]);
2534-
copyTex(texdst, texsrc, nface, edata[0], edata[1], edata[2]);
2535+
copyTex(texdst, texsrc, nface, tdata[0], tdata[1], tdata[2]);
25352536
nface++;
25362537

25372538
makeFace(face, normal, radius, vertxpos, nface, edata[0], edata[2], edata[1]);
2538-
copyTex(texdst, texsrc, nface, edata[0], edata[2], edata[1]);
2539+
copyTex(texdst, texsrc, nface, tdata[0], tdata[2], tdata[1]);
25392540
nface++;
25402541
}
25412542

25422543
// tetrahedra: four faces per element
25432544
else {
25442545
makeFace(face, normal, radius, vertxpos,
25452546
nface, edata[0], edata[1], edata[2]);
2546-
copyTex(texdst, texsrc, nface, edata[0], edata[1], edata[2]);
2547+
copyTex(texdst, texsrc, nface, tdata[0], tdata[1], tdata[2]);
25472548
nface++;
25482549

25492550
makeFace(face, normal, radius, vertxpos,
25502551
nface, edata[0], edata[2], edata[3]);
2551-
copyTex(texdst, texsrc, nface, edata[0], edata[2], edata[3]);
2552+
copyTex(texdst, texsrc, nface, tdata[0], tdata[2], tdata[3]);
25522553
nface++;
25532554

25542555
makeFace(face, normal, radius, vertxpos,
25552556
nface, edata[0], edata[3], edata[1]);
2556-
copyTex(texdst, texsrc, nface, edata[0], edata[3], edata[1]);
2557+
copyTex(texdst, texsrc, nface, tdata[0], tdata[3], tdata[1]);
25572558
nface++;
25582559

25592560
makeFace(face, normal, radius, vertxpos,
25602561
nface, edata[1], edata[3], edata[2]);
2561-
copyTex(texdst, texsrc, nface, edata[1], edata[3], edata[2]);
2562+
copyTex(texdst, texsrc, nface, tdata[1], tdata[3], tdata[2]);
25622563
nface++;
25632564
}
25642565
}
@@ -2598,13 +2599,14 @@ void mjv_updateActiveFlex(const mjModel* m, mjData* d, mjvScene* scn, const mjvO
25982599
if (dim == 2) {
25992600
for (int e=0; e < m->flex_elemnum[f]; e++) {
26002601
const int* edata = m->flex_elem + m->flex_elemdataadr[f] + e*(dim+1);
2602+
const int* tdata = m->flex_elemtexcoord + m->flex_elemdataadr[f] + e*(dim+1);
26012603
makeSmooth(face, normal, radius, flg_flat, vertnorm, vertxpos,
26022604
nface, edata[0], edata[1], edata[2]);
2603-
copyTex(texdst, texsrc, nface, edata[0], edata[1], edata[2]);
2605+
copyTex(texdst, texsrc, nface, tdata[0], tdata[1], tdata[2]);
26042606
nface++;
26052607
makeSmooth(face, normal, -radius, flg_flat, vertnorm, vertxpos,
26062608
nface, edata[0], edata[2], edata[1]);
2607-
copyTex(texdst, texsrc, nface, edata[0], edata[2], edata[1]);
2609+
copyTex(texdst, texsrc, nface, tdata[0], tdata[2], tdata[1]);
26082610
nface++;
26092611
}
26102612
} else {

src/user/user_flexcomp.cc

+6
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ bool mjCFlexcomp::Make(mjsBody* body, char* error, int error_sz) {
413413
mjs_setString(pf->name, name.c_str());
414414
mjs_setInt(pf->elem, element.data(), element.size());
415415
mjs_setFloat(pf->texcoord, texcoord.data(), texcoord.size());
416+
mjs_setInt(pf->facetexcoord, facetexcoord.data(), facetexcoord.size());
416417
if (!centered) {
417418
mjs_setDouble(pf->vert, point.data(), point.size());
418419
}
@@ -1055,6 +1056,11 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
10551056
point[i] = (double) mesh.Vert(i);
10561057
}
10571058

1059+
if (mesh.HasTexcoord()) {
1060+
texcoord = mesh.Texcoord();
1061+
facetexcoord = mesh.FaceTexcoord();
1062+
}
1063+
10581064
// copy faces or create 3D mesh
10591065
if (def.spec.flex->dim == 2) {
10601066
element = mesh.Face();

src/user/user_flexcomp.h

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class mjCFlexcomp {
106106
std::vector<bool> used; // is point used by any element (false: skip)
107107
std::vector<int> element; // flex elements
108108
std::vector<float> texcoord; // vertex texture coordinates
109+
std::vector<int> facetexcoord; // face texture coordinates (OBJ only)
109110

110111
// plugin support
111112
std::string plugin_name;

src/user/user_mesh.cc

+10-1
Original file line numberDiff line numberDiff line change
@@ -3184,6 +3184,7 @@ void mjCFlex::PointToLocal() {
31843184
spec.vert = &spec_vert_;
31853185
spec.node = &spec_node_;
31863186
spec.texcoord = &spec_texcoord_;
3187+
spec.facetexcoord = &spec_facetexcoord_;
31873188
spec.elem = &spec_elem_;
31883189
spec.info = &info;
31893190
material = nullptr;
@@ -3192,6 +3193,7 @@ void mjCFlex::PointToLocal() {
31923193
vert = nullptr;
31933194
node = nullptr;
31943195
texcoord = nullptr;
3196+
facetexcoord = nullptr;
31953197
elem = nullptr;
31963198
}
31973199

@@ -3217,6 +3219,7 @@ void mjCFlex::CopyFromSpec() {
32173219
vert_ = spec_vert_;
32183220
node_ = spec_node_;
32193221
texcoord_ = spec_texcoord_;
3222+
facetexcoord_ = spec_facetexcoord_;
32203223
elem_ = spec_elem_;
32213224

32223225
// clear precompiled asset. TODO: use asset cache
@@ -3320,10 +3323,16 @@ void mjCFlex::Compile(const mjVFS* vfs) {
33203323
}
33213324

33223325
// check texcoord
3323-
if (!texcoord_.empty() && texcoord_.size()!=2*nvert) {
3326+
if (!texcoord_.empty() && texcoord_.size()!=2*nvert && facetexcoord_.empty()) {
33243327
throw mjCError(this, "two texture coordinates per vertex expected");
33253328
}
33263329

3330+
// no facetexcoord: copy from faces
3331+
if (facetexcoord_.empty() && !texcoord_.empty()) {
3332+
facetexcoord_.assign(3*nelem, 0);
3333+
memcpy(facetexcoord_.data(), elem_.data(), 3*nelem*sizeof(int));
3334+
}
3335+
33273336
// resolve material name
33283337
mjCBase* pmat = model->FindObject(mjOBJ_MATERIAL, material_);
33293338
if (pmat) {

src/user/user_model.cc

+3
Original file line numberDiff line numberDiff line change
@@ -2911,10 +2911,13 @@ void mjCModel::CopyObjects(mjModel* m) {
29112911
}
29122912
if (pfl->texcoord_.empty()) {
29132913
m->flex_texcoordadr[i] = -1;
2914+
memcpy(m->flex_elemtexcoord + elemdata_adr, pfl->elem_.data(), pfl->elem_.size()*sizeof(int));
29142915
} else {
29152916
m->flex_texcoordadr[i] = texcoord_adr;
29162917
memcpy(m->flex_texcoord + 2*texcoord_adr,
29172918
pfl->texcoord_.data(), pfl->texcoord_.size()*sizeof(float));
2919+
memcpy(m->flex_elemtexcoord + elemdata_adr, pfl->facetexcoord_.data(),
2920+
pfl->facetexcoord_.size()*sizeof(int));
29182921
}
29192922
m->flex_elemnum[i] = pfl->nelem;
29202923
memcpy(m->flex_elem + elemdata_adr, pfl->elem_.data(), pfl->elem_.size()*sizeof(int));

src/user/user_objects.h

+5
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ class mjCFlex_ : public mjCBase {
776776
std::vector<double> node_; // node positions
777777
std::vector<int> elem_; // element vertex ids
778778
std::vector<float> texcoord_; // vertex texture coordinates
779+
std::vector<int> facetexcoord_; // face texture coordinates (OBJ only)
779780
std::string material_; // name of material used for rendering
780781

781782
std::string spec_material_;
@@ -785,6 +786,7 @@ class mjCFlex_ : public mjCBase {
785786
std::vector<double> spec_node_;
786787
std::vector<int> spec_elem_;
787788
std::vector<float> spec_texcoord_;
789+
std::vector<int> spec_facetexcoord_;
788790
};
789791

790792
class mjCFlex: public mjCFlex_, private mjsFlex {
@@ -815,6 +817,7 @@ class mjCFlex: public mjCFlex_, private mjsFlex {
815817
const std::vector<double>& get_elemaabb() const { return elemaabb_; }
816818
const std::vector<int>& get_elem() const { return elem_; }
817819
const std::vector<float>& get_texcoord() const { return texcoord_; }
820+
const std::vector<int>& get_facetexcoord() const { return facetexcoord_; }
818821
const std::vector<std::string>& get_nodebody() const { return nodebody_; }
819822

820823
bool HasTexcoord() const; // texcoord not null
@@ -927,6 +930,8 @@ class mjCMesh: public mjCMesh_, private mjsMesh {
927930
float Vert(int i) const { return vert_[i]; }
928931
const std::vector<float>& UserVert() const { return spec_vert_; }
929932
const std::vector<float>& UserNormal() const { return spec_normal_; }
933+
const std::vector<float>& Texcoord() const { return texcoord_; }
934+
const std::vector<int>& FaceTexcoord() const { return facetexcoord_; }
930935
const std::vector<float>& UserTexcoord() const { return spec_texcoord_; }
931936
const std::vector<int>& Face() const { return face_; }
932937
const std::vector<int>& UserFace() const { return spec_face_; }

src/xml/xml_native_reader.cc

+6-2
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
324324

325325
{"deformable", "*", "0"},
326326
{"<"},
327-
{"flex", "*", "12", "name", "group", "dim", "radius", "material",
328-
"rgba", "flatskin", "body", "vertex", "element", "texcoord", "node"},
327+
{"flex", "*", "13", "name", "group", "dim", "radius", "material",
328+
"rgba", "flatskin", "body", "vertex", "element", "texcoord", "facetexcoord", "node"},
329329
{"<"},
330330
{"contact", "?", "13", "contype", "conaffinity", "condim", "priority",
331331
"friction", "solmix", "solref", "solimp", "margin", "gap",
@@ -1354,6 +1354,10 @@ void mjXReader::OneFlex(XMLElement* elem, mjsFlex* flex) {
13541354
if (texcoord.has_value()) {
13551355
mjs_setFloat(flex->texcoord, texcoord->data(), texcoord->size());
13561356
}
1357+
auto facetexcoord = ReadAttrVec<int>(elem, "facetexcoord");
1358+
if (facetexcoord.has_value()) {
1359+
mjs_setInt(flex->facetexcoord, facetexcoord->data(), facetexcoord->size());
1360+
}
13571361

13581362
// contact subelement
13591363
XMLElement* cont = FirstChildElement(elem, "contact");

src/xml/xml_native_writer.cc

+4
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ void mjXWriter::OneFlex(XMLElement* elem, const mjCFlex* flex) {
158158
text = VectorToString(flex->get_texcoord());
159159
WriteAttrTxt(elem, "texcoord", text);
160160
}
161+
if (!flex->get_facetexcoord().empty()) {
162+
text = VectorToString(flex->get_facetexcoord());
163+
WriteAttrTxt(elem, "facetexcoord", text);
164+
}
161165
if (!flex->get_nodebody().empty()) {
162166
text = VectorToString(flex->get_nodebody());
163167
WriteAttrTxt(elem, "node", text);
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<mujoco>
2+
<compiler assetdir="textured_torus"/>
3+
<asset>
4+
<texture file="carpet.png" type="2d"/>
5+
<material name="carpet" texture="carpet"/>
6+
</asset>
7+
<worldbody>
8+
<flexcomp name="torus" type="mesh" file="textured_torus.obj"
9+
radius="0.01" dim="2" material="carpet">
10+
<contact internal="false" selfcollide="none"/>
11+
<edge equality="true" />
12+
</flexcomp>
13+
</worldbody>
14+
</mujoco>

test/user/user_flex_test.cc

+16
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,22 @@ TEST_F(UserFlexTest, StiffnessMatrix) {
435435
mj_deleteModel(m);
436436
}
437437

438+
TEST_F(UserFlexTest, LoadTexture) {
439+
const std::string xml_path =
440+
GetTestDataFilePath("user/testdata/textured_torus_flex.xml");
441+
std::array<char, 1024> error;
442+
mjModel* m = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size());
443+
ASSERT_THAT(m, NotNull()) << error.data();
444+
EXPECT_THAT(m->nflextexcoord, 637);
445+
EXPECT_THAT(m->flex_elemtexcoord[0], 0);
446+
EXPECT_THAT(m->flex_elemtexcoord[1], 1);
447+
EXPECT_THAT(m->flex_elemtexcoord[2], 2);
448+
EXPECT_THAT(m->flex_elemtexcoord[3], 0);
449+
EXPECT_THAT(m->flex_elemtexcoord[4], 2);
450+
EXPECT_THAT(m->flex_elemtexcoord[5], 3);
451+
mj_deleteModel(m);
452+
}
453+
438454
TEST_F(UserFlexTest, LoadMSHBinary_41_Success) {
439455
const std::string xml_path =
440456
GetTestDataFilePath("user/testdata/cube_41_binary_vol_gmshApp.xml");

unity/Runtime/Bindings/MjBindings.cs

+2
Original file line numberDiff line numberDiff line change
@@ -5437,6 +5437,7 @@ public unsafe struct mjModel_ {
54375437
public int* flex_vertbodyid;
54385438
public int* flex_edge;
54395439
public int* flex_elem;
5440+
public int* flex_elemtexcoord;
54405441
public int* flex_elemedge;
54415442
public int* flex_elemlayer;
54425443
public int* flex_shell;
@@ -6324,6 +6325,7 @@ public unsafe struct model {
63246325
public int* flex_vertadr;
63256326
public int* flex_vertnum;
63266327
public int* flex_elem;
6328+
public int* flex_elemtexcoord;
63276329
public int* flex_elemlayer;
63286330
public int* flex_elemadr;
63296331
public int* flex_elemnum;

0 commit comments

Comments
 (0)