Skip to content

Commit cc7fb98

Browse files
havesscopybara-github
authored andcommitted
Add texture coordinates to primitive shape types.
PiperOrigin-RevId: 964882123 Change-Id: I17723d21f29b3fe28e171de5c3d2bea1f55a94c2
1 parent 4929f2c commit cc7fb98

18 files changed

Lines changed: 556 additions & 372 deletions

doc/changelog.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,21 @@ Rendering
8585
.. admonition:: Breaking API changes
8686
:class: attention
8787

88+
.. image:: https://www.gstatic.com/mujoco/doc/images/changelog/primitives_textured.gif
89+
:align: right
90+
:width: 40%
91+
92+
- Added explicit texture coordinates to built-in geometries (Plane, Box, Sphere, Ellipsoid, Capsule,
93+
Cylinder) in both the Classic renderer and Filament. 2D textures applied to primitive shapes will look different
94+
as textures are mapped using canonical UV parameterizations rather than projecting onto the :math:`x,y` plane.
95+
96+
For finite planes, textures are now anchored to the bottom-left corner instead of the center. This will cause the
97+
most common visual breakage, as common procedural checker textures will be phase shifted. Infinite planes continue
98+
to be anchored at the origin with no visual changes.
99+
100+
.. image:: images/changelog/plane_uv_tiling.png
101+
:align: center
102+
:width: 70%
88103
- Added :ref:`light/softness<body-light-softness>`: edge softness for spotlights under physically-based lighting
89104
models, given as the fraction of the cone over which intensity falls to zero. The default of 0.2 is a semi-soft
90105
cone which delivers the full :ref:`intensity<body-light-intensity>` everywhere inside it, so that illuminance
163 KB
Loading

src/experimental/filament/compat/scene_geom_util.cc

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,6 @@
2828

2929
namespace mujoco {
3030

31-
// Returns the tile size for infinite plane texture alignment.
32-
// This is duplicated from engine_vis_visualize.c (re-center infinite plane)
33-
// to ensure UV scaling matches the re-centering increments.
34-
static float GetPlaneTileSize(const mjModel* model, int matid,
35-
float texrepeat) {
36-
if (matid >= 0 && texrepeat > 0) {
37-
return 2.0f / texrepeat;
38-
} else {
39-
const float zfar = model->vis.map.zfar * model->stat.extent;
40-
return 2.1f * zfar / (mjMAXPLANEGRID - 2);
41-
}
42-
}
43-
4431
static void PrepareGeomMeshes(mjrfRenderable* renderable, const mjvGeom& geom,
4532
ModelObjects* model_objs,
4633
SceneObjects* scene_objs) {
@@ -230,37 +217,31 @@ static void UpdateGeomMaterial(mjrfRenderable* renderable, const mjvGeom& geom,
230217
}
231218
}
232219

233-
if (tex_uniform) {
234-
if (geom.size[0] > 0) {
235-
material.uv_scale[0] *= geom.size[0];
236-
}
237-
if (geom.size[1] > 0) {
238-
material.uv_scale[1] *= geom.size[1];
239-
}
240-
}
241220
const bool is_infinite_plane =
242221
geom.type == mjGEOM_PLANE && (geom.size[0] <= 0 || geom.size[1] <= 0);
243222
if (is_infinite_plane) {
244-
// Infinite planes are scaled to match the tile size used by
245-
// re-centering in engine_vis_visualize.c.
246223
const float plane_scale = static_cast<float>(mjMAXPLANEGRID) / 2.0f;
247-
const float tile_size_x =
248-
GetPlaneTileSize(model, geom.matid, tex_repeat[0]);
249-
const float tile_size_y =
250-
GetPlaneTileSize(model, geom.matid, tex_repeat[1]);
251-
material.uv_scale[0] = 2.0f * plane_scale / tile_size_x;
252-
material.uv_scale[1] = 2.0f * plane_scale / tile_size_y;
253-
}
254224

255-
// We want to do the equivalent of:
256-
// mjr_setf4(splane, 0.5 * scl.x, 0, 0, -0.5);
257-
// mjr_setf4(tplane, 0, -0.5 * scl.y, 0, -0.5);
258-
// glTexGenfv(GL_S, GL_OBJECT_PLANE, splane);
259-
// glTexGenfv(GL_T, GL_OBJECT_PLANE, tplane);
260-
material.uv_scale[0] = 0.5f * material.uv_scale[0];
261-
material.uv_scale[1] = -0.5f * material.uv_scale[1];
262-
material.uv_offset[0] = -0.5f;
263-
material.uv_offset[1] = -0.5f;
225+
const float dot_pos_axis_x = geom.pos[0] * geom.mat[0] +
226+
geom.pos[1] * geom.mat[3] +
227+
geom.pos[2] * geom.mat[6];
228+
const float dot_pos_axis_y = geom.pos[0] * geom.mat[1] +
229+
geom.pos[1] * geom.mat[4] +
230+
geom.pos[2] * geom.mat[7];
231+
232+
material.uv_scale[0] *= plane_scale;
233+
material.uv_scale[1] *= plane_scale;
234+
// The vertex UVs in PlaneBuilder are u0 = 0.5*x + 0.5, v0 = -0.5*y + 0.5.
235+
// To keep the world-space texture coordinate u = 0.5*worldX*texrepeat - 0.5
236+
// independent of the snapped geomPos, uv_offset must compensate by 0.5*dot_pos.
237+
material.uv_offset[0] =
238+
(0.5f * dot_pos_axis_x - 0.5f * plane_scale) * tex_repeat[0] - 0.5f;
239+
material.uv_offset[1] =
240+
(-0.5f * dot_pos_axis_y - 0.5f * plane_scale) * tex_repeat[1] - 0.5f;
241+
} else if (tex_uniform) {
242+
material.uv_scale[0] *= (geom.size[0] ? geom.size[0] : 1.0f);
243+
material.uv_scale[1] *= (geom.size[1] ? geom.size[1] : 1.0f);
244+
}
264245
} else {
265246
// For cube maps, if `tex_uniform` is true, then scale the texture so that
266247
// it covers a 1x1 area of world space rather than the area of the object.

0 commit comments

Comments
 (0)