Allow multiple textures per material in MJCF.
PiperOrigin-RevId: 654795013 Change-Id: I418b72533484d00accaf801a342aa183e602a2d0
This commit is contained in:
committed by
Copybara-Service
parent
e79efa60d6
commit
33e5960653
+121
-1
@@ -1636,6 +1636,11 @@ still be specified here but this functionality is now deprecated and will be rem
|
||||
:at:`vflip`: :at-val:`[false, true], "false"`
|
||||
If true, images loaded from file are flipped in the vertical direction. Does not affect procedural textures.
|
||||
|
||||
.. _asset-texture-nchannel:
|
||||
|
||||
:at:`nchannel`: :at-val:`int, "3"`
|
||||
The number of channels in the texture image file. This allows loading 4-channel textures (RGBA) or single-channel
|
||||
textures (e.g., for Physics-Based Rendering properties such as roughness or metallic).
|
||||
|
||||
|
||||
.. _asset-material:
|
||||
@@ -1666,7 +1671,12 @@ properties are grouped together.
|
||||
If this attribute is specified, the material has a texture associated with it. Referencing the material from a model
|
||||
element will cause the texture to be applied to that element. Note that the value of this attribute is the name of a
|
||||
texture asset, not a texture file name. Textures cannot be loaded in the material definition; instead they must be
|
||||
loaded explicitly via the :ref:`texture <asset-texture>` element and then referenced here.
|
||||
loaded explicitly via the :ref:`texture <asset-texture>` element and then referenced here. The texture referenced
|
||||
here is used for specifying the RGB values. For advanced rendering (e.g., Physics-Based Rendering), more texture
|
||||
types need to be specified (e.g., roughness, metallic). In this case, this texture attribute should be omitted, and
|
||||
the texture types should be specified explicitly via the specific role child elements, e.g.,
|
||||
:ref:`texture <material-orm>`. Note however that the built-in renderer does not support PBR properties, so these
|
||||
advanced rendering features are only available when using an external renderer.
|
||||
|
||||
.. _asset-material-texrepeat:
|
||||
|
||||
@@ -1738,6 +1748,116 @@ properties are grouped together.
|
||||
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-rgb:
|
||||
|
||||
:el-prefix:`material/` |-| **rgb** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This element references a texture asset used to specify base color / albedo values.
|
||||
|
||||
.. _material-rgb-texture:
|
||||
|
||||
:at:`texture`: :at-val:`string, required`
|
||||
Name of the texture, expected to have exactly 3 channels.
|
||||
|
||||
.. _material-normal:
|
||||
|
||||
:el-prefix:`material/` |-| **normal** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This element references a texture asset used to specify the bump map (surface normals).
|
||||
|
||||
.. _material-normal-texture:
|
||||
|
||||
:at:`texture`: :at-val:`string, required`
|
||||
Name of the texture, expected to have exactly 3 channels.
|
||||
|
||||
.. _material-occlusion:
|
||||
|
||||
:el-prefix:`material/` |-| **occlusion** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This element references a texture asset used to specify ambient occlusion.
|
||||
|
||||
.. _material-occlusion-texture:
|
||||
|
||||
:at:`texture`: :at-val:`string, required`
|
||||
Name of the texture, expected to have exactly one channel.
|
||||
|
||||
.. _material-roughness:
|
||||
|
||||
:el-prefix:`material/` |-| **roughness** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This element references a texture asset used to specify the roughness map.
|
||||
|
||||
.. _material-roughness-texture:
|
||||
|
||||
:at:`texture`: :at-val:`string, required`
|
||||
Name of the texture, expected to have exactly one channel.
|
||||
|
||||
.. _material-metallic:
|
||||
|
||||
:el-prefix:`material/` |-| **metallic** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This element references a texture asset used to specify the metallic map.
|
||||
|
||||
.. _material-metallic-texture:
|
||||
|
||||
:at:`texture`: :at-val:`string, required`
|
||||
Name of the texture, expected to have exactly one channel.
|
||||
|
||||
.. _material-opacity:
|
||||
|
||||
:el-prefix:`material/` |-| **opacity** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This element references a texture asset used to specify the opacity map (alpha channel, transparency).
|
||||
|
||||
.. _material-opacity-texture:
|
||||
|
||||
:at:`texture`: :at-val:`string, required`
|
||||
Name of the texture, expected to have exactly one channel.
|
||||
|
||||
.. _material-emissive:
|
||||
|
||||
:el-prefix:`material/` |-| **emissive** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This element references a texture asset used to specify light emission.
|
||||
|
||||
.. _material-emissive-texture:
|
||||
|
||||
:at:`texture`: :at-val:`string, required`
|
||||
Name of the texture, expected to have exactly 4 channels.
|
||||
|
||||
.. _material-orm:
|
||||
|
||||
:el-prefix:`material/` |-| **orm** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This element references a texture asset used to specify a packed ORM map, where occlusion, roughness, and metallic
|
||||
are joined into the corresponding RGB values of a single texture.
|
||||
|
||||
.. _material-orm-texture:
|
||||
|
||||
:at:`texture`: :at-val:`string, required`
|
||||
Name of the texture, expected to have exactly 3 channels.
|
||||
|
||||
.. _material-rgba:
|
||||
|
||||
:el-prefix:`material/` |-| **rgba** (?)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This element references a texture asset used to specify a packed map where albedo and opacity are joined into the same
|
||||
4-channel texture.
|
||||
|
||||
.. _material-rgba-texture:
|
||||
|
||||
:at:`texture`: :at-val:`string, required`
|
||||
Name of the texture, expected to have exactly 4 channels.
|
||||
|
||||
|
||||
.. _asset-model:
|
||||
|
||||
|
||||
+64
-1
@@ -163,7 +163,7 @@
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`markrgb<asset-texture-markrgb>` | :ref:`random<asset-texture-random>` | :ref:`width<asset-texture-width>` | :ref:`height<asset-texture-height>` | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`hflip<asset-texture-hflip>` | :ref:`vflip<asset-texture-vflip>` | | | |
|
||||
| | | | :ref:`hflip<asset-texture-hflip>` | :ref:`vflip<asset-texture-vflip>` | :ref:`nchannel<asset-texture-nchannel>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_| asset |br| |_| |L| | | .. table:: |
|
||||
@@ -177,6 +177,69 @@
|
||||
| | | | :ref:`reflectance<asset-material-reflectance>` | :ref:`metallic<asset-material-metallic>` | :ref:`roughness<asset-material-roughness>` | :ref:`rgba<asset-material-rgba>` | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||
| :ref:`rgb | ? | :class: mjcf-attributes |
|
||||
| <material-rgb>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`texture<material-rgb-texture>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||
| :ref:`occlusion | ? | :class: mjcf-attributes |
|
||||
| <material-occlusion>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`texture<material-occlusion-texture>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||
| :ref:`roughness | ? | :class: mjcf-attributes |
|
||||
| <material-roughness>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`texture<material-roughness-texture>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||
| :ref:`metallic | ? | :class: mjcf-attributes |
|
||||
| <material-metallic>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`texture<material-metallic-texture>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||
| :ref:`normal | ? | :class: mjcf-attributes |
|
||||
| <material-normal>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`texture<material-normal-texture>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||
| :ref:`opacity | ? | :class: mjcf-attributes |
|
||||
| <material-opacity>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`texture<material-opacity-texture>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||
| :ref:`emissive | ? | :class: mjcf-attributes |
|
||||
| <material-emissive>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`texture<material-emissive-texture>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||
| :ref:`rgba | ? | :class: mjcf-attributes |
|
||||
| <material-rgba>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`texture<material-rgba-texture>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_2| material |br| |_2| |L| | | .. table:: |
|
||||
| :ref:`orm | ? | :class: mjcf-attributes |
|
||||
| <material-orm>` | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
| | | | :ref:`texture<material-orm-texture>` | | | | |
|
||||
| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ |
|
||||
+------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |_| asset |br| |_| |L| | | .. table:: |
|
||||
| :ref:`model | \* | :class: mjcf-attributes |
|
||||
| <asset-model>` | | |
|
||||
|
||||
+5
-2
@@ -10,15 +10,18 @@ General
|
||||
|
||||
1. Renamed ``mjModel.tex_rbg`` to ``mjModel.tex_data``.
|
||||
2. Added a new disable flag ``mjDSBL_AUTORESETNAN`` to disable automatic reset when NaNs or infinities are produced.
|
||||
3. Added sub-elements to the MJCF :ref:`material<asset-material>` element, to allow specification of multiple textures
|
||||
for rendering (e.g., :ref:`occlusion-roughness-metallic<material-orm>`). Note that the MuJoCo renderer doesn't support
|
||||
these new features, and they are made available for use with external renderers.
|
||||
|
||||
MJX
|
||||
^^^
|
||||
|
||||
3. Added more fields to ``mjx.Model`` and ``mjx.Data`` for further compatibility with the corresponding MuJoCo structs.
|
||||
4. Added more fields to ``mjx.Model`` and ``mjx.Data`` for further compatibility with the corresponding MuJoCo structs.
|
||||
|
||||
Python bindings
|
||||
^^^^^^^^^^^^^^^
|
||||
4. Added support for asset dictionary argument in ``mujoco.spec.from_file``, ``mujoco.spec.from_string`` and
|
||||
5. Added support for asset dictionary argument in ``mujoco.spec.from_file``, ``mujoco.spec.from_string`` and
|
||||
``mujoco.spec.compile``.
|
||||
|
||||
Version 3.2.0 (Jul 15, 2024)
|
||||
|
||||
@@ -2015,6 +2015,7 @@ typedef struct mjsTexture_ { // texture specification
|
||||
double random; // probability of random dots
|
||||
int height; // height in pixels (square for cube and skybox)
|
||||
int width; // width in pixels
|
||||
int nchannel; // number of channels
|
||||
|
||||
// method 2: single file
|
||||
mjString* content_type; // content type of file
|
||||
@@ -2035,7 +2036,7 @@ typedef struct mjsTexture_ { // texture specification
|
||||
typedef struct mjsMaterial_ { // material specification
|
||||
mjsElement* element; // element type
|
||||
mjString* name; // name
|
||||
mjString* texture; // name of texture (empty: none)
|
||||
mjStringVec* textures; // names of textures (empty: none)
|
||||
mjtByte texuniform; // make texture cube uniform
|
||||
float texrepeat[2]; // texture repetition for 2D mapping
|
||||
float emission; // emission
|
||||
|
||||
@@ -500,6 +500,7 @@ typedef struct mjsTexture_ { // texture specification
|
||||
double random; // probability of random dots
|
||||
int height; // height in pixels (square for cube and skybox)
|
||||
int width; // width in pixels
|
||||
int nchannel; // number of channels
|
||||
|
||||
// method 2: single file
|
||||
mjString* content_type; // content type of file
|
||||
@@ -522,7 +523,7 @@ typedef struct mjsTexture_ { // texture specification
|
||||
typedef struct mjsMaterial_ { // material specification
|
||||
mjsElement* element; // element type
|
||||
mjString* name; // name
|
||||
mjString* texture; // name of texture (empty: none)
|
||||
mjStringVec* textures; // names of textures (empty: none)
|
||||
mjtByte texuniform; // make texture cube uniform
|
||||
float texrepeat[2]; // texture repetition for 2D mapping
|
||||
float emission; // emission
|
||||
|
||||
@@ -9969,6 +9969,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
||||
type=ValueType(name='int'),
|
||||
doc='width in pixels',
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='nchannel',
|
||||
type=ValueType(name='int'),
|
||||
doc='number of channels',
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='content_type',
|
||||
type=PointerType(
|
||||
@@ -10045,11 +10050,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
||||
doc='name',
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='texture',
|
||||
name='textures',
|
||||
type=PointerType(
|
||||
inner_type=ValueType(name='mjString'),
|
||||
inner_type=ValueType(name='mjStringVec'),
|
||||
),
|
||||
doc='name of texture (empty: none)',
|
||||
doc='names of textures (empty: none)',
|
||||
),
|
||||
StructFieldDecl(
|
||||
name='texuniform',
|
||||
|
||||
@@ -1304,7 +1304,7 @@ static void makeMaterial(const mjModel* m, mjrContext* con) {
|
||||
}
|
||||
|
||||
if (m->nmat >= mjMAXMATERIAL-1) {
|
||||
mju_error("Maximum number of materials is %d", mjMAXMATERIAL);
|
||||
mju_error("Maximum number of materials is 100, got %d", m->nmat);
|
||||
}
|
||||
for (int i=0; i < m->nmat; i++) {
|
||||
if (m->mat_texid[i*mjNTEXROLE + mjTEXROLE_RGB] >= 0) {
|
||||
@@ -1320,7 +1320,8 @@ static void makeMaterial(const mjModel* m, mjrContext* con) {
|
||||
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", mjMAXMATERIAL);
|
||||
mju_error("With skybox, maximum number of materials is 99, got %d",
|
||||
m->nmat);
|
||||
}
|
||||
for (int j=0; j < mjNTEXROLE; j++) {
|
||||
con->mat_texid[mjNTEXROLE * (mjMAXMATERIAL-1) + j] = -1;
|
||||
|
||||
+18
-18
@@ -947,13 +947,11 @@ void mjCModel::DeleteMaterial(std::vector<T*>& list, std::string_view name) {
|
||||
|
||||
|
||||
|
||||
// delete texture with given name or all textures if the name is omitted
|
||||
// delete all textures
|
||||
template <class T>
|
||||
static void DeleteTexture(std::vector<T*>& list, std::string_view name = "") {
|
||||
static void DeleteAllTextures(std::vector<T*>& list) {
|
||||
for (T* plist : list) {
|
||||
if (name.empty() || plist->get_texture() == name) {
|
||||
plist->del_texture();
|
||||
}
|
||||
plist->del_textures();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1046,7 +1044,7 @@ void mjCModel::DeleteAll<mjCMaterial>(std::vector<mjCMaterial*>& elements) {
|
||||
|
||||
template <>
|
||||
void mjCModel::DeleteAll<mjCTexture>(std::vector<mjCTexture*>& elements) {
|
||||
DeleteTexture(materials_);
|
||||
DeleteAllTextures(materials_);
|
||||
for (mjCTexture* element : elements) {
|
||||
delete element;
|
||||
}
|
||||
@@ -1202,13 +1200,15 @@ void mjCModel::IndexAssets(bool discard) {
|
||||
for (int i=0; i<materials_.size(); i++) {
|
||||
mjCMaterial* material = materials_[i];
|
||||
|
||||
// find texture by name
|
||||
if (!material->texture_.empty()) {
|
||||
mjCBase* texture = FindObject(mjOBJ_TEXTURE, material->texture_);
|
||||
if (texture) {
|
||||
material->texid = texture->id;
|
||||
} else {
|
||||
throw mjCError(material, "texture '%s' not found in material %d", material->texture_.c_str(), i);
|
||||
// find textures by name
|
||||
for (int j=0; j<mjNTEXROLE; j++) {
|
||||
if (!material->textures_[j].empty()) {
|
||||
mjCBase* texture = FindObject(mjOBJ_TEXTURE, material->textures_[j]);
|
||||
if (texture) {
|
||||
material->texid[j] = texture->id;
|
||||
} else {
|
||||
throw mjCError(material, "texture '%s' not found in material %d", material->textures_[j].c_str(), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2504,14 +2504,15 @@ void mjCModel::CopyObjects(mjModel* m) {
|
||||
m->tex_type[i] = ptex->type;
|
||||
m->tex_height[i] = ptex->height;
|
||||
m->tex_width[i] = ptex->width;
|
||||
m->tex_nchannel[i] = ptex->nchannel;
|
||||
m->tex_adr[i] = data_adr;
|
||||
m->tex_nchannel[i] = 3;
|
||||
|
||||
// copy rgb data
|
||||
memcpy(m->tex_data + data_adr, ptex->rgb.data(), 3*ptex->width*ptex->height);
|
||||
memcpy(m->tex_data + data_adr, ptex->data.data(),
|
||||
ptex->nchannel * ptex->width * ptex->height);
|
||||
|
||||
// advance counter
|
||||
data_adr += 3*ptex->width*ptex->height;
|
||||
data_adr += ptex->nchannel * ptex->width * ptex->height;
|
||||
}
|
||||
|
||||
// materials
|
||||
@@ -2521,9 +2522,8 @@ void mjCModel::CopyObjects(mjModel* m) {
|
||||
|
||||
// set fields
|
||||
for (int j=0; j<mjNTEXROLE; j++) {
|
||||
m->mat_texid[mjNTEXROLE*i+j] = -1;
|
||||
m->mat_texid[mjNTEXROLE*i+j] = pmat->texid[j];
|
||||
}
|
||||
m->mat_texid[mjNTEXROLE*i+mjTEXROLE_RGB] = pmat->texid;
|
||||
m->mat_texuniform[i] = pmat->texuniform;
|
||||
mjuu_copyvec(m->mat_texrepeat+2*i, pmat->texrepeat, 2);
|
||||
m->mat_emission[i] = pmat->emission;
|
||||
|
||||
+86
-64
@@ -3217,7 +3217,7 @@ mjCTexture::mjCTexture(mjCModel* _model) {
|
||||
spec_cubefiles_.assign(6, "");
|
||||
|
||||
// clear internal variables
|
||||
rgb.clear();
|
||||
data.clear();
|
||||
|
||||
// point to local
|
||||
PointToLocal();
|
||||
@@ -3266,14 +3266,14 @@ void mjCTexture::CopyFromSpec() {
|
||||
cubefiles_ = spec_cubefiles_;
|
||||
|
||||
// clear precompiled asset. TODO: use asset cache
|
||||
rgb.clear();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// free data storage allocated by lodepng
|
||||
mjCTexture::~mjCTexture() {
|
||||
rgb.clear();
|
||||
data.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -3366,21 +3366,21 @@ void mjCTexture::Builtin2D(void) {
|
||||
double pos = 2*sqrt(x*x+y*y) - 1;
|
||||
|
||||
// interpolate through sigmoid
|
||||
interp(rgb.data() + 3*(r*width+c), rgb2, rgb1, pos);
|
||||
interp(data.data() + 3*(r*width+c), rgb2, rgb1, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checker
|
||||
else if (builtin==mjBUILTIN_CHECKER) {
|
||||
checker(rgb.data(), RGB1, RGB2, width, height);
|
||||
checker(data.data(), RGB1, RGB2, width, height);
|
||||
}
|
||||
|
||||
// flat
|
||||
else if (builtin==mjBUILTIN_FLAT) {
|
||||
for (int r=0; r<height; r++) {
|
||||
for (int c=0; c<width; c++) {
|
||||
memcpy(rgb.data()+3*(r*width+c), RGB1, 3);
|
||||
memcpy(data.data()+3*(r*width+c), RGB1, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3390,28 +3390,28 @@ void mjCTexture::Builtin2D(void) {
|
||||
// edge
|
||||
if (mark==mjMARK_EDGE) {
|
||||
for (int r=0; r<height; r++) {
|
||||
memcpy(rgb.data()+3*(r*width+0), RGBm, 3);
|
||||
memcpy(rgb.data()+3*(r*width+width-1), RGBm, 3);
|
||||
memcpy(data.data()+3*(r*width+0), RGBm, 3);
|
||||
memcpy(data.data()+3*(r*width+width-1), RGBm, 3);
|
||||
}
|
||||
for (int c=0; c<width; c++) {
|
||||
memcpy(rgb.data()+3*(0*width+c), RGBm, 3);
|
||||
memcpy(rgb.data()+3*((height-1)*width+c), RGBm, 3);
|
||||
memcpy(data.data()+3*(0*width+c), RGBm, 3);
|
||||
memcpy(data.data()+3*((height-1)*width+c), RGBm, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// cross
|
||||
else if (mark==mjMARK_CROSS) {
|
||||
for (int r=0; r<height; r++) {
|
||||
memcpy(rgb.data()+3*(r*width+width/2), RGBm, 3);
|
||||
memcpy(data.data()+3*(r*width+width/2), RGBm, 3);
|
||||
}
|
||||
for (int c=0; c<width; c++) {
|
||||
memcpy(rgb.data()+3*(height/2*width+c), RGBm, 3);
|
||||
memcpy(data.data()+3*(height/2*width+c), RGBm, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// random dots
|
||||
else if (mark==mjMARK_RANDOM && random>0) {
|
||||
randomdot(rgb.data(), markrgb, width, height, random);
|
||||
randomdot(data.data(), markrgb, width, height, random);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3446,26 +3446,26 @@ void mjCTexture::BuiltinCube(void) {
|
||||
|
||||
// set sides
|
||||
interp(RGBi, rgb1, rgb2, elside);
|
||||
memcpy(rgb.data() + 0 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 0: right
|
||||
memcpy(rgb.data() + 1 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 1: left
|
||||
memcpy(rgb.data() + 4 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 4: front
|
||||
memcpy(rgb.data() + 5 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 5: back
|
||||
memcpy(data.data() + 0 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 0: right
|
||||
memcpy(data.data() + 1 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 1: left
|
||||
memcpy(data.data() + 4 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 4: front
|
||||
memcpy(data.data() + 5 * 3 * ww + 3 * (r * w + c), RGBi, 3); // 5: back
|
||||
|
||||
// set up and down
|
||||
interp(rgb.data() + 2 * 3 * ww + 3 * (r * w + c), rgb1, rgb2, elup); // 2: up
|
||||
interp(rgb.data() + 3 * 3 * ww + 3 * (r * w + c), rgb1, rgb2, -elup); // 3: down
|
||||
interp(data.data() + 2 * 3 * ww + 3 * (r * w + c), rgb1, rgb2, elup); // 2: up
|
||||
interp(data.data() + 3 * 3 * ww + 3 * (r * w + c), rgb1, rgb2, -elup); // 3: down
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checker
|
||||
else if (builtin == mjBUILTIN_CHECKER) {
|
||||
checker(rgb.data() + 0 * 3 * ww, RGB1, RGB2, w, w);
|
||||
checker(rgb.data() + 1 * 3 * ww, RGB1, RGB2, w, w);
|
||||
checker(rgb.data() + 2 * 3 * ww, RGB1, RGB2, w, w);
|
||||
checker(rgb.data() + 3 * 3 * ww, RGB1, RGB2, w, w);
|
||||
checker(rgb.data() + 4 * 3 * ww, RGB2, RGB1, w, w);
|
||||
checker(rgb.data() + 5 * 3 * ww, RGB2, RGB1, w, w);
|
||||
checker(data.data() + 0 * 3 * ww, RGB1, RGB2, w, w);
|
||||
checker(data.data() + 1 * 3 * ww, RGB1, RGB2, w, w);
|
||||
checker(data.data() + 2 * 3 * ww, RGB1, RGB2, w, w);
|
||||
checker(data.data() + 3 * 3 * ww, RGB1, RGB2, w, w);
|
||||
checker(data.data() + 4 * 3 * ww, RGB2, RGB1, w, w);
|
||||
checker(data.data() + 5 * 3 * ww, RGB2, RGB1, w, w);
|
||||
}
|
||||
|
||||
// flat
|
||||
@@ -3473,14 +3473,14 @@ void mjCTexture::BuiltinCube(void) {
|
||||
for (int r = 0; r < w; r++) {
|
||||
for (int c = 0; c < w; c++) {
|
||||
// set sides and up
|
||||
memcpy(rgb.data() + 0 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
memcpy(rgb.data() + 1 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
memcpy(rgb.data() + 2 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
memcpy(rgb.data() + 4 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
memcpy(rgb.data() + 5 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
memcpy(data.data() + 0 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
memcpy(data.data() + 1 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
memcpy(data.data() + 2 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
memcpy(data.data() + 4 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
memcpy(data.data() + 5 * 3 * ww + 3 * (r * w + c), RGB1, 3);
|
||||
|
||||
// set down
|
||||
memcpy(rgb.data() + 3 * 3 * ww + 3 * (r * w + c), RGB2, 3);
|
||||
memcpy(data.data() + 3 * 3 * ww + 3 * (r * w + c), RGB2, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3491,12 +3491,12 @@ void mjCTexture::BuiltinCube(void) {
|
||||
if (mark == mjMARK_EDGE) {
|
||||
for (int j = 0; j < 6; j++) {
|
||||
for (int r = 0; r < w; r++) {
|
||||
memcpy(rgb.data() + j * 3 * ww + 3 * (r * w + 0), RGBm, 3);
|
||||
memcpy(rgb.data() + j * 3 * ww + 3 * (r * w + w - 1), RGBm, 3);
|
||||
memcpy(data.data() + j * 3 * ww + 3 * (r * w + 0), RGBm, 3);
|
||||
memcpy(data.data() + j * 3 * ww + 3 * (r * w + w - 1), RGBm, 3);
|
||||
}
|
||||
for (int c = 0; c < w; c++) {
|
||||
memcpy(rgb.data() + j * 3 * ww + 3 * (0 * w + c), RGBm, 3);
|
||||
memcpy(rgb.data() + j * 3 * ww + 3 * ((w - 1) * w + c), RGBm, 3);
|
||||
memcpy(data.data() + j * 3 * ww + 3 * (0 * w + c), RGBm, 3);
|
||||
memcpy(data.data() + j * 3 * ww + 3 * ((w - 1) * w + c), RGBm, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3505,17 +3505,17 @@ void mjCTexture::BuiltinCube(void) {
|
||||
else if (mark == mjMARK_CROSS) {
|
||||
for (int j = 0; j < 6; j++) {
|
||||
for (int r = 0; r < w; r++) {
|
||||
memcpy(rgb.data() + j * 3 * ww + 3 * (r * w + w / 2), RGBm, 3);
|
||||
memcpy(data.data() + j * 3 * ww + 3 * (r * w + w / 2), RGBm, 3);
|
||||
}
|
||||
for (int c = 0; c < w; c++) {
|
||||
memcpy(rgb.data() + j * 3 * ww + 3 * (w / 2 * w + c), RGBm, 3);
|
||||
memcpy(data.data() + j * 3 * ww + 3 * (w / 2 * w + c), RGBm, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// random dots
|
||||
else if (mark == mjMARK_RANDOM && random > 0) {
|
||||
randomdot(rgb.data(), markrgb, w, height, random);
|
||||
randomdot(data.data(), markrgb, w, height, random);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3523,14 +3523,23 @@ void mjCTexture::BuiltinCube(void) {
|
||||
void mjCTexture::LoadPNG(mjResource* resource,
|
||||
std::vector<unsigned char>& image,
|
||||
unsigned int& w, unsigned int& h) {
|
||||
PNGImage png_image = PNGImage::Load(this, resource, LCT_RGB);
|
||||
LodePNGColorType color_type;
|
||||
if (nchannel == 4) {
|
||||
color_type = LCT_RGBA;
|
||||
} else if (nchannel == 3) {
|
||||
color_type = LCT_RGB;
|
||||
} else if (nchannel == 1) {
|
||||
color_type = LCT_GREY;
|
||||
} else {
|
||||
throw mjCError(this, "Unsupported number of channels: %s",
|
||||
std::to_string(nchannel).c_str());
|
||||
}
|
||||
PNGImage png_image = PNGImage::Load(this, resource, color_type);
|
||||
w = png_image.Width();
|
||||
h = png_image.Height();
|
||||
image = png_image.MoveData();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// load custom file
|
||||
void mjCTexture::LoadCustom(mjResource* resource,
|
||||
std::vector<unsigned char>& image,
|
||||
@@ -3601,6 +3610,10 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
|
||||
|
||||
// horizontal flip
|
||||
if (hflip) {
|
||||
if (nchannel != 3) {
|
||||
throw mjCError(
|
||||
this, "currently only 3-channel textures support horizontal flip");
|
||||
}
|
||||
for (int r=0; r<h; r++) {
|
||||
for (int c=0; c<w/2; c++) {
|
||||
int c1 = w-1-c;
|
||||
@@ -3623,6 +3636,10 @@ void mjCTexture::LoadFlip(std::string filename, const mjVFS* vfs,
|
||||
|
||||
// vertical flip
|
||||
if (vflip) {
|
||||
if (nchannel != 3) {
|
||||
throw mjCError(
|
||||
this, "currently only 3-channel textures support vertical flip");
|
||||
}
|
||||
for (int r=0; r<h/2; r++) {
|
||||
for (int c=0; c<w; c++) {
|
||||
int r1 = h-1-r;
|
||||
@@ -3658,12 +3675,12 @@ void mjCTexture::Load2D(std::string filename, const mjVFS* vfs) {
|
||||
height = h;
|
||||
|
||||
// allocate and copy data
|
||||
rgb.assign(3*width*height, 0);
|
||||
if (rgb.empty()) {
|
||||
data.assign(nchannel*width*height, 0);
|
||||
if (data.empty()) {
|
||||
throw mjCError(this, "Could not allocate memory for texture '%s' (id %d)",
|
||||
(const char*)file_.c_str(), id);
|
||||
}
|
||||
memcpy(rgb.data(), image.data(), 3*width*height);
|
||||
memcpy(data.data(), image.data(), nchannel*width*height);
|
||||
image.clear();
|
||||
}
|
||||
|
||||
@@ -3697,8 +3714,8 @@ void mjCTexture::LoadCubeSingle(std::string filename, const mjVFS* vfs) {
|
||||
}
|
||||
|
||||
// allocate data
|
||||
rgb.assign(3*width*height, 0);
|
||||
if (rgb.empty()) {
|
||||
data.assign(3*width*height, 0);
|
||||
if (data.empty()) {
|
||||
throw mjCError(this,
|
||||
"Could not allocate memory for texture '%s' (id %d)",
|
||||
(const char*)file_.c_str(), id);
|
||||
@@ -3706,7 +3723,7 @@ void mjCTexture::LoadCubeSingle(std::string filename, const mjVFS* vfs) {
|
||||
|
||||
// copy: repeated
|
||||
if (gridsize[0]==1 && gridsize[1]==1) {
|
||||
memcpy(rgb.data(), image.data(), 3*width*width);
|
||||
memcpy(data.data(), image.data(), 3*width*width);
|
||||
}
|
||||
|
||||
// copy: grid
|
||||
@@ -3739,7 +3756,7 @@ void mjCTexture::LoadCubeSingle(std::string filename, const mjVFS* vfs) {
|
||||
int rstart = width*(k/gridsize[1]);
|
||||
int cstart = width*(k%gridsize[1]);
|
||||
for (int j=0; j<width; j++) {
|
||||
memcpy(rgb.data()+i*3*width*width+j*3*width, image.data()+(j+rstart)*3*w+3*cstart, 3*width);
|
||||
memcpy(data.data()+i*3*width*width+j*3*width, image.data()+(j+rstart)*3*w+3*cstart, 3*width);
|
||||
}
|
||||
|
||||
// mark as defined
|
||||
@@ -3753,7 +3770,7 @@ void mjCTexture::LoadCubeSingle(std::string filename, const mjVFS* vfs) {
|
||||
for (int k=0; k<width; k++) {
|
||||
for (int s=0; s<width; s++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
rgb[i*3*width*width + 3*(k*width+s) + j] = (mjtByte)(255*rgb1[j]);
|
||||
data[i*3*width*width + 3*(k*width+s) + j] = (mjtByte)(255*rgb1[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3795,11 +3812,11 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
|
||||
}
|
||||
|
||||
// first file: set size and allocate data
|
||||
if (rgb.empty()) {
|
||||
if (data.empty()) {
|
||||
width = w;
|
||||
height = 6*width;
|
||||
rgb.assign(3*width*height, 0);
|
||||
if (rgb.empty()) {
|
||||
data.assign(3*width*height, 0);
|
||||
if (data.empty()) {
|
||||
throw mjCError(this, "Could not allocate memory for texture");
|
||||
}
|
||||
}
|
||||
@@ -3812,7 +3829,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
|
||||
}
|
||||
|
||||
// copy data
|
||||
memcpy(rgb.data()+i*3*width*width, image.data(), 3*width*width);
|
||||
memcpy(data.data()+i*3*width*width, image.data(), 3*width*width);
|
||||
image.clear();
|
||||
|
||||
// mark as defined
|
||||
@@ -3826,7 +3843,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
|
||||
for (int k=0; k<width; k++) {
|
||||
for (int s=0; s<width; s++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
rgb[i*3*width*width + 3*(k*width+s) + j] = (mjtByte)(255*rgb1[j]);
|
||||
data[i*3*width*width + 3*(k*width+s) + j] = (mjtByte)(255*rgb1[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3857,8 +3874,8 @@ void mjCTexture::Compile(const mjVFS* vfs) {
|
||||
}
|
||||
|
||||
// allocate data
|
||||
rgb.assign(3*width*height, 0);
|
||||
if (rgb.empty()) {
|
||||
data.assign(nchannel*width*height, 0);
|
||||
if (data.empty()) {
|
||||
throw mjCError(this, "Could not allocate memory for texture");
|
||||
}
|
||||
|
||||
@@ -3914,7 +3931,7 @@ void mjCTexture::Compile(const mjVFS* vfs) {
|
||||
}
|
||||
|
||||
// make sure someone allocated data; SHOULD NOT OCCUR
|
||||
if (rgb.empty()) {
|
||||
if (data.empty()) {
|
||||
throw mjCError(this, "texture '%s' (id %d) was not specified", name.c_str(), id);
|
||||
}
|
||||
}
|
||||
@@ -3927,10 +3944,13 @@ void mjCTexture::Compile(const mjVFS* vfs) {
|
||||
mjCMaterial::mjCMaterial(mjCModel* _model, mjCDef* _def) {
|
||||
mjs_defaultMaterial(&spec);
|
||||
elemtype = mjOBJ_MATERIAL;
|
||||
textures_.assign(mjNTEXROLE, "");
|
||||
spec_textures_.assign(mjNTEXROLE, "");
|
||||
|
||||
// clear internal
|
||||
spec_texture_.clear();
|
||||
texid = -1;
|
||||
for (int i=0; i<mjNTEXROLE; i++) {
|
||||
texid[i] = -1;
|
||||
}
|
||||
|
||||
// reset to default if given
|
||||
if (_def) {
|
||||
@@ -3969,16 +3989,16 @@ mjCMaterial& mjCMaterial::operator=(const mjCMaterial& other) {
|
||||
void mjCMaterial::PointToLocal() {
|
||||
spec.element = static_cast<mjsElement*>(this);
|
||||
spec.name = &name;
|
||||
spec.texture = &spec_texture_;
|
||||
spec.textures = &spec_textures_;
|
||||
spec.info = &info;
|
||||
texture = nullptr;
|
||||
textures = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mjCMaterial::CopyFromSpec() {
|
||||
*static_cast<mjsMaterial*>(this) = spec;
|
||||
texture_ = spec_texture_;
|
||||
textures_ = spec_textures_;
|
||||
}
|
||||
|
||||
|
||||
@@ -3987,8 +4007,10 @@ void mjCMaterial::NameSpace(const mjCModel* m) {
|
||||
if (!name.empty()) {
|
||||
name = m->prefix + name + m->suffix;
|
||||
}
|
||||
if (!spec_texture_.empty() && model != m) {
|
||||
spec_texture_ = m->prefix + spec_texture_ + m->suffix;
|
||||
for (int i=0; i<mjNTEXROLE; i++) {
|
||||
if (!spec_textures_[i].empty() && model != m) {
|
||||
spec_textures_[i] = m->prefix + spec_textures_[i] + m->suffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1003,7 +1003,7 @@ class mjCHField : public mjCHField_, private mjsHField {
|
||||
|
||||
class mjCTexture_ : public mjCBase {
|
||||
protected:
|
||||
std::vector<mjtByte> rgb; // rgb data
|
||||
std::vector<mjtByte> data; // texture data (rgb, roughness, etc.)
|
||||
|
||||
std::string file_;
|
||||
std::string content_type_;
|
||||
@@ -1063,9 +1063,9 @@ class mjCTexture : public mjCTexture_, private mjsTexture {
|
||||
|
||||
class mjCMaterial_ : public mjCBase {
|
||||
protected:
|
||||
int texid; // id of material's texture
|
||||
std::string texture_;
|
||||
std::string spec_texture_;
|
||||
int texid[mjNTEXROLE]; // id of material's textures
|
||||
std::vector<std::string> textures_;
|
||||
std::vector<std::string> spec_textures_;
|
||||
};
|
||||
|
||||
class mjCMaterial : public mjCMaterial_, private mjsMaterial {
|
||||
@@ -1086,8 +1086,8 @@ class mjCMaterial : public mjCMaterial_, private mjsMaterial {
|
||||
void PointToLocal();
|
||||
void NameSpace(const mjCModel* m);
|
||||
|
||||
const std::string& get_texture() const { return texture_; }
|
||||
void del_texture() { texture_.clear(); }
|
||||
const std::string& get_texture(int i) const { return textures_[i]; }
|
||||
void del_textures() { for (auto& t : textures_) t.clear(); }
|
||||
|
||||
private:
|
||||
void Compile(void); // compiler
|
||||
|
||||
@@ -239,12 +239,23 @@ const char* MJCF[nMJCF][mjXATTRNUM] = {
|
||||
{"<"},
|
||||
{"bone", "*", "5", "body", "bindpos", "bindquat", "vertid", "vertweight"},
|
||||
{">"},
|
||||
{"texture", "*", "22", "name", "type", "content_type", "file", "gridsize", "gridlayout",
|
||||
{"texture", "*", "23", "name", "type", "content_type", "file", "gridsize", "gridlayout",
|
||||
"fileright", "fileleft", "fileup", "filedown", "filefront", "fileback",
|
||||
"builtin", "rgb1", "rgb2", "mark", "markrgb", "random", "width", "height",
|
||||
"hflip", "vflip"},
|
||||
"hflip", "vflip", "nchannel"},
|
||||
{"material", "*", "12", "name", "class", "texture", "texrepeat", "texuniform",
|
||||
"emission", "specular", "shininess", "reflectance", "metallic", "roughness", "rgba"},
|
||||
{"<"},
|
||||
{"rgb", "?", "1", "texture"},
|
||||
{"occlusion", "?", "1", "texture"},
|
||||
{"roughness", "?", "1", "texture"},
|
||||
{"metallic", "?", "1", "texture"},
|
||||
{"normal", "?", "1", "texture"},
|
||||
{"opacity", "?", "1", "texture"},
|
||||
{"emissive", "?", "1", "texture"},
|
||||
{"rgba", "?", "1", "texture"},
|
||||
{"orm", "?", "1", "texture"},
|
||||
{">"},
|
||||
{"model", "*", "2", "name", "file"},
|
||||
{">"},
|
||||
|
||||
@@ -577,6 +588,19 @@ const mjMap camlight_map[camlight_sz] = {
|
||||
{"targetbodycom", mjCAMLIGHT_TARGETBODYCOM}
|
||||
};
|
||||
|
||||
// texmat role type
|
||||
const int texrole_sz = mjNTEXROLE - 1;
|
||||
const mjMap texrole_map[texrole_sz] = {
|
||||
{"rgb", mjTEXROLE_RGB},
|
||||
{"occlusion", mjTEXROLE_OCCLUSION},
|
||||
{"roughness", mjTEXROLE_ROUGHNESS},
|
||||
{"metallic", mjTEXROLE_METALLIC},
|
||||
{"normal", mjTEXROLE_NORMAL},
|
||||
{"opacity", mjTEXROLE_OPACITY},
|
||||
{"emissive", mjTEXROLE_EMISSIVE},
|
||||
{"rgba", mjTEXROLE_RGBA},
|
||||
{"orm", mjTEXROLE_ORM},
|
||||
};
|
||||
|
||||
// integrator type
|
||||
const int integrator_sz = 4;
|
||||
@@ -1534,9 +1558,26 @@ void mjXReader::OneMaterial(XMLElement* elem, mjsMaterial* pmat) {
|
||||
if (ReadAttrTxt(elem, "name", name)) {
|
||||
mjs_setString(pmat->name, name.c_str());
|
||||
}
|
||||
|
||||
bool tex_attributes_found = false;
|
||||
if (ReadAttrTxt(elem, "texture", texture)) {
|
||||
mjs_setString(pmat->texture, texture.c_str());
|
||||
mjs_setInStringVec(pmat->textures, mjTEXROLE_RGB, texture.c_str());
|
||||
tex_attributes_found = true;
|
||||
}
|
||||
|
||||
XMLElement* tex_elem = FirstChildElement(elem);
|
||||
while (tex_elem) {
|
||||
if (tex_attributes_found) {
|
||||
throw mjXError(tex_elem, "A material with a texture attribute cannot have texture sub-elements");
|
||||
}
|
||||
// texture sub-element
|
||||
int role = FindKey(texrole_map, texrole_sz, tex_elem->Name());
|
||||
string texmat;
|
||||
ReadAttrTxt(tex_elem, "texture", texmat, true);
|
||||
mjs_setInStringVec(pmat->textures, role, texmat.c_str());
|
||||
tex_elem = NextSiblingElement(tex_elem);
|
||||
}
|
||||
|
||||
if (MapValue(elem, "texuniform", &n, bool_map, 2)) {
|
||||
pmat->texuniform = (n==1);
|
||||
}
|
||||
@@ -3095,6 +3136,9 @@ void mjXReader::Asset(XMLElement* section, const mjVFS* vfs) {
|
||||
}
|
||||
ReadAttrInt(elem, "width", &ptex->width);
|
||||
ReadAttrInt(elem, "height", &ptex->height);
|
||||
if (!ReadAttrInt(elem, "nchannel", &ptex->nchannel)) {
|
||||
ptex->nchannel = 3;
|
||||
}
|
||||
ReadAttr(elem, "rgb1", 3, ptex->rgb1, text);
|
||||
ReadAttr(elem, "rgb2", 3, ptex->rgb2, text);
|
||||
ReadAttr(elem, "markrgb", 3, ptex->markrgb, text);
|
||||
|
||||
@@ -99,7 +99,7 @@ class mjXReader : public mjXBase {
|
||||
};
|
||||
|
||||
// MJCF schema
|
||||
#define nMJCF 232
|
||||
#define nMJCF 243
|
||||
extern const char* MJCF[nMJCF][mjXATTRNUM];
|
||||
|
||||
#endif // MUJOCO_SRC_XML_XML_NATIVE_READER_H_
|
||||
|
||||
@@ -305,8 +305,20 @@ void mjXWriter::OneMaterial(XMLElement* elem, const mjCMaterial* pmat, mjCDef* d
|
||||
}
|
||||
|
||||
// defaults and regular
|
||||
if (pmat->texture != def->Material().texture) {
|
||||
WriteAttrTxt(elem, "texture", pmat->get_texture());
|
||||
bool has_non_rgb = false;
|
||||
for (int i=1; i<mjNTEXROLE; i++) {
|
||||
if (!pmat->textures_[i].empty()) {
|
||||
if (i != mjTEXROLE_RGB) {
|
||||
has_non_rgb = true;
|
||||
}
|
||||
}
|
||||
if (pmat->textures_[i] != def->Material().textures_[i]) {
|
||||
WriteAttrTxt(elem, "texture", pmat->get_texture(i));
|
||||
}
|
||||
}
|
||||
if (has_non_rgb) {
|
||||
// // TODO elem = InsertEnd(section, "role");
|
||||
mju_error("mjXWriter: no support for non-RGB textures.");
|
||||
}
|
||||
WriteAttrKey(elem, "texuniform", bool_map, 2, pmat->texuniform, def->Material().texuniform);
|
||||
WriteAttr(elem, "texrepeat", 2, pmat->texrepeat, def->Material().texrepeat);
|
||||
|
||||
@@ -782,12 +782,108 @@ TEST_F(XMLReaderTest, FallbackIncludePathTest) {
|
||||
std::array<char, 1024> error;
|
||||
mjModel* model = mj_loadXML(modelpath.c_str(), nullptr,
|
||||
error.data(), error.size());
|
||||
ASSERT_THAT(model, NotNull());
|
||||
ASSERT_THAT(model, NotNull()) << error.data();
|
||||
EXPECT_EQ(mj_name2id(model, mjOBJ_GEOM, "ball"), 2);
|
||||
EXPECT_EQ(mj_name2id(model, mjOBJ_GEOM, "another_box"), 3);
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, MaterialTextureTest) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<asset>
|
||||
<texture file="tiny0.png" type="2d" name="tiny0"/>
|
||||
<texture file="tiny1.png" type="2d" name="tiny1"/>
|
||||
<material name="material">
|
||||
<occlusion texture="tiny0"/>
|
||||
<roughness texture="tiny0"/>
|
||||
<metallic texture="tiny0"/>
|
||||
<rgb texture="tiny1"/>
|
||||
</material>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<geom type="plane" material="material" size="4 4 4"/>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
MockFilesystem fs("MaterialTextureTest");
|
||||
fs.AddFile("tiny0.png", kTinyPng, sizeof(kTinyPng));
|
||||
fs.AddFile("tiny1.png", kTinyPng, sizeof(kTinyPng));
|
||||
fs.AddFile("model.xml", (const unsigned char*) xml, sizeof(xml));
|
||||
std::string modelpath = fs.FullPath("model.xml");
|
||||
|
||||
char error[1024];
|
||||
mjModel* model = mj_loadXML(modelpath.c_str(), nullptr, error, 1024);
|
||||
|
||||
EXPECT_THAT(model, NotNull()) << error;
|
||||
EXPECT_EQ(model->mat_texid[mjTEXROLE_RGB], 1);
|
||||
EXPECT_EQ(model->mat_texid[mjTEXROLE_METALLIC], 0);
|
||||
EXPECT_EQ(model->mat_texid[mjTEXROLE_ROUGHNESS], 0);
|
||||
EXPECT_EQ(model->mat_texid[mjTEXROLE_OCCLUSION], 0);
|
||||
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, LegacyMaterialTextureTest) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<asset>
|
||||
<texture file="tiny0.png" type="2d" name="tiny0"/>
|
||||
<texture file="tiny1.png" type="2d" name="tiny1"/>
|
||||
<material name="material" texture="tiny1"/>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<geom type="plane" material="material" size="4 4 4"/>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
MockFilesystem fs("LegacyMaterialTextureTest");
|
||||
fs.AddFile("tiny0.png", kTinyPng, sizeof(kTinyPng));
|
||||
fs.AddFile("tiny1.png", kTinyPng, sizeof(kTinyPng));
|
||||
fs.AddFile("model.xml", (const unsigned char*) xml, sizeof(xml));
|
||||
std::string modelpath = fs.FullPath("model.xml");
|
||||
|
||||
char error[1024];
|
||||
mjModel* model = mj_loadXML(modelpath.c_str(), nullptr, error, 1024);
|
||||
|
||||
EXPECT_THAT(model, NotNull()) << error;
|
||||
EXPECT_EQ(model->mat_texid[mjTEXROLE_RGB], 1);
|
||||
|
||||
mj_deleteModel(model);
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, MaterialTextureFailTest) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<asset>
|
||||
<texture file="tiny0.png" type="2d" name="tiny0"/>
|
||||
<texture file="tiny1.png" type="2d" name="tiny1"/>
|
||||
<material name="material" texture="tiny1">
|
||||
<rgb texture="tiny1"/>
|
||||
<occlusion texture="tiny0"/>
|
||||
</material>
|
||||
</asset>
|
||||
<worldbody>
|
||||
<geom type="plane" material="material" size="4 4 4"/>
|
||||
</worldbody>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
MockFilesystem fs("MaterialTextureFailTest");
|
||||
fs.AddFile("tiny0.png", kTinyPng, sizeof(kTinyPng));
|
||||
fs.AddFile("tiny1.png", kTinyPng, sizeof(kTinyPng));
|
||||
fs.AddFile("model.xml", (const unsigned char*) xml, sizeof(xml));
|
||||
std::string modelpath = fs.FullPath("model.xml");
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
|
||||
EXPECT_THAT(m, IsNull());
|
||||
EXPECT_THAT(error.data(), HasSubstr("A material with a texture attribute "
|
||||
"cannot have texture sub-elements"));
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, IncludeAssetsTest) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
|
||||
Reference in New Issue
Block a user