Skip to content

Commit 40393f4

Browse files
Google DeepMindcopybara-github
authored andcommitted
Fix shadow flickering artefacts on platforms that do not support ARB_clip_control.
PiperOrigin-RevId: 743112447 Change-Id: Ibb727685605c0a257547162703f61e5232ff544c
1 parent b839fe7 commit 40393f4

File tree

3 files changed

+27
-6
lines changed

3 files changed

+27
-6
lines changed

doc/changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ Bug fixes
2424
which the Jacobian is computed, now fixed.
2525
- Fixed a bug that caused the parent frame of elements in the child worldbody to be incorrectly set when attaching an
2626
mjSpec to a frame or a site.
27+
- Fixed a bug that caused shadow rendering to flicker on platforms (e.g., MacOS) that do not support ARB_clip_control.
28+
Fixed in collaboration with :github:user:`aftersomemath`.
2729

2830
Python bindings
2931
^^^^^^^^^^^^^^^

src/render/render_context.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,13 +1050,17 @@ static void makeShadow(const mjModel* m, mjrContext* con) {
10501050
}
10511051
glBindFramebuffer(GL_FRAMEBUFFER, con->shadowFBO);
10521052

1053-
// create shadow depth texture: in TEXTURE1
1053+
// Create a shadow depth texture in TEXTURE1 and explicitly select an int24
1054+
// depth buffer. A depth stencil format is used because that appears to be
1055+
// more widely supported (MacOS does not support GL_DEPTH_COMPONENT24). Using
1056+
// a fixed format makes it easier to choose glPolygonOffset parameters that
1057+
// result in reasonably consistent and artifact free shadows across platforms.
10541058
glGenTextures(1, &con->shadowTex);
10551059
glActiveTexture(GL_TEXTURE1);
10561060
glEnable(GL_TEXTURE_2D);
10571061
glBindTexture(GL_TEXTURE_2D, con->shadowTex);
1058-
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
1059-
con->shadowSize, con->shadowSize, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
1062+
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8,
1063+
con->shadowSize, con->shadowSize, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
10601064
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
10611065
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
10621066
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

src/render/render_gl3.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,9 +1211,24 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) {
12111211
int cull_face = glIsEnabled(GL_CULL_FACE);
12121212
glDisable(GL_CULL_FACE); // all faces cast shadows
12131213
glEnable(GL_POLYGON_OFFSET_FILL);
1214-
float kOffsetFactor = -1.5f;
1215-
float kOffsetUnits = -4.0f;
1216-
glPolygonOffset(kOffsetFactor, kOffsetUnits); // prevents "shadow acne"
1214+
1215+
// The limited resolution of the shadow maps means multiple fragments
1216+
// sample the same texel. When light and camera directions differ on
1217+
// surfaces that should be lit this causes "shadow acne" because some
1218+
// fragments will be lit while adjacent fragments are not. To mitigate
1219+
// this artifact, an offset is applied to the depth values in the
1220+
// shadow map. The offset must be large enough to ensure consistent
1221+
// depth comparison occurs within the limited precision of the depth
1222+
// buffer. The offset is computed by glPolygonOffset using parameters
1223+
// that are chosen empirically. We need different values when clip
1224+
// control is on/off because this setting changes the depth precision.
1225+
float kOffsetFactor = -16.0f;
1226+
float kOffsetUnits = -512.0f;
1227+
if (mjGLAD_GL_ARB_clip_control) {
1228+
kOffsetFactor = -1.5f;
1229+
kOffsetUnits = -4.0f;
1230+
}
1231+
glPolygonOffset(kOffsetFactor, kOffsetUnits);
12171232

12181233
// render all geoms to depth texture
12191234
for (int j=0; j < ngeom; j++) {

0 commit comments

Comments
 (0)