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** (*)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| This element creates a texture asset, which is then referenced from a :ref:`material <asset-material>` asset, which is
finally referenced from a model element that needs to be textured. MuJoCo provides access to the texture mapping
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
color in GL_MODULATE mode. The texture data can be loaded from PNG files, with provisions for loading cube and skybox
textures. Alternatively the data can be generated by the compiler as a procedural texture. Because different texture
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
different from .png or .PNG, or if the ``content_type`` attribute is set to ``image/vnd.mujoco.texture``, then MuJoCo
assumes that the texture is in this format. This is a custom binary file format, containing the following data:
This element creates a texture asset, which is then referenced from a :ref:`material <asset-material>` asset, which
is finally referenced from a model element that needs to be textured.
The texture data can be loaded from files or can be generated by the compiler as a procedural texture. Because
different texture types require different parameters, only a subset of the attributes below are used for any given
texture. Provisions are provided for loading cube and skybox textures from individual image files.
Currently, three file formats are supported for loading textures: PNG, KTX, and a custom MuJoCo texture format. The
loader will use the extension of the file name to determine which format to use, defaulting to the custom format if
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
@@ -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`
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
file to be loaded. Any filename extensions will be ignored. Currently ``image/png`` and ``image/vnd.mujoco.texture``
are supported.
file to be loaded. Any filename extensions will be ignored. Currently ``image/png``, ``image/ktx``, and
``image/vnd.mujoco.texture`` are supported.
.. _asset-texture-file:
@@ -1786,11 +1789,11 @@ properties are grouped together.
.. _asset-material-rgba:
: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
in GL_MODULATE mode, meaning that the texture color and the color specified here are multiplied component-wise. Thus
the default value of "1 1 1 1" has the effect of leaving the texture unchanged. When the material is applied to a
model element which defines its own local rgba attribute, the local definition has precedence. Note that this "local"
definition could in fact come from a defaults class. The remaining material properties always apply.
Color and transparency of the material. All components should be in the range [0 1]. Note that the texture color (if
assigned) and the color specified here are multiplied component-wise. Thus the default value of "1 1 1 1" has the
effect of leaving the texture unchanged. When the material is applied to a model element which defines its own local
rgba attribute, the local definition has precedence. Note that this "local" definition could in fact come from a
defaults class. The remaining material properties always apply.
.. _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++) {
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) {
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();
}
// 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
void mjCTexture::LoadCustom(mjResource* resource,
std::vector<unsigned char>& image,
@@ -4336,7 +4358,7 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
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());
}
@@ -4345,6 +4367,11 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
try {
if (asset_type == "image/png") {
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 {
LoadCustom(resource, image, w, h, is_srgb);
}
+3
View File
@@ -1333,6 +1333,9 @@ class mjCTexture : public mjCTexture_, private mjsTexture {
void LoadPNG(mjResource* resource,
std::vector<unsigned char>& image,
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,
std::vector<unsigned char>& image,
unsigned int& w, unsigned int& h, bool& is_srgb);