light: implement self shadowing option for brush models

Brush models can now self shadow without casting shadows on their
environment, using the "_shadowself" entity key.

Signed-off-by: Kevin Shanahan <kmshanah@disenchant.net>
This commit is contained in:
Kevin Shanahan 2013-03-08 15:02:36 +10:30
parent dc39137874
commit d6ef23453a
6 changed files with 65 additions and 27 deletions

View File

@ -1,6 +1,6 @@
Unreleased
* light: brush model entities with the "_shadow" key will cast shadows
* light: implemented self shadowing and full shadows for brush models
2013-03-07 TyrUtils v0.6

View File

@ -33,13 +33,14 @@
#define MAXLIGHTS 1024
qboolean TestSky(const vec3_t start, const vec3_t dirn);
qboolean TestSky(const vec3_t start, const vec3_t dirn, vec3_t skypoint);
qboolean TestLine(const vec3_t start, const vec3_t stop);
qboolean TestLineModel(const dmodel_t *model,
const vec3_t start, const vec3_t stop);
typedef struct {
const dmodel_t *model;
qboolean shadowself;
int minlight;
vec3_t mincolor;
vec3_t offset;

View File

@ -68,6 +68,7 @@ ENTITY PARAMETERS
Set the brightness of the sunlight coming from an unseen sun in the
sky. Sky brushes (or more accurately bsp leafs with sky contents) will
emit sunlight at an angle specified by the "_sun_mangle" paramter.
Default 0.
"_sun_mangle" "x y z"
@ -75,12 +76,14 @@ ENTITY PARAMETERS
in degrees. Yaw specifies the angle around the Z-axis from 0 to 359
degrees and pitch specifies the angle from 90 (straight up) to -90
(straight down). Roll has no effect, so use any value (e.g. 0).
Default is straight down ("0 -90 0").
"_sunlight_color" "r g b"
Specify red(r), green(g) and blue(b) components for the colour of the
sunlight. RGB component values are between -255 and 255. Negative
values will cause colour subtraction from light cast by other entities.
Default is white light ("255 255 255").
MODEL PARAMETERS
@ -89,17 +92,27 @@ ENTITY PARAMETERS
"_minlight" "n"
Set the minimum light level for any surface of the brush model.
Default 0.
"_mincolor" "r g b"
Specify red(r), green(g) and blue(b) components for the colour of the
minlight. RGB component values are between 0 and 255.
minlight. RGB component values are between 0 and 255. Default is
white light ("255 255 255").
"_shadow" "1"
"_shadow" "n"
This model will cast shadows. Note that this doesn't magically give
Quake dynamic lighting powers, so the shadows will not move if the
model moves.
If n is 1, this model will cast shadows on other models and itself
(i.e. "_shadow" implies "_shadowself"). Note that this doesn't
magically give Quake dynamic lighting powers, so the shadows will
not move if the model moves. Default 0.
"_shadowself" "n"
If n is 1, this model will cast shadows on itself if one part
of the model blocks the light from another model surface. This
can be a better compromise for moving models than full
shadowing. Default 0.
LIGHT PARAMETERS

View File

@ -130,10 +130,15 @@ FindModelInfo(void)
Error("%s: Couldn't find entity for model %s.\n", __func__,
modelname);
/* Check if this model will cast shadows */
/* Check if this model will cast shadows (shadow => shadowself) */
shadow = atoi(ValueForKey(entity, "_shadow"));
if (shadow)
if (shadow) {
shadowmodels[numshadowmodels++] = &dmodels[i];
} else {
shadow = atoi(ValueForKey(entity, "_shadowself"));
if (shadow)
modelinfo[i].shadowself = true;
}
/* Set up the offset for rotate_* entities */
attribute = ValueForKey(entity, "classname");

View File

@ -125,9 +125,8 @@ solve3(const vec3_t mtx[3], const int r[3], const int c[3],
#define SINGLEMAP (18*18*4*4)
typedef struct {
vec_t *light;
dface_t *face;
const modelinfo_t *modelinfo;
const dface_t *face;
vec_t facedist;
vec3_t facenormal;
@ -270,7 +269,7 @@ face_centroid(const dface_t *f, vec3_t out)
static void
CalcFaceExtents(lightinfo_t *l, const vec3_t offset)
{
dface_t *s;
const dface_t *s;
vec_t mins[2], maxs[2], val;
vec3_t centroid;
int i, j, e;
@ -526,6 +525,9 @@ SingleLightFace(const entity_t *light, lightinfo_t *l, const vec3_t colors)
/* Test for line of sight */
if (!TestLine(light->origin, surf))
continue;
if (l->modelinfo->shadowself)
if (!TestLineModel(l->modelinfo->model, light->origin, surf))
continue;
angle = (1.0 - scalecos) + scalecos * angle;
add = GetLightValue(light, dist) * angle * spotscale;
@ -637,12 +639,16 @@ SkyLightFace(lightinfo_t *l, const vec3_t colors)
#else
surf = l->surfpt[0];
for (i = 0; i < l->numsurfpt; i++, surf += 3) {
if (TestSky(surf, sunvec)) {
lightmap[i] += angle * sunlight;
if (colored)
VectorMA(colormap[i], angle * sunlight / 255.0f, colors,
colormap[i]);
}
vec3_t skypoint;
if (!TestSky(surf, sunvec, skypoint))
continue;
if (l->modelinfo->shadowself)
if (!TestLineModel(l->modelinfo->model, surf, skypoint))
continue;
lightmap[i] += angle * sunlight;
if (colored)
VectorMA(colormap[i], angle * sunlight / 255.0f, colors,
colormap[i]);
}
#endif
}
@ -726,16 +732,29 @@ FixMinlight(lightinfo_t *l, const int minlight, const vec3_t mincolor)
trace = TestLine(entity->origin, l->surfpt[j]);
if (!trace)
continue;
if (l->modelinfo->shadowself) {
trace = TestLineModel(l->modelinfo->model, entity->origin, l->surfpt[j]);
if (!trace)
continue;
}
lightmap[j] = entity->light;
}
if (!colored)
continue;
for (k = 0; k < 3; k++) {
if (colormap[j][k] < mincolor[k]) {
if (!trace)
if (!trace) {
trace = TestLine(entity->origin, l->surfpt[j]);
if (trace)
colormap[j][k] = mincolor[k];
if (!trace)
break;
if (l->modelinfo->shadowself) {
trace = TestLineModel(l->modelinfo->model,
entity->origin, l->surfpt[j]);
if (!trace)
break;
}
}
colormap[j][k] = mincolor[k];
}
}
}
@ -829,6 +848,7 @@ LightFace(int surfnum, const modelinfo_t *modelinfo)
return; /* non-lit texture */
memset(&l, 0, sizeof(l));
l.modelinfo = modelinfo;
l.face = face;
/* rotate plane */

View File

@ -215,17 +215,16 @@ TestLineModel(const dmodel_t *model, const vec3_t start, const vec3_t stop)
* a CONTENTS_SOLID node.
*/
qboolean
TestSky(const vec3_t start, const vec3_t dirn)
TestSky(const vec3_t start, const vec3_t dirn, vec3_t skypoint)
{
vec3_t stop;
const dmodel_t *const *model;
VectorAdd(dirn, start, stop);
if (!TestLineOrSky(tracelist[0], start, stop, true, stop))
VectorAdd(dirn, start, skypoint);
if (!TestLineOrSky(tracelist[0], start, skypoint, true, skypoint))
return false;
for (model = tracelist + 1; *model; model++)
if (!TestLineModel(*model, start, stop))
if (!TestLineModel(*model, start, skypoint))
break;
return !*model;