Page 1 of 3
Dynamic lights on moving brush models
Posted: Sun Mar 04, 2012 8:46 pm
by mh
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:
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;
Re: Dynamic lights on moving brush models
Posted: Mon Mar 05, 2012 2:49 am
by leileilol
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
Re: Dynamic lights on moving brush models
Posted: Mon Mar 05, 2012 8:59 am
by mh
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:
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.
Re: Dynamic lights on moving brush models
Posted: Mon Mar 05, 2012 12:25 pm
by toneddu2000
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)?
Re: Dynamic lights on moving brush models
Posted: Mon Mar 05, 2012 1:05 pm
by leileilol
Weird artifact
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);
}
}
Re: Dynamic lights on moving brush models
Posted: Mon Mar 05, 2012 5:09 pm
by Baker
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).
Re: Dynamic lights on moving brush models
Posted: Mon Mar 05, 2012 5:52 pm
by mh
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.
Re: Dynamic lights on moving brush models
Posted: Tue Mar 06, 2012 8:44 am
by toneddu2000
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
Re: Dynamic lights on moving brush models
Posted: Tue Mar 06, 2012 1:16 pm
by Chip
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.
Re: Dynamic lights on moving brush models
Posted: Tue Mar 06, 2012 3:59 pm
by toneddu2000
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
Re: Dynamic lights on moving brush models
Posted: Tue Mar 06, 2012 4:41 pm
by Spike
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.
Re: Dynamic lights on moving brush models
Posted: Thu Mar 08, 2012 8:47 am
by toneddu2000
Thanks Spike! I'll try it and post results in another thread not to spoil this one!
Re: Dynamic lights on moving brush models
Posted: Sat Apr 21, 2012 5:28 pm
by mankrip
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,
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.
Re: Dynamic lights on moving brush models
Posted: Sun Apr 22, 2012 12:00 am
by qbism
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
Re: Dynamic lights on moving brush models
Posted: Sun Apr 22, 2012 7:39 am
by leileilol
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