From d43c3ed42682c3332259c0b4c2904d24d5610dc4 Mon Sep 17 00:00:00 2001 From: Pedro Morais Date: Thu, 9 Jul 2026 11:08:43 -0400 Subject: [PATCH] Move texture block copy out of render context so it can be modified online via mjmodel --- doc/APIreference/APIglobals.rst | 3 --- doc/changelog.rst | 9 +++++++ include/mujoco/mjrender.h | 6 ----- include/mujoco/mjvisualize.h | 3 +++ python/mujoco/introspect/structs.py | 42 +++++++++++++---------------- python/mujoco/render.cc | 12 --------- python/mujoco/structs.cc | 3 +++ python/mujoco/structs.h | 1 + python/mujoco/structs_wrappers.cc | 6 +++-- src/engine/engine_vis_visualize.c | 8 ++++++ src/render/classic/render_context.c | 40 --------------------------- src/render/classic/render_gl3.c | 16 +++++------ 12 files changed, 54 insertions(+), 95 deletions(-) diff --git a/doc/APIreference/APIglobals.rst b/doc/APIreference/APIglobals.rst index b25cb5fd..fec3dc6b 100644 --- a/doc/APIreference/APIglobals.rst +++ b/doc/APIreference/APIglobals.rst @@ -583,9 +583,6 @@ Defined in `mjrender.h : public WrapperBase { X(auxFBO_r); X(auxColor); X(auxColor_r); - X(mat_texid); - X(mat_texuniform); - X(mat_texrepeat); X(textureType); X(texture); X(skinvertVBO); @@ -98,9 +95,6 @@ MjrContextWrapper::MjWrapper() X(auxFBO_r), X(auxColor), X(auxColor_r), - X(mat_texid), - X(mat_texuniform), - X(mat_texrepeat), X(textureType), X(texture), X_SKIN(skinvertVBO), @@ -125,9 +119,6 @@ MjrContextWrapper::MjWrapper(const MjModelWrapper& model, int fontscale) X(auxFBO_r), X(auxColor), X(auxColor_r), - X(mat_texid), - X(mat_texuniform), - X(mat_texrepeat), X(textureType), X(texture), X_SKIN(skinvertVBO), @@ -228,9 +219,6 @@ PYBIND11_MODULE(_render, pymodule, pybind11::mod_gil_not_used()) { X(auxFBO_r); X(auxColor); X(auxColor_r); - X(mat_texid); - X(mat_texuniform); - X(mat_texrepeat); X(textureType); X(texture); X(skinvertVBO); diff --git a/python/mujoco/structs.cc b/python/mujoco/structs.cc index 359b14eb..5971ab77 100644 --- a/python/mujoco/structs.cc +++ b/python/mujoco/structs.cc @@ -1185,6 +1185,8 @@ This is useful for example when the MJB is not available as a file on disk.)")); X(objid); X(category); X(matid); + X(texid); + X(texuniform); X(texcoord); X(segid); X(emission); @@ -1201,6 +1203,7 @@ This is useful for example when the MJB is not available as a file on disk.)")); X(pos); X(mat); X(rgba); + X(texrepeat); #undef X DefinePyStr(mjvGeom, "label", &raw::MjvGeom::label); diff --git a/python/mujoco/structs.h b/python/mujoco/structs.h index f8b72049..450c7dbf 100644 --- a/python/mujoco/structs.h +++ b/python/mujoco/structs.h @@ -832,6 +832,7 @@ class MjWrapper : public WrapperBase { X(pos); X(mat); X(rgba); + X(texrepeat); #undef X }; diff --git a/python/mujoco/structs_wrappers.cc b/python/mujoco/structs_wrappers.cc index 60bd3bff..4e47446b 100644 --- a/python/mujoco/structs_wrappers.cc +++ b/python/mujoco/structs_wrappers.cc @@ -1193,7 +1193,8 @@ MjvGeomWrapper::MjWrapper() static_assert(sizeof(ptr_->mat) == sizeof(ptr_->mat[0]) * 9); return InitPyArray(std::array{3, 3}, ptr_->mat, owner_); }()), - X(rgba) { + X(rgba), + X(texrepeat) { 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); return InitPyArray(std::array{3, 3}, ptr_->mat, owner_); }()), - X(rgba) {} + X(rgba), + X(texrepeat) {} #undef X MjvGeomWrapper::MjWrapper(const MjvGeomWrapper& other) : MjvGeomWrapper() { diff --git a/src/engine/engine_vis_visualize.c b/src/engine/engine_vis_visualize.c index 6350da14..1eda8563 100644 --- a/src/engine/engine_vis_visualize.c +++ b/src/engine/engine_vis_visualize.c @@ -241,6 +241,10 @@ static void setMaterial(const mjModel* m, mjvGeom* geom, int matid, const float* // set texture if (flags[mjVIS_TEXTURE] && matid >= 0) { 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 @@ -379,6 +383,10 @@ void mjv_initGeom(mjvGeom* geom, int type, const mjtNum* size, // set defaults that cannot be assigned via this function geom->dataid = -1; geom->matid = -1; + geom->texid = -1; + geom->texuniform = 0; + geom->texrepeat[0] = 0; + geom->texrepeat[1] = 0; geom->texcoord = 0; geom->emission = 0; geom->specular = 0.5; diff --git a/src/render/classic/render_context.c b/src/render/classic/render_context.c index c7a5dd0b..52402c7f 100644 --- a/src/render/classic/render_context.c +++ b/src/render/classic/render_context.c @@ -14,7 +14,6 @@ #include "render/classic/render_context.h" -#include // IWYU pragma: keep #include #include #include @@ -1299,44 +1298,6 @@ static void makeFont(mjrContext* con, int fontscale) { } } -// make materials, just for those that have textures -static void makeMaterial(const mjModel* m, mjrContext* con) { - memset(con->mat_texid, -1, sizeof(con->mat_texid)); - memset(con->mat_texuniform, 0, sizeof(con->mat_texuniform)); - memset(con->mat_texrepeat, 0, sizeof(con->mat_texrepeat)); - - // find skybox texture - for (int i=0; i < m->ntex; i++) { - if (m->tex_type[i] == mjTEXTURE_SKYBOX) { - if (m->nmat >= mjMAXMATERIAL-2) { - mju_error("With skybox, maximum number of materials is %d, got %" PRId64, - mjMAXMATERIAL-1, m->nmat); - } - for (int j=0; j < mjNTEXROLE; j++) { - con->mat_texid[mjNTEXROLE * (mjMAXMATERIAL-1) + j] = -1; - } - con->mat_texid[mjNTEXROLE * (mjMAXMATERIAL-1) + mjTEXROLE_RGB] = i; - - break; - } - } - - if (m->nmat >= mjMAXMATERIAL-1) { - mju_error("Maximum number of materials is %d, got %" PRId64, mjMAXMATERIAL, m->nmat); - } - for (int i=0; i < m->nmat; i++) { - if (m->mat_texid[i*mjNTEXROLE + mjTEXROLE_RGB] >= 0) { - for (int j=0; j < mjNTEXROLE; j++) { - con->mat_texid[i*mjNTEXROLE + j] = m->mat_texid[i*mjNTEXROLE + j]; - } - con->mat_texuniform[i] = m->mat_texuniform[i]; - con->mat_texrepeat[2*i] = m->mat_texrepeat[2*i]; - con->mat_texrepeat[2*i+1] = m->mat_texrepeat[2*i+1]; - } - } -} - - // make textures static void makeTexture(const mjModel* m, mjrContext* con) { // checks size @@ -1639,7 +1600,6 @@ void mjr_makeContext_offSize(const mjModel* m, mjrContext* con, int fontscale, // make everything makeOff(con); makeShadow(m, con); - makeMaterial(m, con); makeTexture(m, con); makePlane(m, con); makeMesh(m, con); diff --git a/src/render/classic/render_gl3.c b/src/render/classic/render_gl3.c index 30d246ff..402fcc6a 100644 --- a/src/render/classic/render_gl3.c +++ b/src/render/classic/render_gl3.c @@ -64,7 +64,7 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom int texid = -1; if (geom) { if (geom->matid >= 0) { - texid = con->mat_texid[mjNTEXROLE * geom->matid + mjTEXROLE_RGB]; + texid = geom->texid; } } @@ -119,8 +119,8 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom glBindTexture(GL_TEXTURE_2D, con->texture[texid]); // determine scaling, adjust for pre-scaled geoms - scl[0] = con->mat_texrepeat[geom->matid*2]; - scl[1] = con->mat_texrepeat[geom->matid*2+1]; + scl[0] = geom->texrepeat[0]; + scl[1] = geom->texrepeat[1]; if (geom->dataid >= 0) { if (geom->size[0] > 0) { scl[0] = scl[0] / mju_max(mjMINVAL, geom->size[0]); @@ -132,7 +132,7 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom } // uniform: repeat relative to spatial units rather than object - if (con->mat_texuniform[geom->matid]) { + if (geom->texuniform) { if (geom->size[0] > 0) { scl[0] = scl[0] * geom->size[0]; } @@ -171,11 +171,11 @@ static void settexture(int type, int state, const mjrContext* con, const mjvGeom // set mapping : cube if (type == mjtexREGULAR) { - mjr_setf4(plane, con->mat_texuniform[geom->matid] ? geom->size[0] : 1, 0, 0, 0); + mjr_setf4(plane, geom->texuniform ? geom->size[0] : 1, 0, 0, 0); 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, geom->texuniform ? geom->size[1] : 1, 0, 0); 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, geom->texuniform ? geom->size[2] : 1, 0); glTexGenfv(GL_R, GL_OBJECT_PLANE, plane); } @@ -1317,7 +1317,7 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { if (con->textureType[i] == mjTEXTURE_SKYBOX) { // save first skybox texture id in tempgeom memset(&tempgeom, 0, sizeof(mjvGeom)); - tempgeom.matid = mjMAXMATERIAL - 1; + tempgeom.texid = i; // modify settings glDisable(GL_LIGHTING);