Merge pull request #3387 from bd-pmorais:pmorais/renderer-live-mat-texid
PiperOrigin-RevId: 949427127 Change-Id: I607af41aefdefd6d22602889e6982d64df8b380b
This commit is contained in:
@@ -86,6 +86,11 @@ Bug fixes
|
|||||||
in-gap contacts on multi-geom bodies.
|
in-gap contacts on multi-geom bodies.
|
||||||
- Fixed a bug in the mesh compiler where normals were scaled as vectors rather than covectors.
|
- Fixed a bug in the mesh compiler where normals were scaled as vectors rather than covectors.
|
||||||
|
|
||||||
|
.. admonition:: Breaking ABI changes
|
||||||
|
:class: attention
|
||||||
|
|
||||||
|
- Added ``texid``, ``texuniform`` and ``texrepeat`` fields to ``mjvGeom``.
|
||||||
|
|
||||||
Version 3.10.0 (June 22, 2026)
|
Version 3.10.0 (June 22, 2026)
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -3219,6 +3219,8 @@ typedef struct mjvGeom_ { // abstract geom
|
|||||||
int objid; // mujoco object id; -1 for decor
|
int objid; // mujoco object id; -1 for decor
|
||||||
int category; // visual category
|
int category; // visual category
|
||||||
int matid; // material id; -1: no textured material
|
int matid; // material id; -1: no textured material
|
||||||
|
int texid; // texture id; -1: none
|
||||||
|
int texuniform; // uniform cube mapping
|
||||||
int texcoord; // mesh or flex geom has texture coordinates
|
int texcoord; // mesh or flex geom has texture coordinates
|
||||||
int segid; // segmentation id; -1: not shown
|
int segid; // segmentation id; -1: not shown
|
||||||
|
|
||||||
@@ -3233,6 +3235,7 @@ typedef struct mjvGeom_ { // abstract geom
|
|||||||
float specular; // specular coef
|
float specular; // specular coef
|
||||||
float shininess; // shininess coef
|
float shininess; // shininess coef
|
||||||
float reflectance; // reflectance coef
|
float reflectance; // reflectance coef
|
||||||
|
float texrepeat[2]; // texture repetition for 2d mapping
|
||||||
|
|
||||||
char label[100]; // text label
|
char label[100]; // text label
|
||||||
|
|
||||||
|
|||||||
@@ -231,6 +231,8 @@ typedef struct mjvGeom_ { // abstract geom
|
|||||||
int objid; // mujoco object id; -1 for decor
|
int objid; // mujoco object id; -1 for decor
|
||||||
int category; // visual category
|
int category; // visual category
|
||||||
int matid; // material id; -1: no textured material
|
int matid; // material id; -1: no textured material
|
||||||
|
int texid; // texture id; -1: none
|
||||||
|
int texuniform; // uniform cube mapping
|
||||||
int texcoord; // mesh or flex geom has texture coordinates
|
int texcoord; // mesh or flex geom has texture coordinates
|
||||||
int segid; // segmentation id; -1: not shown
|
int segid; // segmentation id; -1: not shown
|
||||||
|
|
||||||
@@ -245,6 +247,7 @@ typedef struct mjvGeom_ { // abstract geom
|
|||||||
float specular; // specular coef
|
float specular; // specular coef
|
||||||
float shininess; // shininess coef
|
float shininess; // shininess coef
|
||||||
float reflectance; // reflectance coef
|
float reflectance; // reflectance coef
|
||||||
|
float texrepeat[2]; // texture repetition for 2d mapping
|
||||||
|
|
||||||
char label[100]; // text label
|
char label[100]; // text label
|
||||||
|
|
||||||
|
|||||||
@@ -10371,6 +10371,16 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
type=ValueType(name='int'),
|
type=ValueType(name='int'),
|
||||||
doc='material id; -1: no textured material',
|
doc='material id; -1: no textured material',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='texid',
|
||||||
|
type=ValueType(name='int'),
|
||||||
|
doc='texture id; -1: none',
|
||||||
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='texuniform',
|
||||||
|
type=ValueType(name='int'),
|
||||||
|
doc='uniform cube mapping',
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='texcoord',
|
name='texcoord',
|
||||||
type=ValueType(name='int'),
|
type=ValueType(name='int'),
|
||||||
@@ -10433,6 +10443,14 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
type=ValueType(name='float'),
|
type=ValueType(name='float'),
|
||||||
doc='reflectance coef',
|
doc='reflectance coef',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='texrepeat',
|
||||||
|
type=ArrayType(
|
||||||
|
inner_type=ValueType(name='float'),
|
||||||
|
extents=(2,),
|
||||||
|
),
|
||||||
|
doc='texture repetition for 2d mapping',
|
||||||
|
),
|
||||||
StructFieldDecl(
|
StructFieldDecl(
|
||||||
name='label',
|
name='label',
|
||||||
type=ArrayType(
|
type=ArrayType(
|
||||||
|
|||||||
@@ -1186,6 +1186,8 @@ This is useful for example when the MJB is not available as a file on disk.)"));
|
|||||||
X(objid);
|
X(objid);
|
||||||
X(category);
|
X(category);
|
||||||
X(matid);
|
X(matid);
|
||||||
|
X(texid);
|
||||||
|
X(texuniform);
|
||||||
X(texcoord);
|
X(texcoord);
|
||||||
X(segid);
|
X(segid);
|
||||||
X(emission);
|
X(emission);
|
||||||
@@ -1202,6 +1204,7 @@ This is useful for example when the MJB is not available as a file on disk.)"));
|
|||||||
X(pos);
|
X(pos);
|
||||||
X(mat);
|
X(mat);
|
||||||
X(rgba);
|
X(rgba);
|
||||||
|
X(texrepeat);
|
||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
DefinePyStr(mjvGeom, "label", &raw::MjvGeom::label);
|
DefinePyStr(mjvGeom, "label", &raw::MjvGeom::label);
|
||||||
|
|||||||
@@ -832,6 +832,7 @@ class MjWrapper<raw::MjvGeom> : public WrapperBase<raw::MjvGeom> {
|
|||||||
X(pos);
|
X(pos);
|
||||||
X(mat);
|
X(mat);
|
||||||
X(rgba);
|
X(rgba);
|
||||||
|
X(texrepeat);
|
||||||
#undef X
|
#undef X
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1193,7 +1193,8 @@ MjvGeomWrapper::MjWrapper()
|
|||||||
static_assert(sizeof(ptr_->mat) == sizeof(ptr_->mat[0]) * 9);
|
static_assert(sizeof(ptr_->mat) == sizeof(ptr_->mat[0]) * 9);
|
||||||
return InitPyArray(std::array{3, 3}, ptr_->mat, owner_);
|
return InitPyArray(std::array{3, 3}, ptr_->mat, owner_);
|
||||||
}()),
|
}()),
|
||||||
X(rgba) {
|
X(rgba),
|
||||||
|
X(texrepeat) {
|
||||||
mjv_initGeom(ptr_, mjGEOM_NONE, nullptr, nullptr, nullptr, nullptr);
|
mjv_initGeom(ptr_, mjGEOM_NONE, nullptr, nullptr, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1205,7 +1206,8 @@ MjvGeomWrapper::MjWrapper(raw::MjvGeom* ptr, py::handle owner)
|
|||||||
static_assert(sizeof(ptr_->mat) == sizeof(ptr_->mat[0]) * 9);
|
static_assert(sizeof(ptr_->mat) == sizeof(ptr_->mat[0]) * 9);
|
||||||
return InitPyArray(std::array{3, 3}, ptr_->mat, owner_);
|
return InitPyArray(std::array{3, 3}, ptr_->mat, owner_);
|
||||||
}()),
|
}()),
|
||||||
X(rgba) {}
|
X(rgba),
|
||||||
|
X(texrepeat) {}
|
||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
MjvGeomWrapper::MjWrapper(const MjvGeomWrapper& other) : MjvGeomWrapper() {
|
MjvGeomWrapper::MjWrapper(const MjvGeomWrapper& other) : MjvGeomWrapper() {
|
||||||
|
|||||||
@@ -241,6 +241,10 @@ static void setMaterial(const mjModel* m, mjvGeom* geom, int matid, const float*
|
|||||||
// set texture
|
// set texture
|
||||||
if (flags[mjVIS_TEXTURE] && matid >= 0) {
|
if (flags[mjVIS_TEXTURE] && matid >= 0) {
|
||||||
geom->matid = matid;
|
geom->matid = matid;
|
||||||
|
geom->texid = m->mat_texid[matid*mjNTEXROLE + mjTEXROLE_RGB];
|
||||||
|
geom->texuniform = m->mat_texuniform[matid];
|
||||||
|
geom->texrepeat[0] = m->mat_texrepeat[2*matid];
|
||||||
|
geom->texrepeat[1] = m->mat_texrepeat[2*matid+1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale alpha for dynamic geoms only
|
// scale alpha for dynamic geoms only
|
||||||
@@ -379,6 +383,10 @@ void mjv_initGeom(mjvGeom* geom, int type, const mjtNum* size,
|
|||||||
// set defaults that cannot be assigned via this function
|
// set defaults that cannot be assigned via this function
|
||||||
geom->dataid = -1;
|
geom->dataid = -1;
|
||||||
geom->matid = -1;
|
geom->matid = -1;
|
||||||
|
geom->texid = -1;
|
||||||
|
geom->texuniform = 0;
|
||||||
|
geom->texrepeat[0] = 0;
|
||||||
|
geom->texrepeat[1] = 0;
|
||||||
geom->texcoord = 0;
|
geom->texcoord = 0;
|
||||||
geom->emission = 0;
|
geom->emission = 0;
|
||||||
geom->specular = 0.5;
|
geom->specular = 0.5;
|
||||||
|
|||||||
@@ -174,6 +174,9 @@ static void UpdateGeomMaterial(mjrfRenderable* renderable, const mjvGeom& geom,
|
|||||||
material.roughness_texture = get_texture(mjTEXROLE_ROUGHNESS);
|
material.roughness_texture = get_texture(mjTEXROLE_ROUGHNESS);
|
||||||
material.occlusion_texture = get_texture(mjTEXROLE_OCCLUSION);
|
material.occlusion_texture = get_texture(mjTEXROLE_OCCLUSION);
|
||||||
}
|
}
|
||||||
|
if (geom.texid >= 0) {
|
||||||
|
material.color_texture = model_objs->GetTexture(geom.texid);
|
||||||
|
}
|
||||||
|
|
||||||
material.reflectance = geom.reflectance;
|
material.reflectance = geom.reflectance;
|
||||||
material.emissive = geom.emission;
|
material.emissive = geom.emission;
|
||||||
@@ -200,14 +203,21 @@ static void UpdateGeomMaterial(mjrfRenderable* renderable, const mjvGeom& geom,
|
|||||||
// the programmatic UVs.
|
// the programmatic UVs.
|
||||||
|
|
||||||
if (material.color_texture) {
|
if (material.color_texture) {
|
||||||
const bool tex_uniform = model->mat_texuniform[geom.matid];
|
bool tex_uniform;
|
||||||
|
float tex_repeat[2];
|
||||||
|
if (geom.texid >= 0) {
|
||||||
|
tex_uniform = geom.texuniform;
|
||||||
|
tex_repeat[0] = geom.texrepeat[0];
|
||||||
|
tex_repeat[1] = geom.texrepeat[1];
|
||||||
|
} else {
|
||||||
|
tex_uniform = model->mat_texuniform[geom.matid];
|
||||||
|
tex_repeat[0] = model->mat_texrepeat[(geom.matid * 2) + 0];
|
||||||
|
tex_repeat[1] = model->mat_texrepeat[(geom.matid * 2) + 1];
|
||||||
|
}
|
||||||
if (mjrf_getTextureSamplerType(material.color_texture) == mjTEXTURE_2D) {
|
if (mjrf_getTextureSamplerType(material.color_texture) == mjTEXTURE_2D) {
|
||||||
// For 2D textures, `tex_repeat` specifies how many times the texture
|
// For 2D textures, `tex_repeat` specifies how many times the texture
|
||||||
// image is repeated. The `tex_uniform` flag determines if the repetition
|
// image is repeated. The `tex_uniform` flag determines if the repetition
|
||||||
// is applied at in object space (false) or in world space (true).
|
// is applied at in object space (false) or in world space (true).
|
||||||
float tex_repeat[2];
|
|
||||||
tex_repeat[0] = model->mat_texrepeat[(geom.matid * 2) + 0];
|
|
||||||
tex_repeat[1] = model->mat_texrepeat[(geom.matid * 2) + 1];
|
|
||||||
material.uv_scale[0] = tex_repeat[0];
|
material.uv_scale[0] = tex_repeat[0];
|
||||||
material.uv_scale[1] = tex_repeat[1];
|
material.uv_scale[1] = tex_repeat[1];
|
||||||
|
|
||||||
|
|||||||
@@ -61,10 +61,19 @@ enum {
|
|||||||
// enable/disable texture mapping
|
// enable/disable texture mapping
|
||||||
static void settexture(int type, int state, const mjrContext* con, const mjvGeom* geom) {
|
static void settexture(int type, int state, const mjrContext* con, const mjvGeom* geom) {
|
||||||
float plane[4], scl[2];
|
float plane[4], scl[2];
|
||||||
int texid = -1;
|
int texid = -1, texuniform = 0;
|
||||||
|
float texrepeat[2] = {0, 0};
|
||||||
if (geom) {
|
if (geom) {
|
||||||
if (geom->matid >= 0) {
|
if (geom->texid >= 0) {
|
||||||
|
texid = geom->texid;
|
||||||
|
texuniform = geom->texuniform;
|
||||||
|
texrepeat[0] = geom->texrepeat[0];
|
||||||
|
texrepeat[1] = geom->texrepeat[1];
|
||||||
|
} else if (geom->matid >= 0) {
|
||||||
texid = con->mat_texid[mjNTEXROLE * geom->matid + mjTEXROLE_RGB];
|
texid = con->mat_texid[mjNTEXROLE * geom->matid + mjTEXROLE_RGB];
|
||||||
|
texuniform = con->mat_texuniform[geom->matid];
|
||||||
|
texrepeat[0] = con->mat_texrepeat[geom->matid*2];
|
||||||
|
texrepeat[1] = con->mat_texrepeat[geom->matid*2+1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,8 +128,8 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom
|
|||||||
glBindTexture(GL_TEXTURE_2D, con->texture[texid]);
|
glBindTexture(GL_TEXTURE_2D, con->texture[texid]);
|
||||||
|
|
||||||
// determine scaling, adjust for pre-scaled geoms
|
// determine scaling, adjust for pre-scaled geoms
|
||||||
scl[0] = con->mat_texrepeat[geom->matid*2];
|
scl[0] = texrepeat[0];
|
||||||
scl[1] = con->mat_texrepeat[geom->matid*2+1];
|
scl[1] = texrepeat[1];
|
||||||
if (geom->dataid >= 0) {
|
if (geom->dataid >= 0) {
|
||||||
if (geom->size[0] > 0) {
|
if (geom->size[0] > 0) {
|
||||||
scl[0] = scl[0] / mju_max(mjMINVAL, geom->size[0]);
|
scl[0] = scl[0] / mju_max(mjMINVAL, geom->size[0]);
|
||||||
@@ -132,7 +141,7 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom
|
|||||||
}
|
}
|
||||||
|
|
||||||
// uniform: repeat relative to spatial units rather than object
|
// uniform: repeat relative to spatial units rather than object
|
||||||
if (con->mat_texuniform[geom->matid]) {
|
if (texuniform) {
|
||||||
if (geom->size[0] > 0) {
|
if (geom->size[0] > 0) {
|
||||||
scl[0] = scl[0] * geom->size[0];
|
scl[0] = scl[0] * geom->size[0];
|
||||||
}
|
}
|
||||||
@@ -171,11 +180,11 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom
|
|||||||
|
|
||||||
// set mapping : cube
|
// set mapping : cube
|
||||||
if (type == mjtexREGULAR) {
|
if (type == mjtexREGULAR) {
|
||||||
mjr_setf4(plane, con->mat_texuniform[geom->matid] ? geom->size[0] : 1, 0, 0, 0);
|
mjr_setf4(plane, texuniform ? geom->size[0] : 1, 0, 0, 0);
|
||||||
glTexGenfv(GL_S, GL_OBJECT_PLANE, plane);
|
glTexGenfv(GL_S, GL_OBJECT_PLANE, plane);
|
||||||
mjr_setf4(plane, 0, con->mat_texuniform[geom->matid] ? geom->size[1] : 1, 0, 0);
|
mjr_setf4(plane, 0, texuniform ? geom->size[1] : 1, 0, 0);
|
||||||
glTexGenfv(GL_T, GL_OBJECT_PLANE, plane);
|
glTexGenfv(GL_T, GL_OBJECT_PLANE, plane);
|
||||||
mjr_setf4(plane, 0, 0, con->mat_texuniform[geom->matid] ? geom->size[2] : 1, 0);
|
mjr_setf4(plane, 0, 0, texuniform ? geom->size[2] : 1, 0);
|
||||||
glTexGenfv(GL_R, GL_OBJECT_PLANE, plane);
|
glTexGenfv(GL_R, GL_OBJECT_PLANE, plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1317,7 +1326,7 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) {
|
|||||||
if (con->textureType[i] == mjTEXTURE_SKYBOX) {
|
if (con->textureType[i] == mjTEXTURE_SKYBOX) {
|
||||||
// save first skybox texture id in tempgeom
|
// save first skybox texture id in tempgeom
|
||||||
memset(&tempgeom, 0, sizeof(mjvGeom));
|
memset(&tempgeom, 0, sizeof(mjvGeom));
|
||||||
tempgeom.matid = mjMAXMATERIAL - 1;
|
tempgeom.texid = i;
|
||||||
|
|
||||||
// modify settings
|
// modify settings
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
|
|||||||
@@ -5974,6 +5974,8 @@ public unsafe struct mjvGeom_ {
|
|||||||
public int objid;
|
public int objid;
|
||||||
public int category;
|
public int category;
|
||||||
public int matid;
|
public int matid;
|
||||||
|
public int texid;
|
||||||
|
public int texuniform;
|
||||||
public int texcoord;
|
public int texcoord;
|
||||||
public int segid;
|
public int segid;
|
||||||
public fixed float size[3];
|
public fixed float size[3];
|
||||||
@@ -5984,6 +5986,7 @@ public unsafe struct mjvGeom_ {
|
|||||||
public float specular;
|
public float specular;
|
||||||
public float shininess;
|
public float shininess;
|
||||||
public float reflectance;
|
public float reflectance;
|
||||||
|
public fixed float texrepeat[2];
|
||||||
public fixed char label[100];
|
public fixed char label[100];
|
||||||
public float camdist;
|
public float camdist;
|
||||||
public float modelrbound;
|
public float modelrbound;
|
||||||
|
|||||||
@@ -6099,6 +6099,9 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
|||||||
.property("size", &MjvGeom::size)
|
.property("size", &MjvGeom::size)
|
||||||
.property("specular", &MjvGeom::specular, &MjvGeom::set_specular, reference())
|
.property("specular", &MjvGeom::specular, &MjvGeom::set_specular, reference())
|
||||||
.property("texcoord", &MjvGeom::texcoord, &MjvGeom::set_texcoord, reference())
|
.property("texcoord", &MjvGeom::texcoord, &MjvGeom::set_texcoord, reference())
|
||||||
|
.property("texid", &MjvGeom::texid, &MjvGeom::set_texid, reference())
|
||||||
|
.property("texrepeat", &MjvGeom::texrepeat)
|
||||||
|
.property("texuniform", &MjvGeom::texuniform, &MjvGeom::set_texuniform, reference())
|
||||||
.property("transparent", &MjvGeom::transparent, &MjvGeom::set_transparent, reference())
|
.property("transparent", &MjvGeom::transparent, &MjvGeom::set_transparent, reference())
|
||||||
.property("type", &MjvGeom::type, &MjvGeom::set_type, reference());
|
.property("type", &MjvGeom::type, &MjvGeom::set_type, reference());
|
||||||
emscripten::class_<MjvLight>("MjvLight")
|
emscripten::class_<MjvLight>("MjvLight")
|
||||||
|
|||||||
@@ -1850,6 +1850,18 @@ struct MjvGeom {
|
|||||||
void set_matid(int value) {
|
void set_matid(int value) {
|
||||||
ptr_->matid = value;
|
ptr_->matid = value;
|
||||||
}
|
}
|
||||||
|
int texid() const {
|
||||||
|
return ptr_->texid;
|
||||||
|
}
|
||||||
|
void set_texid(int value) {
|
||||||
|
ptr_->texid = value;
|
||||||
|
}
|
||||||
|
int texuniform() const {
|
||||||
|
return ptr_->texuniform;
|
||||||
|
}
|
||||||
|
void set_texuniform(int value) {
|
||||||
|
ptr_->texuniform = value;
|
||||||
|
}
|
||||||
int texcoord() const {
|
int texcoord() const {
|
||||||
return ptr_->texcoord;
|
return ptr_->texcoord;
|
||||||
}
|
}
|
||||||
@@ -1898,6 +1910,9 @@ struct MjvGeom {
|
|||||||
void set_reflectance(float value) {
|
void set_reflectance(float value) {
|
||||||
ptr_->reflectance = value;
|
ptr_->reflectance = value;
|
||||||
}
|
}
|
||||||
|
emscripten::val texrepeat() const {
|
||||||
|
return emscripten::val(emscripten::typed_memory_view(2, ptr_->texrepeat));
|
||||||
|
}
|
||||||
emscripten::val label() const {
|
emscripten::val label() const {
|
||||||
return emscripten::val(emscripten::typed_memory_view(100, ptr_->label));
|
return emscripten::val(emscripten::typed_memory_view(100, ptr_->label));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user