⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 light.c

📁 quake3工具源码。包括生成bsp文件
💻 C
📖 第 1 页 / 共 4 页
字号:
SetEntityOrigins

Find the offset values for inline models
================
*/
void SetEntityOrigins( void ) {
	int			i, j;
	entity_t	*e;
	vec3_t		origin;
	const char	*key;
	int			modelnum;
	dmodel_t	*dm;

	for ( i=0 ; i < num_entities ; i++ ) {
		e = &entities[i];
		key = ValueForKey (e, "model");
		if ( key[0] != '*' ) {
			continue;
		}
		modelnum = atoi( key + 1 );
		dm = &dmodels[ modelnum ];

		// set entity surface to true for all surfaces for this model
		for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
			entitySurface[ dm->firstSurface + j ] = qtrue;
		}

		key = ValueForKey (e, "origin");
		if ( !key[0] ) {
			continue;
		}
		GetVectorForKey ( e, "origin", origin );

		// set origin for all surfaces for this model
		for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
			VectorCopy( origin, surfaceOrigin[ dm->firstSurface + j ] );
		}
	}
}


/*
=================================================================


=================================================================
*/

#define	MAX_POINTS_ON_WINDINGS	64

/*
================
PointToPolygonFormFactor
================
*/
float	PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ) {
	vec3_t		triVector, triNormal;
	int			i, j;
	vec3_t		dirs[MAX_POINTS_ON_WINDING];
	float		total;
	float		dot, angle, facing;

	for ( i = 0 ; i < w->numpoints ; i++ ) {
		VectorSubtract( w->p[i], point, dirs[i] );
		VectorNormalize( dirs[i], dirs[i] );
	}

	// duplicate first vertex to avoid mod operation
	VectorCopy( dirs[0], dirs[i] );

	total = 0;
	for ( i = 0 ; i < w->numpoints ; i++ ) {
		j = i+1;
		dot = DotProduct( dirs[i], dirs[j] );

		// roundoff can cause slight creep, which gives an IND from acos
		if ( dot > 1.0 ) {
			dot = 1.0;
		} else if ( dot < -1.0 ) {
			dot = -1.0;
		}
		
		angle = acos( dot );
		CrossProduct( dirs[i], dirs[j], triVector );
		if ( VectorNormalize( triVector, triNormal ) < 0.0001 ) {
			continue;
		}
		facing = DotProduct( normal, triNormal );
		total += facing * angle;

		if ( total > 6.3 || total < -6.3 ) {
			static qboolean printed;

			if ( !printed ) {
				printed = qtrue;
				_printf( "WARNING: bad PointToPolygonFormFactor: %f at %1.1f %1.1f %1.1f from %1.1f %1.1f %1.1f\n", total,
					w->p[i][0], w->p[i][1], w->p[i][2], point[0], point[1], point[2]);
			}
			return 0;
		}

	}

	total /= 2*3.141592657;		// now in the range of 0 to 1 over the entire incoming hemisphere

	return total;
}


/*
================
FilterTrace

Returns 0 to 1.0 filter fractions for the given trace
================
*/
void	FilterTrace( const vec3_t start, const vec3_t end, vec3_t filter ) {
	float		d1, d2;
	filter_t	*f;
	int			filterNum;
	vec3_t		point;
	float		frac;
	int			i;
	float		s, t;
	int			u, v;
	int			x, y;
	byte		*pixel;
	float		radius;
	float		len;
	vec3_t		total;

	filter[0] = 1.0;
	filter[1] = 1.0;
	filter[2] = 1.0;

	for ( filterNum = 0 ; filterNum < numFilters ; filterNum++ ) {
		f = &filters[ filterNum ];

		// see if the plane is crossed
		d1 = DotProduct( start, f->plane ) - f->plane[3];
		d2 = DotProduct( end, f->plane ) - f->plane[3];

		if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
			continue;
		}

		// calculate the crossing point
		frac = d1 / ( d1 - d2 );

		for ( i = 0 ; i < 3 ; i++ ) {
			point[i] = start[i] + frac * ( end[i] - start[i] );
		}

		VectorSubtract( point, f->origin, point );

		s = DotProduct( point, f->vectors[0] );
		t = 1.0 - DotProduct( point, f->vectors[1] );
		if ( s < 0 || s >= 1.0 || t < 0 || t >= 1.0 ) {
			continue;
		}

		// decide the filter size
		radius = 10 * frac;
		len = VectorLength( f->vectors[0] );
		if ( !len ) {
			continue;
		}
		radius = radius * len * f->si->width;

		// look up the filter, taking multiple samples
		VectorClear( total );
		for ( u = -1 ; u <= 1 ; u++ ) {
			for ( v = -1 ; v <=1 ; v++ ) {
				x = s * f->si->width + u * radius;
				if ( x < 0 ) {
					x = 0;
				}
				if ( x >= f->si->width ) {
					x = f->si->width - 1;
				}
				y = t * f->si->height + v * radius;
				if ( y < 0 ) {
					y = 0;
				}
				if ( y >= f->si->height ) {
					y = f->si->height - 1;
				}

				pixel = f->si->pixels + ( y * f->si->width + x ) * 4;
				total[0] += pixel[0];
				total[1] += pixel[1];
				total[2] += pixel[2];
			}
		}

		filter[0] *= total[0]/(255.0*9);
		filter[1] *= total[1]/(255.0*9);
		filter[2] *= total[2]/(255.0*9);
	}

}

/*
================
SunToPoint

Returns an amount of light to add at the point
================
*/
int		c_sunHit, c_sunMiss;
void SunToPoint( const vec3_t origin, traceWork_t *tw, vec3_t addLight ) {
	int			i;
	trace_t		trace;
	skyBrush_t	*b;
	vec3_t		end;

	if ( !numSkyBrushes ) {
		VectorClear( addLight );
		return;
	}

	VectorMA( origin, MAX_WORLD_COORD * 2, sunDirection, end );

	TraceLine( origin, end, &trace, qtrue, tw );

	// see if trace.hit is inside a sky brush
	for ( i = 0 ; i < numSkyBrushes ; i++) {
		b = &skyBrushes[ i ];

		// this assumes that sky brushes are axial...
		if (   trace.hit[0] < b->bounds[0][0] 
			|| trace.hit[0] > b->bounds[1][0]
			|| trace.hit[1] < b->bounds[0][1]
			|| trace.hit[1] > b->bounds[1][1]
			|| trace.hit[2] < b->bounds[0][2]
			|| trace.hit[2] > b->bounds[1][2] ) {
			continue;
		}


		// trace again to get intermediate filters
		TraceLine( origin, trace.hit, &trace, qtrue, tw );

		// we hit the sky, so add sunlight
		if ( numthreads == 1 ) {
			c_sunHit++;
		}
		addLight[0] = trace.filter[0] * sunLight[0];
		addLight[1] = trace.filter[1] * sunLight[1];
		addLight[2] = trace.filter[2] * sunLight[2];

		return;
	}

	if ( numthreads == 1 ) {
		c_sunMiss++;
	}

	VectorClear( addLight );
}

/*
================
SunToPlane
================
*/
void SunToPlane( const vec3_t origin, const vec3_t normal, vec3_t color, traceWork_t *tw ) {
	float		angle;
	vec3_t		sunColor;

	if ( !numSkyBrushes ) {
		return;
	}

	angle = DotProduct( normal, sunDirection );
	if ( angle <= 0 ) {
		return;		// facing away
	}

	SunToPoint( origin, tw, sunColor );
	VectorMA( color, angle, sunColor, color );
}

/*
================
LightingAtSample
================
*/
void LightingAtSample( vec3_t origin, vec3_t normal, vec3_t color, 
					  qboolean testOcclusion, qboolean forceSunLight, traceWork_t *tw ) {
	light_t		*light;
	trace_t		trace;
	float		angle;
	float		add;
	float		dist;
	vec3_t		dir;

	VectorCopy( ambientColor, color );

	// trace to all the lights
	for ( light = lights ; light ; light = light->next ) {

		//MrE: if the light is behind the surface
		if ( DotProduct(light->origin, normal) - DotProduct(normal, origin) < 0 )
			continue;
		// testing exact PTPFF
		if ( exactPointToPolygon && light->type == emit_area ) {
			float		factor;
			float		d;
			vec3_t		pushedOrigin;

			// see if the point is behind the light
			d = DotProduct( origin, light->normal ) - light->dist;
			if ( !light->twosided ) {
				if ( d < -1 ) {
					continue;		// point is behind light
				}
			}

			// test occlusion and find light filters
			// clip the line, tracing from the surface towards the light
			if ( !notrace && testOcclusion ) {
				TraceLine( origin, light->origin, &trace, qfalse, tw );

				// other light rays must not hit anything
				if ( trace.passSolid ) {
					continue;
				}
			} else {
				trace.filter[0] = 1.0;
				trace.filter[1] = 1.0;
				trace.filter[2] = 1.0;
			}

			// nudge the point so that it is clearly forward of the light
			// so that surfaces meeting a light emiter don't get black edges
			if ( d > -8 && d < 8 ) {
				VectorMA( origin, (8-d), light->normal, pushedOrigin );	
			} else {
				VectorCopy( origin, pushedOrigin );
			}

			// calculate the contribution
			factor = PointToPolygonFormFactor( pushedOrigin, normal, light->w );
			if ( factor <= 0 ) {
				if ( light->twosided ) {
					factor = -factor;
				} else {
					continue;
				}
			}
			color[0] += factor * light->emitColor[0] * trace.filter[0];
			color[1] += factor * light->emitColor[1] * trace.filter[1];
			color[2] += factor * light->emitColor[2] * trace.filter[2];

			continue;
		}

		// calculate the amount of light at this sample
		if ( light->type == emit_point ) {
			VectorSubtract( light->origin, origin, dir );
			dist = VectorNormalize( dir, dir );
			// clamp the distance to prevent super hot spots
			if ( dist < 16 ) {
				dist = 16;
			}
			angle = DotProduct( normal, dir );
			if ( light->linearLight ) {
				add = angle * light->photons * linearScale - dist;
				if ( add < 0 ) {
					add = 0;
				}
			} else {
				add = light->photons / ( dist * dist ) * angle;
			}
		} else if ( light->type == emit_spotlight ) {
			float	distByNormal;
			vec3_t	pointAtDist;
			float	radiusAtDist;
			float	sampleRadius;
			vec3_t	distToSample;
			float	coneScale;

			VectorSubtract( light->origin, origin, dir );

			distByNormal = -DotProduct( dir, light->normal );
			if ( distByNormal < 0 ) {
				continue;
			}
			VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
			radiusAtDist = light->radiusByDist * distByNormal;

			VectorSubtract( origin, pointAtDist, distToSample );
			sampleRadius = VectorLength( distToSample );

			if ( sampleRadius >= radiusAtDist ) {
				continue;		// outside the cone
			}
			if ( sampleRadius <= radiusAtDist - 32 ) {
				coneScale = 1.0;	// fully inside
			} else {
				coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
			}
			
			dist = VectorNormalize( dir, dir );
			// clamp the distance to prevent super hot spots
			if ( dist < 16 ) {
				dist = 16;
			}
			angle = DotProduct( normal, dir );
			add = light->photons / ( dist * dist ) * angle * coneScale;

		} else if ( light->type == emit_area ) {
			VectorSubtract( light->origin, origin, dir );
			dist = VectorNormalize( dir, dir );
			// clamp the distance to prevent super hot spots
			if ( dist < 16 ) {
				dist = 16;
			}
			angle = DotProduct( normal, dir );
			if ( angle <= 0 ) {
				continue;
			}
			angle *= -DotProduct( light->normal, dir );
			if ( angle <= 0 ) {
				continue;
			}

			if ( light->linearLight ) {
				add = angle * light->photons * linearScale - dist;
				if ( add < 0 ) {
					add = 0;
				}
			} else {
				add = light->photons / ( dist * dist ) * angle;
			}
		}

		if ( add <= 1.0 ) {
			continue;
		}

		// clip the line, tracing from the surface towards the light
		if ( !notrace && testOcclusion ) {
			TraceLine( origin, light->origin, &trace, qfalse, tw );

			// other light rays must not hit anything
			if ( trace.passSolid ) {
				continue;
			}
		} else {
			trace.filter[0] = 1;
			trace.filter[1] = 1;
			trace.filter[2] = 1;
		}
		
		// add the result
		color[0] += add * light->color[0] * trace.filter[0];
		color[1] += add * light->color[1] * trace.filter[1];
		color[2] += add * light->color[2] * trace.filter[2];
	}

	//
	// trace directly to the sun
	//
	if ( testOcclusion || forceSunLight ) {
		SunToPlane( origin, normal, color, tw );
	}
}

/*
=============
PrintOccluded

For debugging
=============
*/
void PrintOccluded( byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE], 
				   int width, int height ) {
	int	i, j;

	_printf( "\n" );

	for ( i = 0 ; i < height ; i++ ) {
		for ( j = 0 ; j < width ; j++ ) {
			_printf("%i", (int)occluded[j][i] );
		}
		_printf( "\n" );
	}
}


/*
=============
VertexLighting

Vertex lighting will completely ignore occlusion, because
shadows would not be resolvable anyway.
=============
*/
void VertexLighting( dsurface_t *ds, qboolean testOcclusion, qboolean forceSunLight, float scale, traceWork_t *tw ) {
	int			i, j;
	drawVert_t	*dv;
	vec3_t		sample, normal;
	float		max;

	VectorCopy( ds->lightmapVecs[2], normal );

	// generate vertex lighting
	for ( i = 0 ; i < ds->numVerts ; i++ ) {
		dv = &drawVerts[ ds->firstVert + i ];

		if ( ds->patchWidth ) {
			LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
		}
		else if (ds->surfaceType == MST_TRIANGLE_SOUP) {
			LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
		}
		else {
			LightingAtSample( dv->xyz, normal, sample, testOcclusion, forceSunLight, tw );
		}

		if (scale >= 0)
			VectorScale(sample, scale, 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 ) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -