Dynamic lights on moving brush models
Moderator: InsideQC Admins
34 posts
• Page 1 of 3 • 1, 2, 3
Dynamic lights on moving brush models
Here we're going to fix dynamic lights so that they will correctly apply to moving brush models. This can be seen all over Quake, but a good example is the first secret in e1m4. After the shaft doors open and you kill the wizard, give yourself the rocket launcher and shoot it up at the platform. It's lit properly. Now shoot the two switches to lower the platform and jump to the bottom of the shaft. Shoot a few weapons to get the muzzleflash, and the platform isn't lit. That's because dynamic lights take no account of differences in entity positions; they're always at the origin so far as lights are concerned.
DISCLAIMER
This isn't the best way to fix it. I'm well aware of that. I am however showing this way so that it can be used as a baseline for doing it right. Also, it involves much fewer code modifications so it's easier to demonstrate what's needed without needing an overhaul of other parts of the engine first. It's expected that any serious implementation will do it better (e.g. by generalizing R_PushDlights and by properly calculating the inverse matrix in software).
So, add this to your dlight_t struct:
Then find your R_DrawBrushModel and replace the relevant part of the code with this:
In R_PushDlights add this before the call to R_MarkLights:
And the rest is easy - just replace the use of "origin" in R_MarkLights and R_AddDynamicLights with "transformed", thus:
DISCLAIMER
This isn't the best way to fix it. I'm well aware of that. I am however showing this way so that it can be used as a baseline for doing it right. Also, it involves much fewer code modifications so it's easier to demonstrate what's needed without needing an overhaul of other parts of the engine first. It's expected that any serious implementation will do it better (e.g. by generalizing R_PushDlights and by properly calculating the inverse matrix in software).
So, add this to your dlight_t struct:
- Code: Select all
vec3_t transformed;
Then find your R_DrawBrushModel and replace the relevant part of the code with this:
- Code: Select all
// calculate dynamic lighting for bmodel if it's not an instanced model
if (clmodel->firstmodelsurface != 0 && !gl_flashblend.value)
{
float matrix[16];
// get the inverse transform for moving the light back to the same space as the model
glPushMatrix ();
glLoadIdentity ();
glRotatef (-e->angles[2], 1, 0, 0);
glRotatef (-e->angles[0], 0, 1, 0);
glRotatef (-e->angles[1], 0, 0, 1);
glTranslatef (-e->origin[0], -e->origin[1], -e->origin[2]);
glGetFloatv (GL_MODELVIEW_MATRIX, matrix);
glPopMatrix ();
for (k = 0; k < MAX_DLIGHTS; k++)
{
if ((cl_dlights[k].die < cl.time) || (!cl_dlights[k].radius))
continue;
// move the light back to the same space as the model
cl_dlights[k].transformed[0] = cl_dlights[k].origin[0] * matrix[0] + cl_dlights[k].origin[1] * matrix[4] + cl_dlights[k].origin[2] * matrix[8] + matrix[12];
cl_dlights[k].transformed[1] = cl_dlights[k].origin[0] * matrix[1] + cl_dlights[k].origin[1] * matrix[5] + cl_dlights[k].origin[2] * matrix[9] + matrix[13];
cl_dlights[k].transformed[2] = cl_dlights[k].origin[0] * matrix[2] + cl_dlights[k].origin[1] * matrix[6] + cl_dlights[k].origin[2] * matrix[10] + matrix[14];
// light the model
R_MarkLights (&cl_dlights[k], 1 << k, clmodel->nodes + clmodel->hulls[0].firstclipnode);
}
}
In R_PushDlights add this before the call to R_MarkLights:
- Code: Select all
VectorCopy (l->origin, l->transformed);
And the rest is easy - just replace the use of "origin" in R_MarkLights and R_AddDynamicLights with "transformed", thus:
- Code: Select all
dist = DotProduct (light->transformed, splitplane->normal) - splitplane->dist;
- Code: Select all
dist = DotProduct (cl_dlights[lnum].transformed, surf->plane->normal) -
surf->plane->dist;
- Code: Select all
impact[i] = cl_dlights[lnum].transformed[i] -
surf->plane->normal[i]*dist;
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
-
mh - Posts: 2286
- Joined: Sat Jan 12, 2008 1:38 am
Re: Dynamic lights on moving brush models
COOL!!!!! I'll try to try this in software.
a good place to test this is dm2's moving platform
In software, the R_DrawBrushModel equivelant is R_DrawBEntitiesOnList in r_main.c
i'm only a bit lost on the matrix translation
a good place to test this is dm2's moving platform
In software, the R_DrawBrushModel equivelant is R_DrawBEntitiesOnList in r_main.c
i'm only a bit lost on the matrix translation
i should not be here
- leileilol
- Posts: 2783
- Joined: Fri Oct 15, 2004 3:23 am
Re: Dynamic lights on moving brush models
I'm not entirely certain I've got it right myself (in particular the inverse part) - the code was originally written for an engine where nice helper functions to do this kind of thing were available.
It's enough to just move each light by the entities origin though; something like this:
Since the original Quake didn't have rotating bmodels this will be fine.
It's enough to just move each light by the entities origin though; something like this:
- Code: Select all
cl_dlights[k].transformed[0] = cl_dlights[k].origin[0] - e->origin[0];
cl_dlights[k].transformed[1] = cl_dlights[k].origin[1] - e->origin[1];
cl_dlights[k].transformed[2] = cl_dlights[k].origin[2] - e->origin[2];
Since the original Quake didn't have rotating bmodels this will be fine.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
-
mh - Posts: 2286
- Joined: Sat Jan 12, 2008 1:38 am
Re: Dynamic lights on moving brush models
SuperCool! So, if I understood correctly, if I use Ode, I could make a swinging lamp which castes real time shadows(like far cry did in a map)?
- toneddu2000
- Posts: 1278
- Joined: Tue Feb 24, 2009 4:39 pm
- Location: Italy
Re: Dynamic lights on moving brush models
Weird artifact

R_DrawBEntitiesOnList

R_DrawBEntitiesOnList
- Code: Select all
// calculate dynamic lighting for bmodel if it's not an
// instanced model
if (clmodel->firstmodelsurface != 0)
{
for (k=0 ; k<MAX_DLIGHTS ; k++)
{
if ((cl_dlights[k].die < cl.time) ||
(!cl_dlights[k].radius))
{
continue;
}
// MH dlight fix
// move the light back to the same space as the model
cl_dlights[k].transformed[0] = cl_dlights[k].origin[0] - r_entorigin[0];
cl_dlights[k].transformed[1] = cl_dlights[k].origin[1] - r_entorigin[1];
cl_dlights[k].transformed[2] = cl_dlights[k].origin[2] - r_entorigin[2];
R_MarkLights (&cl_dlights[k], 1<<k,
clmodel->nodes + clmodel->hulls[0].firstclipnode);
}
for (k=0 ; k<MAX_SHADOWS ; k++)
{
if ((cl_shadows[k].die < cl.time) ||
(!cl_shadows[k].radius))
{
continue;
}
R_MarkShadows (&cl_shadows[k], 1<<k,
clmodel->nodes + clmodel->hulls[0].firstclipnode);
}
}
i should not be here
- leileilol
- Posts: 2783
- Joined: Fri Oct 15, 2004 3:23 am
Re: Dynamic lights on moving brush models
toneddu2000 wrote:SuperCool! So, if I understood correctly, if I use Ode, I could make a swinging lamp which castes real time shadows(like far cry did in a map)?
No this is making original Quake's existing feature work right. In MH's first post he provides an example.
Examples of dynamic light in Quake (WinQuake and GL) is the illumination of firing a rocket and as the rocket moves the area under the rocket is lit up on the surface of the floor. On moving brush models --- a brush model is a door ... essentially anything that is part of a map --- Quake doesn't treat them properly (in a great many ways, really).
The night is young. How else can I annoy the world before sunsrise?
Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..

-
Baker - Posts: 3660
- Joined: Tue Mar 14, 2006 5:15 am
Re: Dynamic lights on moving brush models
I've been looking over the software Quake source and it seems that further work is needed for this.
As I understand it, the basic loop goes something like this:
- Identify which entities get drawn
- Mark lights in the world
- Mark lights for entities
- Build surface caches for the world
- Build surface caches for entities
- Draw the lot
The problem here is that the "transformed" member will go out of step - it's necessary to retransform again during the surface cache building stages, for both entities and for the world.
As I understand it, the basic loop goes something like this:
- Identify which entities get drawn
- Mark lights in the world
- Mark lights for entities
- Build surface caches for the world
- Build surface caches for entities
- Draw the lot
The problem here is that the "transformed" member will go out of step - it's necessary to retransform again during the surface cache building stages, for both entities and for the world.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
-
mh - Posts: 2286
- Joined: Sat Jan 12, 2008 1:38 am
Re: Dynamic lights on moving brush models
Baker wrote:No this is making original Quake's existing feature work right. In MH's first post he provides an example.
Ah,ok, thanks. Sorry for my unmotivated enthusiasm!

Anyway, is it so difficult to "link" dinamyc lights (at least in DP) with models in map?So for example, use a func_train with a light with dynamic shadows that when it moves along a path it casts dynamic shadows?...it would be cool
- toneddu2000
- Posts: 1278
- Joined: Tue Feb 24, 2009 4:39 pm
- Location: Italy
Re: Dynamic lights on moving brush models
toneddu2000 wrote:Baker wrote:No this is making original Quake's existing feature work right. In MH's first post he provides an example.
Ah,ok, thanks. Sorry for my unmotivated enthusiasm!
Anyway, is it so difficult to "link" dinamyc lights (at least in DP) with models in map?So for example, use a func_train with a light with dynamic shadows that when it moves along a path it casts dynamic shadows?...it would be cool
Did you try r_shadows 1, or r_shadows 2?
Also, r_shadow_shadowmapping (1 or 2) depending on your Darkplaces build.
QuakeWiki
getButterfly - WordPress Support Services
Roo Holidays
Fear not the dark, but what the dark hides.
getButterfly - WordPress Support Services
Roo Holidays
Fear not the dark, but what the dark hides.
-
Chip - Posts: 575
- Joined: Wed Jan 21, 2009 9:12 am
- Location: Dublin, Ireland
Re: Dynamic lights on moving brush models
Thanks Chip for the hint but I didn't want to cast fake shadows, I want to parent a real light to a model, so wherever the model goes the shadow will cast realtime shadows
- toneddu2000
- Posts: 1278
- Joined: Tue Feb 24, 2009 4:39 pm
- Location: Italy
Re: Dynamic lights on moving brush models
there's some tenebrae extension that allows you to attach proper realtime lights to entities, but you might need stuff like MOVETYPE_FOLLOW if its a bsp entity.
- Spike
- Posts: 2873
- Joined: Fri Nov 05, 2004 3:12 am
- Location: UK
Re: Dynamic lights on moving brush models
Thanks Spike! I'll try it and post results in another thread not to spoil this one! 

- toneddu2000
- Posts: 1278
- Joined: Tue Feb 24, 2009 4:39 pm
- Location: Italy
Re: Dynamic lights on moving brush models
Thanks for bringing this up mh. Now I understand why Quake never had big moving trains, or really complex sets of moving BSP entities.
I just figured out how to implement this in Makaqu, and here's a copy-paste tutorial.
Just open r_light.c, copy/overwrite the four lines featuring the "dynamic lights on moving brush models fix" string below,
... and do the same for the corresponding four lines in r_surf.c:
Actually, the main problem with the BSP renderer, at least in software, is that it does not care much about entities, and do much of the work by blindly navigating through the BSP tree. As you can see, I had to set currententity in R_PushDlights because it wasn't set prior to that.
I just figured out how to implement this in Makaqu, and here's a copy-paste tutorial.
Just open r_light.c, copy/overwrite the four lines featuring the "dynamic lights on moving brush models fix" string below,
- Code: Select all
void R_MarkLights (dlight_t *light, int bit, mnode_t *node)
{
mplane_t *splitplane;
float dist;
msurface_t *surf;
int i;
vec3_t origin_for_ent; // mankrip - dynamic lights on moving brush models fix
if (node->contents < 0)
return;
splitplane = node->plane;
VectorSubtract (light->origin, currententity->origin, origin_for_ent); // mankrip - dynamic lights on moving brush models fix
dist = DotProduct (origin_for_ent, splitplane->normal) - splitplane->dist; // mankrip - dynamic lights on moving brush models fix - edited
if (dist > light->radius)
{
R_MarkLights (light, bit, node->children[0]);
return;
}
if (dist < -light->radius)
{
R_MarkLights (light, bit, node->children[1]);
return;
}
// mark the polygons
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i=0 ; i<node->numsurfaces ; i++, surf++)
{
if (surf->dlightframe != r_dlightframecount)
{
surf->dlightbits = 0;
surf->dlightframe = r_dlightframecount;
}
surf->dlightbits |= bit;
}
R_MarkLights (light, bit, node->children[0]);
R_MarkLights (light, bit, node->children[1]);
}
/*
=============
R_PushDlights
=============
*/
void R_PushDlights (void)
{
int i;
dlight_t *l;
r_dlightframecount = r_framecount + 1; // because the count hasn't
// advanced yet for this frame
l = cl_dlights;
currententity = &cl_entities[0]; // mankrip - dynamic lights on moving brush models fix
for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
{
if (l->die < cl.time || !l->radius)
continue;
R_MarkLights ( l, 1<<i, cl.worldmodel->nodes );
}
}
... and do the same for the corresponding four lines in r_surf.c:
- Code: Select all
void R_AddDynamicLights (void)
{
msurface_t *surf;
int lnum;
int sd, td;
float dist, rad, minlight;
vec3_t impact, local;
vec3_t origin_for_ent; // mankrip - dynamic lights on moving brush models fix
int s, t;
int i;
int smax, tmax;
mtexinfo_t *tex;
surf = r_drawsurf.surf;
smax = (surf->extents[0]>>4)+1;
tmax = (surf->extents[1]>>4)+1;
tex = surf->texinfo;
for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
{
if ( !(surf->dlightbits & (1<<lnum) ) )
continue; // not lit by this light
rad = cl_dlights[lnum].radius;
VectorSubtract (cl_dlights[lnum].origin, currententity->origin, origin_for_ent); // mankrip - dynamic lights on moving brush models fix
dist = DotProduct (origin_for_ent, surf->plane->normal) - // mankrip - dynamic lights on moving brush models fix - edited
surf->plane->dist;
rad -= fabs(dist);
minlight = cl_dlights[lnum].minlight;
if (rad < minlight)
continue;
minlight = rad - minlight;
for (i=0 ; i<3 ; i++)
{
impact[i] = origin_for_ent[i] - // mankrip - dynamic lights on moving brush models fix - edited
surf->plane->normal[i]*dist;
}
local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
local[0] -= surf->texturemins[0];
local[1] -= surf->texturemins[1];
for (t = 0 ; t<tmax ; t++)
{
td = local[1] - t*16;
if (td < 0)
td = -td;
for (s=0 ; s<smax ; s++)
{
sd = local[0] - s*16;
if (sd < 0)
sd = -sd;
if (sd > td)
dist = sd + (td>>1);
else
dist = td + (sd>>1);
if (dist < minlight)
//#ifdef QUAKE2
{
unsigned temp;
temp = (rad - dist)*256;
i = t*smax + s;
if (!cl_dlights[lnum].dark)
blocklights[i] += temp;
else
{
if (blocklights[i] > temp)
blocklights[i] -= temp;
else
blocklights[i] = 0;
}
}
//#else
// blocklights[t*smax + s] += (rad - dist)*256;
//#endif
}
}
}
}
mh wrote:As I understand it, the basic loop goes something like this:
- Identify which entities get drawn
[...]
Actually, the main problem with the BSP renderer, at least in software, is that it does not care much about entities, and do much of the work by blindly navigating through the BSP tree. As you can see, I had to set currententity in R_PushDlights because it wasn't set prior to that.
-
mankrip - Posts: 908
- Joined: Fri Jul 04, 2008 3:02 am
Re: Dynamic lights on moving brush models
mankrip wrote:I just figured out how to implement this in Makaqu, and here's a copy-paste tutorial.
Quick copy-paste test on E1M4 works great! This can be combined with mh's "Extending the number of dynamic lights" tute. http://forums.inside3d.com/viewtopic.php?t=4257
-
qbism - Posts: 1235
- Joined: Thu Nov 04, 2004 5:51 am
Re: Dynamic lights on moving brush models
I just applied it to Engoo's shadows!
It's now in svn but i believe I hit a wall lighting bug. I tried to apply this onto the faster lordhavoc marklights function, a video
It's now in svn but i believe I hit a wall lighting bug. I tried to apply this onto the faster lordhavoc marklights function, a video
i should not be here
- leileilol
- Posts: 2783
- Joined: Fri Oct 15, 2004 3:23 am
34 posts
• Page 1 of 3 • 1, 2, 3
Return to Programming Tutorials
Who is online
Users browsing this forum: No registered users and 1 guest