Forum

Dynamic lights on moving brush models

Post tutorials on how to do certain tasks within game or engine code here.

Moderator: InsideQC Admins

Dynamic lights on moving brush models

Postby mh » Sun Mar 04, 2012 8:46 pm

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:
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
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Dynamic lights on moving brush models

Postby leileilol » Mon Mar 05, 2012 2:49 am

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
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Re: Dynamic lights on moving brush models

Postby mh » Mon Mar 05, 2012 8:59 am

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.
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
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Dynamic lights on moving brush models

Postby toneddu2000 » Mon Mar 05, 2012 12:25 pm

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: 1320
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Dynamic lights on moving brush models

Postby leileilol » Mon Mar 05, 2012 1:05 pm

Weird artifact
Image

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

Postby Baker » Mon Mar 05, 2012 5:09 pm

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? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
User avatar
Baker
 
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Dynamic lights on moving brush models

Postby mh » Mon Mar 05, 2012 5:52 pm

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.
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
User avatar
mh
 
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Re: Dynamic lights on moving brush models

Postby toneddu2000 » Tue Mar 06, 2012 8:44 am

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: 1320
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Dynamic lights on moving brush models

Postby Chip » Tue Mar 06, 2012 1:16 pm

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.
User avatar
Chip
 
Posts: 575
Joined: Wed Jan 21, 2009 9:12 am
Location: Dublin, Ireland

Re: Dynamic lights on moving brush models

Postby toneddu2000 » Tue Mar 06, 2012 3:59 pm

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: 1320
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Dynamic lights on moving brush models

Postby Spike » Tue Mar 06, 2012 4:41 pm

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: 2883
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: Dynamic lights on moving brush models

Postby toneddu2000 » Thu Mar 08, 2012 8:47 am

Thanks Spike! I'll try it and post results in another thread not to spoil this one! :)
toneddu2000
 
Posts: 1320
Joined: Tue Feb 24, 2009 4:39 pm
Location: Italy

Re: Dynamic lights on moving brush models

Postby mankrip » Sat Apr 21, 2012 5:28 pm

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.
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
User avatar
mankrip
 
Posts: 915
Joined: Fri Jul 04, 2008 3:02 am

Re: Dynamic lights on moving brush models

Postby qbism » Sun Apr 22, 2012 12:00 am

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
User avatar
qbism
 
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am

Re: Dynamic lights on moving brush models

Postby leileilol » Sun Apr 22, 2012 7:39 am

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
i should not be here
leileilol
 
Posts: 2783
Joined: Fri Oct 15, 2004 3:23 am

Next

Return to Programming Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest