From a3425c72a75acd7f1655881ecbf09a99ba4d4f29 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Thu, 30 Jul 2026 13:13:07 -0700 Subject: [PATCH] Ignore unsupported light types in the classic renderer. The classic renderer supports only directional and spot lights, but initLights() set GL light colors for every scene light before dispatching on type, and the render passes enabled GL light slots without filtering. Since no position was ever set for unsupported types (mjLIGHT_POINT, mjLIGHT_IMAGE), OpenGL's default eye-space position turned them into phantom headlights with the model light's diffuse color, washing out the scene. A cast-shadow image light additionally triggered a full shadow pass with an unset light projection. Filter all light setup and enable sites on a shared type predicate, so unsupported light types contribute nothing. The no-lights ambient fallback now applies when no supported lights are present. PiperOrigin-RevId: 956696548 Change-Id: Ic29763df7f9330f21d94f14501ae2559fd460f2b --- src/render/classic/render_gl3.c | 53 +++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/render/classic/render_gl3.c b/src/render/classic/render_gl3.c index f986c0ff..b5ee76c3 100644 --- a/src/render/classic/render_gl3.c +++ b/src/render/classic/render_gl3.c @@ -667,10 +667,23 @@ static void initGL3(const mjvScene* scn, const mjrContext* con) { +// light type is supported by the fixed-function pipeline +static int isSupportedLight(const mjvLight* light) { + return light->type == mjLIGHT_DIRECTIONAL || light->type == mjLIGHT_SPOT; +} + + + // init lights static void initLights(mjvScene* scn) { - // create some ambient light if no ligths are present - float global = scn->nlight ? 0 : 0.3f; + // count supported lights + int nsupported = 0; + for (int i=0; i < scn->nlight; i++) { + nsupported += isSupportedLight(scn->lights+i); + } + + // create some ambient light if no supported lights are present + float global = nsupported ? 0 : 0.3f; float rgba_global[4] = {global, global, global, 1}; // init light model @@ -680,6 +693,11 @@ static void initLights(mjvScene* scn) { // set light properties for (int i=0; i < scn->nlight; i++) { + // ignore unsupported light types: mjLIGHT_POINT, mjLIGHT_IMAGE + if (!isSupportedLight(scn->lights+i)) { + continue; + } + // colors glLightfv(GL_LIGHT0+i, GL_AMBIENT, scn->lights[i].ambient); glLightfv(GL_LIGHT0+i, GL_DIFFUSE, scn->lights[i].diffuse); @@ -702,10 +720,6 @@ static void initLights(mjvScene* scn) { glLightf(GL_LIGHT0+i, GL_LINEAR_ATTENUATION, scn->lights[i].attenuation[1]); glLightf(GL_LIGHT0+i, GL_QUADRATIC_ATTENUATION, scn->lights[i].attenuation[2]); } - - else { - // ignore unsupported light types: mjLIGHT_POINT, mjLIGHT_IMAGE - } } // disable all lights (enable selectively in render) @@ -1089,10 +1103,12 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { glPushMatrix(); mjr_reflect(thisgeom->pos, thisgeom->mat); - // set light position and direction, enable + // set light position and direction, enable supported lights for (int j=0; j < nlight; j++) { - adjustLight(scn->lights+j, j); - glEnable(GL_LIGHT0+j); + if (isSupportedLight(scn->lights+j)) { + adjustLight(scn->lights+j, j); + glEnable(GL_LIGHT0+j); + } } // render reflected non-transparent geoms, except for thisgeom @@ -1143,8 +1159,13 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { // set light position and direction, enable non-shadow lights for (int i=0; i < nlight; i++) { - // set light + // get pointer, ignore unsupported light types thislight = scn->lights + i; + if (!isSupportedLight(thislight)) { + continue; + } + + // set light adjustLight(thislight, i); // enable lights without shadows @@ -1184,10 +1205,10 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { // shadow map rendering if (scn->flags[mjRND_SHADOW] && con->shadowFBO) { for (int i=0; i < nlight; i++) { - // get pointer + // get pointer, ignore unsupported light types thislight = scn->lights + i; - if (thislight->castshadow) { + if (thislight->castshadow && isSupportedLight(thislight)) { // prepare up-direction mjr_orthoVec(temp, thislight->dir); @@ -1210,8 +1231,6 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { } else if (thislight->type == mjLIGHT_SPOT) { mjr_perspective(mju_min(2*thislight->cutoff*con->shadowScale, 160), 1, cam.frustum_near, cam.frustum_far); - } else { - // ignore unsupported light types: mjLIGHT_POINT, mjLIGHT_IMAGE } glGetFloatv(GL_PROJECTION_MATRIX, lightProject); @@ -1408,9 +1427,11 @@ void mjr_render(mjrRect viewport, mjvScene* scn, const mjrContext* con) { //------------------------------------ transparent regular rendering - // enable lights + // enable supported lights for (int i=0; i < nlight; i++) { - glEnable(GL_LIGHT0+i); + if (isSupportedLight(scn->lights+i)) { + glEnable(GL_LIGHT0+i); + } } // blend mode