Shadows on brush models
Moderator: InsideQC Admins
19 posts
• Page 2 of 2 • 1, 2
tenebrae uses something a bit like an early version of dp's rtlights
so it would seem it does :S
pretty much nothing of the old ligth code remains.
this is what remains.
so it would seem it does :S
pretty much nothing of the old ligth code remains.
- Code: Select all
// r_light.c - PENTA: almost obsolete now
#include "quakedef.h"
int r_dlightframecount;
/*
==================
R_AnimateLight
==================
*/
void R_AnimateLight (void)
{
int i,j,k;
//
// light animations
// 'm' is normal light, 'a' is no light, 'z' is double bright
i = (int)(cl.time*10);
for (j=0 ; j<MAX_LIGHTSTYLES ; j++)
{
if (!cl_lightstyle[j].length)
{
d_lightstylevalue[j] = 256;
continue;
}
k = i % cl_lightstyle[j].length;
k = cl_lightstyle[j].map[k] - 'a';
k = k*22;
d_lightstylevalue[j] = k;
}
}
/*
=============================================================================
LIGHT SAMPLING
=============================================================================
*/
mplane_t *lightplane;
vec3_t lightspot;
int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end)
{
int r;
float front, back, frac;
int side;
mplane_t *plane;
vec3_t mid;
msurface_t *surf;
int s, t, ds, dt;
int i;
mtexinfo_t *tex;
byte *lightmap;
unsigned scale;
int maps;
if (node->contents < 0)
{
return -1; // didn't hit anything
}
// calculate mid point
plane = node->plane;
front = DotProduct (start, plane->normal) - plane->dist;
back = DotProduct (end, plane->normal) - plane->dist;
side = front < 0;
if ( (back < 0) == side)
{
return RecursiveLightPoint (node->children[side], start, end);
}
frac = front / (front-back);
mid[0] = start[0] + (end[0] - start[0])*frac;
mid[1] = start[1] + (end[1] - start[1])*frac;
mid[2] = start[2] + (end[2] - start[2])*frac;
// go down front side
r = RecursiveLightPoint (node->children[side], start, mid);
if (r >= 0)
{
return r; // hit something
}
if ( (back < 0) == side )
{
return -1; // didn't hit anuthing
}
// check for impact on this node
VectorCopy (mid, lightspot);
lightplane = plane;
surf = cl.worldmodel->surfaces + node->firstsurface;
for (i=0 ; i<node->numsurfaces ; i++, surf++)
{
if (surf->flags & SURF_DRAWTILED) continue; // no lightmaps
tex = surf->texinfo;
s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3];
t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];;
if (s < surf->texturemins[0] || t < surf->texturemins[1]) continue;
ds = s - surf->texturemins[0];
dt = t - surf->texturemins[1];
if ( ds > surf->extents[0] || dt > surf->extents[1] ) continue;
if (!surf->samples)
{
return 0;
}
ds >>= 4;
dt >>= 4;
lightmap = surf->samples;
r = 0;
if (lightmap)
{
lightmap += dt * ((surf->extents[0]>>4)+1) + ds;
for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; maps++)
{
scale = d_lightstylevalue[surf->styles[maps]];
r += *lightmap * scale;
lightmap += ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1);
}
r >>= 8;
}
return r;
}
// go down back side
return RecursiveLightPoint (node->children[!side], mid, end);
}
int R_LightPoint (vec3_t p)
{
vec3_t end;
int r;
if (!cl.worldmodel->lightdata)
{
return 255;
}
end[0] = p[0];
end[1] = p[1];
end[2] = p[2] - 2048;
r = RecursiveLightPoint (cl.worldmodel->nodes, p, end);
if (r == -1)
{
r = 0;
}
return r;
}
this is what remains.
-

revelator - Posts: 2567
- Joined: Thu Jan 24, 2008 12:04 pm
- Location: inside tha debugger
reckless wrote:looking at tenebraes i once thought hey it cant be that hard but im still to have a breakthrough with that one (does tenenbraes shadow volumes assume per pixel lighting ?).
It does.
Technically without per pixel lighting to mask off with the stencil buffer, all you're doing is some crude hack.
r_shadows in darkplaces applies a 50% gray multiply blend on the whole screen where the stencil buffer is set.
Shadow volumes work on this principle:
From a set of geometry facing the light source (or facing away from it) you can extrude a volume - each triangle produces a front triangle (identical to the original) and a back triangle (stretched far away from the lightsource), it also produces a quad (2 triangles) for each non-casting edge (silhouette quads).
Clear stencil buffer - as a practical matter I clear it to 128.
Render all objects using a stencil increment where zfail for backfaces (facing away from the viewer) and a stencil decrement where zfail for frontfaces (facing toward the viewer).
This results in pixels inside the shadow volume being marked as 129 (or more in the case of overlapping shadows), because the decrement did not occur on the frontfaces, because the frontfaces of the volume were zpass (which was set to do nothing), not zfail on those pixels.
So you end up with literally a count of how many shadows are on each pixel.
DarkPlaces computes the triangleneighbors array at load for each model/map, containing 3 triangle indexes per triangle, which are -1 if there is no triangle sharing that edge (or if more than one other triangle is sharing that edge! be careful about this, the dog model and some others have some redundantly shared edges, be sure they are stored as -1), the algorithm is simply to look up every triangle that uses the same two vertices as this edge, and there are 3 edges per triangle.
Lights simply mark which triangles should cast shadows, and call the casting code with that list of triangles, it generates a new mesh from those triangles (the shadow volume).
After all this, you can render lighting with stencil test on (and compare to 128), any pixel that is 128 receives light, any pixel that is not 128 does not.
r_shadows works similarly but inverted - render a fullscreen "shadow" quad (alpha blending some black works fine for this) where stencil is not 128 - and obviously this uses fake light sources for each entity for the shadow casting itself.
Side effect of any fake shadowing is shadow bleed (seeing a shadow on the floor below a ledge a monster is standing on), this is the main drawback.
Shadow bleed does not occur with real light sources being masked, because the ledge itself is casting shadows in that case, one can not tell that multiple shadows are stacked on the floor below.
Note that shadowmapping works differently - a depth texture is bound as a framebuffer object's depth attachment, no color buffers are bound, and all the geometry is rendered from the light's viewpoint, as 6 separate views.
Then this texture is bound as a shader input when rendering the lighting and each pixel it has to make a decision as to which of the 6 views contains the data it wants, read that pixel and neighboring pixels and compare them to the depth value it expects for this pixel (from the light's view!) to get a white or black result, then blur between those shadow comparison results a bit (soft shadowing).
You can find the shadowmapping and all other shader code used in DP here: http://ghdigital.com/~havoc/default.glsl (Note: usually somewhat out of date, I post updated shader code to this occasionally, not every time it is changed in darkplaces svn)
- LordHavoc
- Posts: 322
- Joined: Fri Nov 05, 2004 3:12 am
- Location: western Oregon, USA
19 posts
• Page 2 of 2 • 1, 2
Who is online
Users browsing this forum: No registered users and 1 guest
