📄 light.c
字号:
VectorScale( sample, 255/max, sample );
}
// save the sample
for ( j = 0 ; j < 3 ; j++ ) {
if ( sample[j] > 255 ) {
sample[j] = 255;
}
dv->color[j] = sample[j];
}
// Don't bother writing alpha since it will already be set to 255,
// plus we don't want to write over alpha generated by SetTerrainTextures
//dv->color[3] = 255;
}
}
/*
=================
LinearSubdivideMesh
For extra lighting, just midpoint one of the axis.
The edges are clamped at the original edges.
=================
*/
mesh_t *LinearSubdivideMesh( mesh_t *in ) {
int i, j;
mesh_t *out;
drawVert_t *v1, *v2, *vout;
out = malloc( sizeof( *out ) );
out->width = in->width * 2;
out->height = in->height;
out->verts = malloc( out->width * out->height * sizeof(*out->verts) );
for ( j = 0 ; j < in->height ; j++ ) {
out->verts[ j * out->width + 0 ] = in->verts[ j * in->width + 0 ];
out->verts[ j * out->width + out->width - 1 ] = in->verts[ j * in->width + in->width - 1 ];
for ( i = 1 ; i < out->width - 1 ; i+= 2 ) {
v1 = in->verts + j * in->width + (i >> 1);
v2 = v1 + 1;
vout = out->verts + j * out->width + i;
vout->xyz[0] = 0.75 * v1->xyz[0] + 0.25 * v2->xyz[0];
vout->xyz[1] = 0.75 * v1->xyz[1] + 0.25 * v2->xyz[1];
vout->xyz[2] = 0.75 * v1->xyz[2] + 0.25 * v2->xyz[2];
vout->normal[0] = 0.75 * v1->normal[0] + 0.25 * v2->normal[0];
vout->normal[1] = 0.75 * v1->normal[1] + 0.25 * v2->normal[1];
vout->normal[2] = 0.75 * v1->normal[2] + 0.25 * v2->normal[2];
VectorNormalize( vout->normal, vout->normal );
vout++;
vout->xyz[0] = 0.25 * v1->xyz[0] + 0.75 * v2->xyz[0];
vout->xyz[1] = 0.25 * v1->xyz[1] + 0.75 * v2->xyz[1];
vout->xyz[2] = 0.25 * v1->xyz[2] + 0.75 * v2->xyz[2];
vout->normal[0] = 0.25 * v1->normal[0] + 0.75 * v2->normal[0];
vout->normal[1] = 0.25 * v1->normal[1] + 0.75 * v2->normal[1];
vout->normal[2] = 0.25 * v1->normal[2] + 0.75 * v2->normal[2];
VectorNormalize( vout->normal, vout->normal );
}
}
FreeMesh( in );
return out;
}
/*
==============
ColorToBytes
==============
*/
void ColorToBytes( const float *color, byte *colorBytes ) {
float max;
vec3_t sample;
VectorCopy( color, sample );
// clamp with color normalization
max = sample[0];
if ( sample[1] > max ) {
max = sample[1];
}
if ( sample[2] > max ) {
max = sample[2];
}
if ( max > 255 ) {
VectorScale( sample, 255/max, sample );
}
colorBytes[ 0 ] = sample[0];
colorBytes[ 1 ] = sample[1];
colorBytes[ 2 ] = sample[2];
}
/*
=============
TraceLtm
=============
*/
void TraceLtm( int num ) {
dsurface_t *ds;
int i, j, k;
int x, y;
int position, numPositions;
vec3_t base, origin, normal;
byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
vec3_t color[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
traceWork_t tw;
vec3_t average;
int count;
mesh_t srcMesh, *mesh, *subdivided;
shaderInfo_t *si;
static float nudge[2][9] = {
{ 0, -1, 0, 1, -1, 1, -1, 0, 1 },
{ 0, -1, -1, -1, 0, 0, 1, 1, 1 }
};
int sampleWidth, sampleHeight, ssize;
vec3_t lightmapOrigin, lightmapVecs[2];
int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_WIDTH];
ds = &drawSurfaces[num];
si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
// vertex-lit triangle model
if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
return;
}
if ( ds->lightmapNum == -1 ) {
return; // doesn't need lighting at all
}
if (!novertexlighting) {
// calculate the vertex lighting for gouraud shade mode
VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
}
if ( ds->lightmapNum < 0 ) {
return; // doesn't need lightmap lighting
}
si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
ssize = samplesize;
if (si->lightmapSampleSize)
ssize = si->lightmapSampleSize;
if (si->patchShadows)
tw.patchshadows = qtrue;
else
tw.patchshadows = patchshadows;
if ( ds->surfaceType == MST_PATCH ) {
srcMesh.width = ds->patchWidth;
srcMesh.height = ds->patchHeight;
srcMesh.verts = drawVerts + ds->firstVert;
mesh = SubdivideMesh( srcMesh, 8, 999 );
PutMeshOnCurve( *mesh );
MakeMeshNormals( *mesh );
subdivided = RemoveLinearMeshColumnsRows( mesh );
FreeMesh(mesh);
mesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
if ( mesh->width != ds->lightmapWidth || mesh->height != ds->lightmapHeight ) {
Error( "Mesh lightmap miscount");
}
if ( extra ) {
mesh_t *mp;
// chop it up for more light samples (leaking memory...)
mp = mesh;//CopyMesh( mesh );
mp = LinearSubdivideMesh( mp );
mp = TransposeMesh( mp );
mp = LinearSubdivideMesh( mp );
mp = TransposeMesh( mp );
mesh = mp;
}
} else {
VectorCopy( ds->lightmapVecs[2], normal );
if ( !extra ) {
VectorCopy( ds->lightmapOrigin, lightmapOrigin );
VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
} else {
// sample at a closer spacing for antialiasing
VectorCopy( ds->lightmapOrigin, lightmapOrigin );
VectorScale( ds->lightmapVecs[0], 0.5, lightmapVecs[0] );
VectorScale( ds->lightmapVecs[1], 0.5, lightmapVecs[1] );
VectorMA( lightmapOrigin, -0.5, lightmapVecs[0], lightmapOrigin );
VectorMA( lightmapOrigin, -0.5, lightmapVecs[1], lightmapOrigin );
}
}
if ( extra ) {
sampleWidth = ds->lightmapWidth * 2;
sampleHeight = ds->lightmapHeight * 2;
} else {
sampleWidth = ds->lightmapWidth;
sampleHeight = ds->lightmapHeight;
}
memset ( color, 0, sizeof( color ) );
// determine which samples are occluded
memset ( occluded, 0, sizeof( occluded ) );
for ( i = 0 ; i < sampleWidth ; i++ ) {
for ( j = 0 ; j < sampleHeight ; j++ ) {
if ( ds->patchWidth ) {
numPositions = 9;
VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
// VectorNormalize( normal, normal );
// push off of the curve a bit
VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
} else {
numPositions = 9;
for ( k = 0 ; k < 3 ; k++ ) {
base[k] = lightmapOrigin[k] + normal[k]
+ i * lightmapVecs[0][k]
+ j * lightmapVecs[1][k];
}
}
VectorAdd( base, surfaceOrigin[ num ], base );
// we may need to slightly nudge the sample point
// if directly on a wall
for ( position = 0 ; position < numPositions ; position++ ) {
// calculate lightmap sample position
for ( k = 0 ; k < 3 ; k++ ) {
origin[k] = base[k] +
+ ( nudge[0][position]/16 ) * lightmapVecs[0][k]
+ ( nudge[1][position]/16 ) * lightmapVecs[1][k];
}
if ( notrace ) {
break;
}
if ( !PointInSolid( origin ) ) {
break;
}
}
// if none of the nudges worked, this sample is occluded
if ( position == numPositions ) {
occluded[i][j] = qtrue;
if ( numthreads == 1 ) {
c_occluded++;
}
continue;
}
if ( numthreads == 1 ) {
c_visible++;
}
occluded[i][j] = qfalse;
LightingAtSample( origin, normal, color[i][j], qtrue, qfalse, &tw );
}
}
if ( dump ) {
PrintOccluded( occluded, sampleWidth, sampleHeight );
}
// calculate average values for occluded samples
for ( i = 0 ; i < sampleWidth ; i++ ) {
for ( j = 0 ; j < sampleHeight ; j++ ) {
if ( !occluded[i][j] ) {
continue;
}
// scan all surrounding samples
count = 0;
VectorClear( average );
for ( x = -1 ; x <= 1; x++ ) {
for ( y = -1 ; y <= 1 ; y++ ) {
if ( i + x < 0 || i + x >= sampleWidth ) {
continue;
}
if ( j + y < 0 || j + y >= sampleHeight ) {
continue;
}
if ( occluded[i+x][j+y] ) {
continue;
}
count++;
VectorAdd( color[i+x][j+y], average, average );
}
}
if ( count ) {
VectorScale( average, 1.0/count, color[i][j] );
}
}
}
// average together the values if we are extra sampling
if ( ds->lightmapWidth != sampleWidth ) {
for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
for ( k = 0 ; k < 3 ; k++ ) {
float value, coverage;
value = color[i*2][j*2][k] + color[i*2][j*2+1][k] +
color[i*2+1][j*2][k] + color[i*2+1][j*2+1][k];
coverage = 4;
if ( extraWide ) {
// wider than box filter
if ( i > 0 ) {
value += color[i*2-1][j*2][k] + color[i*2-1][j*2+1][k];
value += color[i*2-2][j*2][k] + color[i*2-2][j*2+1][k];
coverage += 4;
}
if ( i < ds->lightmapWidth - 1 ) {
value += color[i*2+2][j*2][k] + color[i*2+2][j*2+1][k];
value += color[i*2+3][j*2][k] + color[i*2+3][j*2+1][k];
coverage += 4;
}
if ( j > 0 ) {
value += color[i*2][j*2-1][k] + color[i*2+1][j*2-1][k];
value += color[i*2][j*2-2][k] + color[i*2+1][j*2-2][k];
coverage += 4;
}
if ( j < ds->lightmapHeight - 1 ) {
value += color[i*2][j*2+2][k] + color[i*2+1][j*2+2][k];
value += color[i*2][j*2+3][k] + color[i*2+1][j*2+3][k];
coverage += 2;
}
}
color[i][j][k] = value / coverage;
}
}
}
}
// optionally create a debugging border around the lightmap
if ( lightmapBorder ) {
for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
color[i][0][0] = 255;
color[i][0][1] = 0;
color[i][0][2] = 0;
color[i][ds->lightmapHeight-1][0] = 255;
color[i][ds->lightmapHeight-1][1] = 0;
color[i][ds->lightmapHeight-1][2] = 0;
}
for ( i = 0 ; i < ds->lightmapHeight ; i++ ) {
color[0][i][0] = 255;
color[0][i][1] = 0;
color[0][i][2] = 0;
color[ds->lightmapWidth-1][i][0] = 255;
color[ds->lightmapWidth-1][i][1] = 0;
color[ds->lightmapWidth-1][i][2] = 0;
}
}
// clamp the colors to bytes and store off
for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j)
* LIGHTMAP_WIDTH + ds->lightmapX + i;
ColorToBytes( color[i][j], lightBytes + k*3 );
}
}
if (ds->surfaceType == MST_PATCH)
{
FreeMesh(mesh);
}
}
//=============================================================================
vec3_t gridMins;
vec3_t gridSize = { 64, 64, 128 };
int gridBounds[3];
/*
========================
LightContributionToPoint
========================
*/
qboolean LightContributionToPoint( const light_t *light, const vec3_t origin,
vec3_t color, traceWork_t *tw ) {
trace_t trace;
float add;
add = 0;
VectorClear( color );
// testing exact PTPFF
if ( exactPointToPolygon && light->type == emit_area ) {
float factor;
float d;
vec3_t normal;
// see if the point is behind the light
d = DotProduct( origin, light->normal ) - light->dist;
if ( !light->twosided ) {
if ( d < 1 ) {
return qfalse; // point is behind light
}
}
// test occlusion
// clip the line, tracing from the surface towards the light
TraceLine( origin, light->origin, &trace, qfalse, tw );
if ( trace.passSolid ) {
return qfalse;
}
// calculate the contribution
VectorSubtract( light->origin, origin, normal );
if ( VectorNormalize( normal, normal ) == 0 ) {
return qfalse;
}
factor = PointToPolygonFormFactor( origin, normal, light->w );
if ( factor <= 0 ) {
if ( light->twosided ) {
factor = -factor;
} else {
return qfalse;
}
}
VectorScale( light->emitColor, factor, color );
return qtrue;
}
// calculate the amount of light at this sample
if ( light->type == emit_point || light->type == emit_spotlight ) {
vec3_t dir;
float dist;
VectorSubtract( light->origin, origin, dir );
dist = VectorLength( dir );
// clamp the distance to prevent super hot spots
if ( dist < 16 ) {
dist = 16;
}
if ( light->linearLight ) {
add = light->photons * linearScale - dist;
if ( add < 0 ) {
add = 0;
}
} else {
add = light->photons / ( dist * dist );
}
} else {
return qfalse;
}
if ( add <= 1.0 ) {
return qfalse;
}
// clip the line, tracing from the surface towards the light
TraceLine( origin, light->origin, &trace, qfalse, tw );
// other light rays must not hit anything
if ( trace.passSolid ) {
return qfalse;
}
// add the result
color[0] = add * light->color[0];
color[1] = add * light->color[1];
color[2] = add * light->color[2];
return qtrue;
}
typedef struct {
vec3_t dir;
vec3_t color;
} contribution_t;
/*
=============
TraceGrid
Grid samples are foe quickly determining the lighting
of dynamically placed entities in the world
=============
*/
#define MAX_CONTRIBUTIONS 1024
void TraceGrid( int num ) {
int x, y, z;
vec3_t origin;
light_t *light;
vec3_t color;
int mod;
vec3_t directedColor;
vec3_t summedDir;
contribution_t contributions[MAX_CONTRIBUTIONS];
int numCon;
int i;
traceWork_t tw;
float addSize;
mod = num;
z = mod / ( gridBounds[0] * gridBounds[1] );
mod -= z * ( gridBounds[0] * gridBounds[1] );
y = mod / gridBounds[0];
mod -= y * gridBounds[0];
x = mod;
origin[0] = gridMins[0] + x * gridSize[0];
origin[1] = gridMins[1] + y * gridSize[1];
origin[2] = gridMins[2] + z * gridSize[2];
if ( PointInSolid( origin ) ) {
vec3_t baseOrigin;
int step;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -