📄 tr_sky.c
字号:
sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
//
// iterate through the subdivisions
//
for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
i,
s_skyTexCoords[t][s],
s_skyPoints[t][s] );
}
}
DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
sky_mins_subd,
sky_maxs_subd );
}
}
static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes )
{
int s, t;
int vertexStart = tess.numVertexes;
int tHeight, sWidth;
tHeight = maxs[1] - mins[1] + 1;
sWidth = maxs[0] - mins[0] + 1;
for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
tess.numVertexes++;
if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
{
ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()\n" );
}
}
}
// only add indexes for one pass, otherwise it would draw multiple times for each pass
if ( addIndexes ) {
for ( t = 0; t < tHeight-1; t++ )
{
for ( s = 0; s < sWidth-1; s++ )
{
tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
tess.numIndexes++;
tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
tess.numIndexes++;
}
}
}
}
static void FillCloudBox( const shader_t *shader, int stage )
{
int i;
for ( i =0; i < 6; i++ )
{
int sky_mins_subd[2], sky_maxs_subd[2];
int s, t;
float MIN_T;
if ( 1 ) // FIXME? shader->sky.fullClouds )
{
MIN_T = -HALF_SKY_SUBDIVISIONS;
// still don't want to draw the bottom, even if fullClouds
if ( i == 5 )
continue;
}
else
{
switch( i )
{
case 0:
case 1:
case 2:
case 3:
MIN_T = -1;
break;
case 5:
// don't draw clouds beneath you
continue;
case 4: // top
default:
MIN_T = -HALF_SKY_SUBDIVISIONS;
break;
}
}
sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
( sky_mins[1][i] >= sky_maxs[1][i] ) )
{
continue;
}
sky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS );
sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS );
sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS );
sky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS );
if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_mins_subd[1] < MIN_T )
sky_mins_subd[1] = MIN_T;
else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
if ( sky_maxs_subd[1] < MIN_T )
sky_maxs_subd[1] = MIN_T;
else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
//
// iterate through the subdivisions
//
for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
{
for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
{
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
i,
NULL,
s_skyPoints[t][s] );
s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
}
}
// only add indexes for first stage
FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
}
}
/*
** R_BuildCloudData
*/
void R_BuildCloudData( shaderCommands_t *input )
{
int i;
shader_t *shader;
shader = input->shader;
assert( shader->isSky );
sky_min = 1.0 / 256.0f; // FIXME: not correct?
sky_max = 255.0 / 256.0f;
// set up for drawing
tess.numIndexes = 0;
tess.numVertexes = 0;
if ( input->shader->sky.cloudHeight )
{
for ( i = 0; i < MAX_SHADER_STAGES; i++ )
{
if ( !tess.xstages[i] ) {
break;
}
FillCloudBox( input->shader, i );
}
}
}
/*
** R_InitSkyTexCoords
** Called when a sky shader is parsed
*/
#define SQR( a ) ((a)*(a))
void R_InitSkyTexCoords( float heightCloud )
{
int i, s, t;
float radiusWorld = 4096;
float p;
float sRad, tRad;
vec3_t skyVec;
vec3_t v;
// init zfar so MakeSkyVec works even though
// a world hasn't been bounded
backEnd.viewParms.zFar = 1024;
for ( i = 0; i < 6; i++ )
{
for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
{
for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
{
// compute vector from view origin to sky side integral point
MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
i,
NULL,
skyVec );
// compute parametric value 'p' that intersects with cloud layer
p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
( -2 * skyVec[2] * radiusWorld +
2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
SQR( skyVec[0] ) * SQR( heightCloud ) +
2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
SQR( skyVec[1] ) * SQR( heightCloud ) +
2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
SQR( skyVec[2] ) * SQR( heightCloud ) ) );
s_cloudTexP[i][t][s] = p;
// compute intersection point based on p
VectorScale( skyVec, p, v );
v[2] += radiusWorld;
// compute vector from world origin to intersection point 'v'
VectorNormalize( v );
sRad = Q_acos( v[0] );
tRad = Q_acos( v[1] );
s_cloudTexCoords[i][t][s][0] = sRad;
s_cloudTexCoords[i][t][s][1] = tRad;
}
}
}
}
//======================================================================================
/*
** RB_DrawSun
*/
void RB_DrawSun( void ) {
float size;
float dist;
vec3_t origin, vec1, vec2;
vec3_t temp;
if ( !backEnd.skyRenderedThisView ) {
return;
}
if ( !r_drawSun->integer ) {
return;
}
qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
size = dist * 0.4;
VectorScale( tr.sunDirection, dist, origin );
PerpendicularVector( vec1, tr.sunDirection );
CrossProduct( tr.sunDirection, vec1, vec2 );
VectorScale( vec1, size, vec1 );
VectorScale( vec2, size, vec2 );
// farthest depth range
qglDepthRange( 1.0, 1.0 );
// FIXME: use quad stamp
RB_BeginSurface( tr.sunShader, tess.fogNum );
VectorCopy( origin, temp );
VectorSubtract( temp, vec1, temp );
VectorSubtract( temp, vec2, temp );
VectorCopy( temp, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255;
tess.vertexColors[tess.numVertexes][1] = 255;
tess.vertexColors[tess.numVertexes][2] = 255;
tess.numVertexes++;
VectorCopy( origin, temp );
VectorAdd( temp, vec1, temp );
VectorSubtract( temp, vec2, temp );
VectorCopy( temp, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 0;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255;
tess.vertexColors[tess.numVertexes][1] = 255;
tess.vertexColors[tess.numVertexes][2] = 255;
tess.numVertexes++;
VectorCopy( origin, temp );
VectorAdd( temp, vec1, temp );
VectorAdd( temp, vec2, temp );
VectorCopy( temp, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 1;
tess.vertexColors[tess.numVertexes][0] = 255;
tess.vertexColors[tess.numVertexes][1] = 255;
tess.vertexColors[tess.numVertexes][2] = 255;
tess.numVertexes++;
VectorCopy( origin, temp );
VectorSubtract( temp, vec1, temp );
VectorAdd( temp, vec2, temp );
VectorCopy( temp, tess.xyz[tess.numVertexes] );
tess.texCoords[tess.numVertexes][0][0] = 1;
tess.texCoords[tess.numVertexes][0][1] = 0;
tess.vertexColors[tess.numVertexes][0] = 255;
tess.vertexColors[tess.numVertexes][1] = 255;
tess.vertexColors[tess.numVertexes][2] = 255;
tess.numVertexes++;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 1;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 0;
tess.indexes[tess.numIndexes++] = 2;
tess.indexes[tess.numIndexes++] = 3;
RB_EndSurface();
// back to normal depth range
qglDepthRange( 0.0, 1.0 );
}
/*
================
RB_StageIteratorSky
All of the visible sky triangles are in tess
Other things could be stuck in here, like birds in the sky, etc
================
*/
void RB_StageIteratorSky( void ) {
if ( r_fastsky->integer ) {
return;
}
// go through all the polygons and project them onto
// the sky box to see which blocks on each side need
// to be drawn
RB_ClipSkyPolygons( &tess );
// r_showsky will let all the sky blocks be drawn in
// front of everything to allow developers to see how
// much sky is getting sucked in
if ( r_showsky->integer ) {
qglDepthRange( 0.0, 0.0 );
} else {
qglDepthRange( 1.0, 1.0 );
}
// draw the outer skybox
if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
qglPushMatrix ();
GL_State( 0 );
qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
DrawSkyBox( tess.shader );
qglPopMatrix();
}
// generate the vertexes for all the clouds, which will be drawn
// by the generic shader routine
R_BuildCloudData( &tess );
RB_StageIteratorGeneric();
// draw the inner skybox
// back to normal depth range
qglDepthRange( 0.0, 1.0 );
// note that sky was drawn so we will draw a sun later
backEnd.skyRenderedThisView = qtrue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -