Support image/ktx format for textures.

PiperOrigin-RevId: 761926074
Change-Id: I6a312634b5bdc706ea5166bc3b2be273e14c1c8a
This commit is contained in:
Google DeepMind
2025-05-22 05:46:49 -07:00
committed by Copybara-Service
parent 3e9bc79b54
commit 373b4c0437
4 changed files with 52 additions and 19 deletions
+20 -17
View File
@@ -1464,16 +1464,19 @@ still be specified here but this functionality is now deprecated and will be rem
:el-prefix:`asset/` |-| **texture** (*) :el-prefix:`asset/` |-| **texture** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| This element creates a texture asset, which is then referenced from a :ref:`material <asset-material>` asset, which is This element creates a texture asset, which is then referenced from a :ref:`material <asset-material>` asset, which
finally referenced from a model element that needs to be textured. MuJoCo provides access to the texture mapping is finally referenced from a model element that needs to be textured.
mechanism in OpenGL. Texture coordinates are generated automatically in GL_OBJECT_PLANE mode, using either 2D or cube
mapping. MIP maps are always enabled in GL_LINEAR_MIPMAP_LINEAR mode. The texture color is combined with the object The texture data can be loaded from files or can be generated by the compiler as a procedural texture. Because
color in GL_MODULATE mode. The texture data can be loaded from PNG files, with provisions for loading cube and skybox different texture types require different parameters, only a subset of the attributes below are used for any given
textures. Alternatively the data can be generated by the compiler as a procedural texture. Because different texture texture. Provisions are provided for loading cube and skybox textures from individual image files.
types require different parameters, only a subset of the attributes below are used for any given texture.
| A second file format is supported for loading textures, in addition to PNG. If the file name extension is Currently, three file formats are supported for loading textures: PNG, KTX, and a custom MuJoCo texture format. The
different from .png or .PNG, or if the ``content_type`` attribute is set to ``image/vnd.mujoco.texture``, then MuJoCo loader will use the extension of the file name to determine which format to use, defaulting to the custom format if
assumes that the texture is in this format. This is a custom binary file format, containing the following data: the extension is not recognized. Alternatively, the content_type attribute can be used to specify the format
explicitly. Only ``image/png``, ``image/ktx``, or ``image/vnd.mujoco.texture`` are supported.
The custom MuJoCo format is assumed to be a binary file containing the following data:
.. code:: Text .. code:: Text
@@ -1537,8 +1540,8 @@ still be specified here but this functionality is now deprecated and will be rem
:at:`content_type`: :at-val:`string, optional` :at:`content_type`: :at-val:`string, optional`
If the file attribute is specified, then this sets the If the file attribute is specified, then this sets the
`Media Type <https://www.iana.org/assignments/media-types/media-types.xhtml>`_ (formerly known as MIME types) of the `Media Type <https://www.iana.org/assignments/media-types/media-types.xhtml>`_ (formerly known as MIME types) of the
file to be loaded. Any filename extensions will be ignored. Currently ``image/png`` and ``image/vnd.mujoco.texture`` file to be loaded. Any filename extensions will be ignored. Currently ``image/png``, ``image/ktx``, and
are supported. ``image/vnd.mujoco.texture`` are supported.
.. _asset-texture-file: .. _asset-texture-file:
@@ -1786,11 +1789,11 @@ properties are grouped together.
.. _asset-material-rgba: .. _asset-material-rgba:
:at:`rgba`: :at-val:`real(4), "1 1 1 1"` :at:`rgba`: :at-val:`real(4), "1 1 1 1"`
Color and transparency of the material. All components should be in the range [0 1]. Note that textures are applied Color and transparency of the material. All components should be in the range [0 1]. Note that the texture color (if
in GL_MODULATE mode, meaning that the texture color and the color specified here are multiplied component-wise. Thus assigned) and the color specified here are multiplied component-wise. Thus the default value of "1 1 1 1" has the
the default value of "1 1 1 1" has the effect of leaving the texture unchanged. When the material is applied to a effect of leaving the texture unchanged. When the material is applied to a model element which defines its own local
model element which defines its own local rgba attribute, the local definition has precedence. Note that this "local" rgba attribute, the local definition has precedence. Note that this "local" definition could in fact come from a
definition could in fact come from a defaults class. The remaining material properties always apply. defaults class. The remaining material properties always apply.
.. _material-layer: .. _material-layer:
+1 -1
View File
@@ -2406,7 +2406,7 @@ const char* mj_validateReferences(const mjModel* m) {
} }
} }
for (int i=0; i < m->ntex; i++) { for (int i=0; i < m->ntex; i++) {
int tex_adr = m->tex_adr[i] + 3*m->tex_height[i]*m->tex_width[i]; int tex_adr = m->tex_adr[i] + m->tex_nchannel[i]*m->tex_height[i]*m->tex_width[i];
if (tex_adr > m->ntexdata || m->tex_adr[i] < 0) { if (tex_adr > m->ntexdata || m->tex_adr[i] < 0) {
return "Invalid model: tex_adr out of bounds."; return "Invalid model: tex_adr out of bounds.";
} }
+28 -1
View File
@@ -4283,6 +4283,28 @@ void mjCTexture::LoadPNG(mjResource* resource,
image = png_image.MoveData(); image = png_image.MoveData();
} }
// load KTX file
void mjCTexture::LoadKTX(mjResource* resource,
std::vector<unsigned char>& image, unsigned int& w,
unsigned int& h, bool& is_srgb) {
const void* buffer = 0;
int buffer_sz = mju_readResource(resource, &buffer);
// still not found
if (buffer_sz < 0) {
throw mjCError(this, "could not read texture file '%s'", resource->name);
} else if (!buffer_sz) {
throw mjCError(this, "texture file is empty: '%s'", resource->name);
}
w = buffer_sz;
h = 1;
is_srgb = false;
image.resize(buffer_sz);
memcpy(image.data(), buffer, buffer_sz);
}
// load custom file // load custom file
void mjCTexture::LoadCustom(mjResource* resource, void mjCTexture::LoadCustom(mjResource* resource,
std::vector<unsigned char>& image, std::vector<unsigned char>& image,
@@ -4336,7 +4358,7 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
asset_type = "image/vnd.mujoco.texture"; asset_type = "image/vnd.mujoco.texture";
} }
if (asset_type != "image/png" && asset_type != "image/vnd.mujoco.texture") { if (asset_type != "image/png" && asset_type != "image/ktx" && asset_type != "image/vnd.mujoco.texture") {
throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str()); throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str());
} }
@@ -4345,6 +4367,11 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
try { try {
if (asset_type == "image/png") { if (asset_type == "image/png") {
LoadPNG(resource, image, w, h, is_srgb); LoadPNG(resource, image, w, h, is_srgb);
} else if (asset_type == "image/ktx") {
if (hflip || vflip) {
throw mjCError(this, "cannot flip KTX textures");
}
LoadKTX(resource, image, w, h, is_srgb);
} else { } else {
LoadCustom(resource, image, w, h, is_srgb); LoadCustom(resource, image, w, h, is_srgb);
} }
+3
View File
@@ -1333,6 +1333,9 @@ class mjCTexture : public mjCTexture_, private mjsTexture {
void LoadPNG(mjResource* resource, void LoadPNG(mjResource* resource,
std::vector<unsigned char>& image, std::vector<unsigned char>& image,
unsigned int& w, unsigned int& h, bool& is_srgb); unsigned int& w, unsigned int& h, bool& is_srgb);
void LoadKTX(mjResource* resource,
std::vector<unsigned char>& image,
unsigned int& w, unsigned int& h, bool& is_srgb);
void LoadCustom(mjResource* resource, void LoadCustom(mjResource* resource,
std::vector<unsigned char>& image, std::vector<unsigned char>& image,
unsigned int& w, unsigned int& h, bool& is_srgb); unsigned int& w, unsigned int& h, bool& is_srgb);