Proper lit water on TyrUtils' light.exe

Post tutorials on how to do certain tasks within game or engine code here.
Post Reply
mankrip
Posts: 924
Joined: Fri Jul 04, 2008 3:02 am

Proper lit water on TyrUtils' light.exe

Post by mankrip »

Simple copypaste. Liquid surfaces must be lit not only from the front, but also from the back.

This code includes a hack to force liquid surfaces' lightmaps to always be saved, otherwise fully dark liquids would remain fullbright.

Code: Select all

static int backwater; // mankrip

static void
LightFace_Entity(const entity_t *entity, const lightsample_t *light,
		 const lightsurf_t *lightsurf, lightmap_t *lightmaps)
{
    const modelinfo_t *modelinfo = lightsurf->modelinfo;
    const plane_t *plane = &lightsurf->plane;
    const dmodel_t *shadowself;
    const vec_t *surfpoint;
    int i;
    qboolean hit;
    vec_t dist, add, angle, spotscale;
    lightsample_t *sample;
    lightmap_t *lightmap;
    vec3_t anormal; // mankrip

    dist = DotProduct(entity->origin, plane->normal) - plane->dist;

    VectorCopy (plane->normal, anormal); // mankrip
    /* don't bother with lights behind the surface */
    if (dist < 0)
    // mankrip - begin
    {
        if (!backwater)
    // mankrip - end
            return;
    // mankrip - begin
        VectorInverse (anormal);
    }
    // mankrip - end

    /* don't bother with light too far away */
    if (dist > entity->fadedist)
    if (!backwater) // mankrip
	return;

    /*
     * Check it for real
     */
    hit = false;
    hit = backwater; // mankrip
    lightmap = Lightmap_ForStyle(lightmaps, entity->style);
    shadowself = modelinfo->shadowself ? modelinfo->model : NULL;
    sample = lightmap->samples;
    surfpoint = lightsurf->points[0];
    for (i = 0; i < lightsurf->numpoints; i++, sample++, surfpoint += 3) {
    vec3_t ray;

    VectorSubtract(entity->origin, surfpoint, ray);
    dist = VectorLength(ray);

    /* Quick distance check first */
    if (dist > entity->fadedist)
        continue;

    /* Check spotlight cone */
    VectorScale(ray, 1.0 / dist, ray);
    angle = DotProduct(ray, anormal); // mankrip - edited

[...]

}





void
LightFace(bsp2_dface_t *face, const modelinfo_t *modelinfo,
	  const bsp2_t *bsp)
{
    int i, j, k;
    const entity_t *entity;
    lightsample_t *sample;
    lightsurf_t lightsurf;
    sun_t *sun;

    /* One extra lightmap is allocated to simplify handling overflow */
    lightmap_t lightmaps[MAXLIGHTMAPS + 1];

    /* some surfaces don't need lightmaps */
    face->lightofs = -1;
    for (i = 0; i < MAXLIGHTMAPS; i++)
	face->styles[i] = 255;
    if (bsp->texinfo[face->texinfo].flags & TEX_SPECIAL)
	return;

    // mankrip - begin
    {
    const texinfo_t *tex = &bsp->texinfo[face->texinfo];
    const int offset = bsp->dtexdata.header->dataofs[tex->miptex];
    const miptex_t *miptex = (const miptex_t *)(bsp->dtexdata.base + offset);
    backwater = (miptex->name[0] == '*');
    }
    // mankrip - end

[...]

}
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
qbism
Posts: 1236
Joined: Thu Nov 04, 2004 5:51 am
Contact:

Re: Proper lit water on TyrUtils' light.exe

Post by qbism »

Holy smokes! This has been on wish-lists forever. Surfaces must be lit from both sides because lighting will stop at the surface?
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Proper lit water on TyrUtils' light.exe

Post by Spike »

technically the light coming up from a water surface should be relative to the average light level within the water volume beneath the surface, combined with the light hitting that paritcular part of the surface (spread out a lot without any harsh shadows, representing the amount of light bouncing locally between impurities before being bounced back out of the volume itself - note that this part won't be all that significant, as it would take quite a lot of impurities to completely reflect it all).
the other way around is muuuuch harder to describe, on account of quake not actually having any of those impurities that I just described that give the water itself any colour...
so yeah, just make it accept light from both sides so that a light under the surface doesn't brighten up a wall next to the water without also making the water surface visible too.
just get the lighting tool to completely ignore the surface normal for fully diffuse lighting, because there really isn't any other sane way to deal with it.
which is what I believe mankrip has done.
mankrip
Posts: 924
Joined: Fri Jul 04, 2008 3:02 am

Re: Proper lit water on TyrUtils' light.exe

Post by mankrip »

qbism wrote:Surfaces must be lit from both sides because lighting will stop at the surface?
On the contrary; they won't.

As Spike described, by default a light under the water will brighten any nearby walls all the way without stopping, so the water surface must properly indicate that there's light crossing it.

Spike: No, this code doesn't ignore the normals, it just inverts the normals of backfaced surfaces. This way the lighting on the water surface will match the lighting on the nearby floors.
Ph'nglui mglw'nafh mankrip Hell's end wgah'nagl fhtagn.
==-=-=-=-=-=-=-=-=-=-==
Dev blog / Twitter / YouTube
Post Reply