📄 light.c
字号:
VectorCopy( origin, baseOrigin );
// try to nudge the origin around to find a valid point
for ( step = 9 ; step <= 18 ; step += 9 ) {
for ( i = 0 ; i < 8 ; i++ ) {
VectorCopy( baseOrigin, origin );
if ( i & 1 ) {
origin[0] += step;
} else {
origin[0] -= step;
}
if ( i & 2 ) {
origin[1] += step;
} else {
origin[1] -= step;
}
if ( i & 4 ) {
origin[2] += step;
} else {
origin[2] -= step;
}
if ( !PointInSolid( origin ) ) {
break;
}
}
if ( i != 8 ) {
break;
}
}
if ( step > 18 ) {
// can't find a valid point at all
for ( i = 0 ; i < 8 ; i++ ) {
gridData[ num*8 + i ] = 0;
}
return;
}
}
VectorClear( summedDir );
// trace to all the lights
// find the major light direction, and divide the
// total light between that along the direction and
// the remaining in the ambient
numCon = 0;
for ( light = lights ; light ; light = light->next ) {
vec3_t add;
vec3_t dir;
float addSize;
if ( !LightContributionToPoint( light, origin, add, &tw ) ) {
continue;
}
VectorSubtract( light->origin, origin, dir );
VectorNormalize( dir, dir );
VectorCopy( add, contributions[numCon].color );
VectorCopy( dir, contributions[numCon].dir );
numCon++;
addSize = VectorLength( add );
VectorMA( summedDir, addSize, dir, summedDir );
if ( numCon == MAX_CONTRIBUTIONS-1 ) {
break;
}
}
//
// trace directly to the sun
//
SunToPoint( origin, &tw, color );
addSize = VectorLength( color );
if ( addSize > 0 ) {
VectorCopy( color, contributions[numCon].color );
VectorCopy( sunDirection, contributions[numCon].dir );
VectorMA( summedDir, addSize, sunDirection, summedDir );
numCon++;
}
// now that we have identified the primary light direction,
// go back and seperate all the light into directed and ambient
VectorNormalize( summedDir, summedDir );
VectorCopy( ambientColor, color );
VectorClear( directedColor );
for ( i = 0 ; i < numCon ; i++ ) {
float d;
d = DotProduct( contributions[i].dir, summedDir );
if ( d < 0 ) {
d = 0;
}
VectorMA( directedColor, d, contributions[i].color, directedColor );
// the ambient light will be at 1/4 the value of directed light
d = 0.25 * ( 1.0 - d );
VectorMA( color, d, contributions[i].color, color );
}
// now do some fudging to keep the ambient from being too low
VectorMA( color, 0.25, directedColor, color );
//
// save the resulting value out
//
ColorToBytes( color, gridData + num*8 );
ColorToBytes( directedColor, gridData + num*8 + 3 );
VectorNormalize( summedDir, summedDir );
NormalToLatLong( summedDir, gridData + num*8 + 6);
}
/*
=============
SetupGrid
=============
*/
void SetupGrid( void ) {
int i;
vec3_t maxs;
for ( i = 0 ; i < 3 ; i++ ) {
gridMins[i] = gridSize[i] * ceil( dmodels[0].mins[i] / gridSize[i] );
maxs[i] = gridSize[i] * floor( dmodels[0].maxs[i] / gridSize[i] );
gridBounds[i] = (maxs[i] - gridMins[i])/gridSize[i] + 1;
}
numGridPoints = gridBounds[0] * gridBounds[1] * gridBounds[2];
if (numGridPoints * 8 >= MAX_MAP_LIGHTGRID)
Error("MAX_MAP_LIGHTGRID");
qprintf( "%5i gridPoints\n", numGridPoints );
}
//=============================================================================
/*
=============
RemoveLightsInSolid
=============
*/
void RemoveLightsInSolid(void)
{
light_t *light, *prev;
int numsolid = 0;
prev = NULL;
for ( light = lights ; light ; ) {
if (PointInSolid(light->origin))
{
if (prev) prev->next = light->next;
else lights = light->next;
if (light->w)
FreeWinding(light->w);
free(light);
numsolid++;
if (prev)
light = prev->next;
else
light = lights;
}
else
{
prev = light;
light = light->next;
}
}
_printf (" %7i lights in solid\n", numsolid);
}
/*
=============
LightWorld
=============
*/
void LightWorld (void) {
float f;
// determine the number of grid points
SetupGrid();
// find the optional world ambient
GetVectorForKey( &entities[0], "_color", ambientColor );
f = FloatForKey( &entities[0], "ambient" );
VectorScale( ambientColor, f, ambientColor );
// create lights out of patches and lights
qprintf ("--- CreateLights ---\n");
CreateEntityLights ();
qprintf ("%i point lights\n", numPointLights);
qprintf ("%i area lights\n", numAreaLights);
if (!nogridlighting) {
qprintf ("--- TraceGrid ---\n");
RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
qprintf( "%i x %i x %i = %i grid\n", gridBounds[0], gridBounds[1],
gridBounds[2], numGridPoints);
}
qprintf ("--- TraceLtm ---\n");
RunThreadsOnIndividual( numDrawSurfaces, qtrue, TraceLtm );
qprintf( "%5i visible samples\n", c_visible );
qprintf( "%5i occluded samples\n", c_occluded );
}
/*
========
CreateFilters
EXPERIMENTAL, UNUSED
Look for transparent light filter surfaces.
This will only work for flat 3*3 patches that exactly hold one copy of the texture.
========
*/
#define PLANAR_PATCH_EPSILON 0.1
void CreateFilters( void ) {
int i;
filter_t *f;
dsurface_t *ds;
shaderInfo_t *si;
drawVert_t *v1, *v2, *v3;
vec3_t d1, d2;
int vertNum;
numFilters = 0;
return;
for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
ds = &drawSurfaces[i];
if ( !ds->patchWidth ) {
continue;
}
si = ShaderInfoForShader( dshaders[ ds->shaderNum ].shader );
/*
if ( !(si->surfaceFlags & SURF_LIGHTFILTER) ) {
continue;
}
*/
// we have a filter patch
v1 = &drawVerts[ ds->firstVert ];
if ( ds->patchWidth != 3 || ds->patchHeight != 3 ) {
_printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't a 3 by 3\n",
v1->xyz[0], v1->xyz[1], v1->xyz[2] );
continue;
}
if ( numFilters == MAX_FILTERS ) {
Error( "MAX_FILTERS" );
}
f = &filters[ numFilters ];
numFilters++;
v2 = &drawVerts[ ds->firstVert + 2 ];
v3 = &drawVerts[ ds->firstVert + 6 ];
VectorSubtract( v2->xyz, v1->xyz, d1 );
VectorSubtract( v3->xyz, v1->xyz, d2 );
VectorNormalize( d1, d1 );
VectorNormalize( d2, d2 );
CrossProduct( d1, d2, f->plane );
f->plane[3] = DotProduct( v1->xyz, f->plane );
// make sure all the control points are on the plane
for ( vertNum = 0 ; vertNum < ds->numVerts ; vertNum++ ) {
float d;
d = DotProduct( drawVerts[ ds->firstVert + vertNum ].xyz, f->plane ) - f->plane[3];
if ( fabs( d ) > PLANAR_PATCH_EPSILON ) {
break;
}
}
if ( vertNum != ds->numVerts ) {
numFilters--;
_printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't flat\n",
v1->xyz[0], v1->xyz[1], v1->xyz[2] );
continue;
}
}
f = &filters[0];
numFilters = 1;
f->plane[0] = 1;
f->plane[1] = 0;
f->plane[2] = 0;
f->plane[3] = 448;
f->origin[0] = 448;
f->origin[1] = 192;
f->origin[2] = 0;
f->vectors[0][0] = 0;
f->vectors[0][1] = -1.0 / 128;
f->vectors[0][2] = 0;
f->vectors[1][0] = 0;
f->vectors[1][1] = 0;
f->vectors[1][2] = 1.0 / 128;
f->si = ShaderInfoForShader( "textures/hell/blocks11ct" );
}
/*
=============
VertexLightingThread
=============
*/
void VertexLightingThread(int num) {
dsurface_t *ds;
traceWork_t tw;
shaderInfo_t *si;
ds = &drawSurfaces[num];
// vertex-lit triangle model
if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
return;
}
if (novertexlighting)
return;
if ( ds->lightmapNum == -1 ) {
return; // doesn't need lighting at all
}
si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
// calculate the vertex lighting for gouraud shade mode
VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
}
/*
=============
TriSoupLightingThread
=============
*/
void TriSoupLightingThread(int num) {
dsurface_t *ds;
traceWork_t tw;
shaderInfo_t *si;
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 );
}
}
/*
=============
GridAndVertexLighting
=============
*/
void GridAndVertexLighting(void) {
SetupGrid();
FindSkyBrushes();
CreateFilters();
InitTrace();
CreateEntityLights ();
CreateSurfaceLights();
if (!nogridlighting) {
_printf ("--- TraceGrid ---\n");
RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
}
if (!novertexlighting) {
_printf ("--- Vertex Lighting ---\n");
RunThreadsOnIndividual( numDrawSurfaces, qtrue, VertexLightingThread );
}
_printf("--- Model Lighting ---\n");
RunThreadsOnIndividual( numDrawSurfaces, qtrue, TriSoupLightingThread );
}
/*
========
LightMain
========
*/
int LightMain (int argc, char **argv) {
int i;
double start, end;
const char *value;
_printf ("----- Lighting ----\n");
verbose = qfalse;
for (i=1 ; i<argc ; i++) {
if (!strcmp(argv[i],"-tempname"))
{
i++;
} else if (!strcmp(argv[i],"-v")) {
verbose = qtrue;
} else if (!strcmp(argv[i],"-threads")) {
numthreads = atoi (argv[i+1]);
i++;
} else if (!strcmp(argv[i],"-area")) {
areaScale *= atof(argv[i+1]);
_printf ("area light scaling at %f\n", areaScale);
i++;
} else if (!strcmp(argv[i],"-point")) {
pointScale *= atof(argv[i+1]);
_printf ("point light scaling at %f\n", pointScale);
i++;
} else if (!strcmp(argv[i],"-notrace")) {
notrace = qtrue;
_printf ("No occlusion tracing\n");
} else if (!strcmp(argv[i],"-patchshadows")) {
patchshadows = qtrue;
_printf ("Patch shadow casting enabled\n");
} else if (!strcmp(argv[i],"-extra")) {
extra = qtrue;
_printf ("Extra detail tracing\n");
} else if (!strcmp(argv[i],"-extrawide")) {
extra = qtrue;
extraWide = qtrue;
_printf ("Extra wide detail tracing\n");
} else if (!strcmp(argv[i], "-samplesize")) {
samplesize = atoi(argv[i+1]);
if (samplesize < 1) samplesize = 1;
i++;
_printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
} else if (!strcmp(argv[i], "-novertex")) {
novertexlighting = qtrue;
_printf("no vertex lighting = true\n");
} else if (!strcmp(argv[i], "-nogrid")) {
nogridlighting = qtrue;
_printf("no grid lighting = true\n");
} else if (!strcmp(argv[i],"-border")) {
lightmapBorder = qtrue;
_printf ("Adding debug border to lightmaps\n");
} else if (!strcmp(argv[i],"-nosurf")) {
noSurfaces = qtrue;
_printf ("Not tracing against surfaces\n" );
} else if (!strcmp(argv[i],"-dump")) {
dump = qtrue;
_printf ("Dumping occlusion maps\n");
} else {
break;
}
}
ThreadSetDefault ();
if (i != argc - 1) {
_printf("usage: q3map -light [-<switch> [-<switch> ...]] <mapname>\n"
"\n"
"Switches:\n"
" v = verbose output\n"
" threads <X> = set number of threads to X\n"
" area <V> = set the area light scale to V\n"
" point <W> = set the point light scale to W\n"
" notrace = don't cast any shadows\n"
" extra = enable super sampling for anti-aliasing\n"
" extrawide = same as extra but smoothen more\n"
" nogrid = don't calculate light grid for dynamic model lighting\n"
" novertex = don't calculate vertex lighting\n"
" samplesize <N> = set the lightmap pixel size to NxN units\n");
exit(0);
}
start = I_FloatTime ();
SetQdirFromPath (argv[i]);
#ifdef _WIN32
InitPakFile(gamedir, NULL);
#endif
strcpy (source, ExpandArg(argv[i]));
StripExtension (source);
DefaultExtension (source, ".bsp");
LoadShaderInfo();
_printf ("reading %s\n", source);
LoadBSPFile (source);
FindSkyBrushes();
ParseEntities();
value = ValueForKey( &entities[0], "gridsize" );
if (strlen(value)) {
sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
_printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
}
CreateFilters();
InitTrace();
SetEntityOrigins();
CountLightmaps();
CreateSurfaceLights();
LightWorld();
_printf ("writing %s\n", source);
WriteBSPFile (source);
end = I_FloatTime ();
_printf ("%5.0f seconds elapsed\n", end-start);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -