概括说,就是先绘制离视点远的物体,再绘制离视点近的物体,这样离视点较近的物体将自动覆盖背景。
可以根据渲染列表中的每个多边形的Z值,从后到前的顺序排列
对于多边形较小,且不是凹的,不互相重叠,是可行的。
排序是根据相机坐标进行,所以要在世界坐标系到相机坐标变换之后和相机坐标到透视坐标之前进行。
定义几个常量用来排序渲染列表中的多边形
#define SORT_POLYLIST_AVGZ 0
#define SORT_POLYLIST_NEARZ 1
#define SORT_POLYLIST_FARZ 2
比较函数随之分三个,比较NEARZ,AVGZ和FARZ,用来当判断标准。
int ddraw_liushuixian::Compare_AvgZ_PolyF4DV1( const void * arg1, const void * arg2 )
{
float z1, z2;
POLYF4DV1_PTR poly_1, poly_2;
poly_1 = * ( ( POLYF4DV1_PTR * ) ( arg1 ));
poly_2 = * ( ( POLYF4DV1_PTR * ) ( arg2 ));
z1 = ( float ) 0.33333 * ( poly_1->tvlist[0].z + poly_1->tvlist[1].z + poly_1->tvlist[2].z );
z2 = ( float ) 0.33333 * ( poly_2->tvlist[0].z + poly_2->tvlist[1].z + poly_2->tvlist[2].z );
if ( z1 > z2 )
{
return -1;
}
else
if ( z1 < z2)
{
return 1;
}
else
{
return 0;
}
}
int ddraw_liushuixian::Compare_NearZ_PolyF4DV1( const void * arg1, const void * arg2 )
{
float z1, z2;
POLYF4DV1_PTR poly_1, poly_2;
poly_1 = * ( ( POLYF4DV1_PTR * ) ( arg1 ));
poly_2 = * ( ( POLYF4DV1_PTR * ) ( arg2 ));
z1 = MIN( poly_1->tvlist[0].z, poly_1->tvlist[1].z );
z1 = MIN( z1, poly_1->tvlist[2].z );
z2 = MIN( poly_2->tvlist[0].z, poly_2->tvlist[1].z );
z2 = MIN( z2, poly_2->tvlist[2].z );
if ( z1 > z2 )
{
return -1;
}
else
if ( z1 < z2)
{
return 1;
}
else
{
return 0;
}
}
int ddraw_liushuixian::Compare_FarZ_PolyF4DV1( const void * arg1, const void * arg2 )
{
float z1, z2;
POLYF4DV1_PTR poly_1, poly_2;
poly_1 = * ( ( POLYF4DV1_PTR * ) ( arg1 ));
poly_2 = * ( ( POLYF4DV1_PTR * ) ( arg2 ));
z1 = MAX( poly_1->tvlist[0].z, poly_1->tvlist[1].z );
z1 = MAX( z1, poly_1->tvlist[2].z );
z2 = MAX( poly_2->tvlist[0].z, poly_2->tvlist[1].z );
z2 = MAX( z2, poly_2->tvlist[2].z );
if ( z1 > z2 )
{
return -1;
}
else
if ( z1 < z2)
{
return 1;
}
else
{
return 0;
}
}
按照各种情况进行排序
int ddraw_liushuixian::Sort_RENDERLIST4DV1( RENDERLIST4DV1_PTR rend_list, int sort_method )
{
switch( sort_method )
{
case SORT_POLYLIST_AVGZ:
{
qsort( ( void *) rend_list->poly_ptrs, rend_list->num_polys, sizeof( POLYF4DV1_PTR ), Compare_AvgZ_PolyF4DV1 );
}
break;
case SORT_POLYLIST_NEARZ:
{
qsort( ( void *) rend_list->poly_ptrs, rend_list->num_polys, sizeof( POLYF4DV1_PTR ), Compare_NearZ_PolyF4DV1);
}
break;
case SORT_POLYLIST_FARZ:
{
qsort( ( void *) rend_list->poly_ptrs, rend_list->num_polys, sizeof( POLYF4DV1_PTR ), Compare_FarZ_PolyF4DV1 );
}
break;
default:
break;
}
}
下面,进行主程序看看,
在GAME_MAIN()的每帧中,设定一个Z排序模式,
static int zsort_mode = 1;
liushuixian.Insert_OBJECT4DV1_RENDERLIST4DV12( * math, & render_list, & obj_player, 0, 0 );
liushuixian.Insert_OBJECT4DV1_RENDERLIST4DV12( * math, & render_list, & obj_tank, 0, 0 );
liushuixian.Insert_OBJECT4DV1_RENDERLIST4DV12( * math, & render_list, & obj_tower,0,0 );
光照是在渲染列表中进行,
int ddraw_liushuixian::Light_RENDERLIST4DV1_World16( ddraw_math math, int rgb_format, RENDERLIST4DV1_PTR rend_list, CAM4DV1_PTR cam, LIGHTV1_PTR lights, int max_lights )
{
unsigned int r_base, g_base, b_base, //原来的颜色值
r_sum, g_sum, b_sum, //全部光源的总体光照效果
shaded_color; //最后的颜色
float dp, //点积
dist, //表面和光源之间的距离
i, //强度
nl, //法线长度
atten; //衰减计算结果
for ( int poly = 0; poly < rend_list->num_polys; poly ++)
{
POLYF4DV1_PTR curr_poly = rend_list->poly_ptrs[poly];
if ( ! ( curr_poly->state & OBJECT4DV1_STATE_ACTIVE ) ||
( curr_poly-> state & OBJECT4DV1_STATE_CULLED ) ||
! ( curr_poly->state & OBJECT4DV1_STATE_VISIBLE))
{
return ( 0 );
}
//检查多边形的着色模式
if ( curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_FLAT ||
curr_poly->attr & POLY4DV1_ATTR_SHADE_MODE_GOURAUD )
{
//提取多边形颜色的RGB值
if ( rgb_format == DD_PIXEL_FORMAT565 )
{
_RGB565FROM16BIT( curr_poly->color, & r_base, & g_base, & b_base );
//转换成.8.8格式
r_base <<= 3;
g_base <<= 2;
b_base <<= 3;
}
else
{
_RGB555FROM16BIT( curr_poly->color, & r_base, & g_base, & b_base );
//转换成.8.8格式
r_base <<= 3;
g_base <<= 3;
b_base <<= 3;
}
//初始化总体光照颜色
r_sum = 0;
g_sum = 0;
b_sum = 0;
//遍历光照
for ( int curr_light = 0; curr_light < max_lights; curr_light ++)
{
//光源是否被打开
if ( lights[curr_light].state== LIGHTV1_STATE_OFF)
{
continue;
}
//判断光源类型
if ( lights[curr_light].attr & LIGHTV1_ATTR_AMBIENT )
{
r_sum += ( ( lights[curr_light].c_ambient.r * r_base) / 256 );
g_sum += ( ( lights[curr_light].c_ambient.g * g_base) / 256 );
b_sum += ( ( lights[curr_light].c_ambient.b * b_base) / 256 );
}
else
if ( lights[curr_light].attr & LIGHTV1_ATTR_INFINITE )
{
VECTOR4D u, v, n;
math.VECTOR4D_Build( & curr_poly->tvlist[0], & curr_poly->tvlist[1], & u );
math.VECTOR4D_Build( & curr_poly->tvlist[0], & curr_poly->tvlist[1], & v );
math.VECTOR4D_CROSS( & u, &v, &n );
nl = math.VECTOR4D_length(&n);
dp = math.VECTOR4D_DOT( &n, & lights[curr_light].dir );
if ( dp > 0 )
{
i = 128 * dp / nl;
r_sum += ( lights[curr_light].c_diffuse.r * r_base * i ) / ( 256 * 128);
g_sum += ( lights[curr_light].c_diffuse.g * g_base * i ) / ( 256 * 128);
b_sum += ( lights[curr_light].c_diffuse.b * b_base * i ) / ( 256 * 128);
}
}
else
if ( lights[curr_light].attr & LIGHTV1_ATTR_POINT )
{
VECTOR4D u, v, n, l;
math.VECTOR4D_Build( & curr_poly->tvlist[0], & curr_poly->tvlist[1], & u );
math.VECTOR4D_Build( & curr_poly->tvlist[0], & curr_poly->tvlist[1], & v );
math.VECTOR4D_CROSS( & u, &v, &n );
nl = math.VECTOR4D_length(&n);
//计算从表面到光源的向量
math.VECTOR4D_Build( &curr_poly->tvlist[0], & lights[curr_light].pos, &l );
//计算距离和衰减
dist = math.VECTOR4D_length( &l);
dp = math.VECTOR4D_DOT( &n, & l);
if ( dp > 0 )
{
atten = ( lights[curr_light].kc + lights[curr_light].kl * dist + lights[curr_light].kq * dist * dist );
i = 128 * dp / ( nl * dist * atten );
r_sum += ( lights[curr_light].c_diffuse.r * r_base * i ) / ( 256 * 128);
g_sum += ( lights[curr_light].c_diffuse.g * g_base * i ) / ( 256 * 128);
b_sum += ( lights[curr_light].c_diffuse.b * b_base * i ) / ( 256 * 128);
}
}
else
if ( lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT1 )
{
VECTOR4D u, v, n, l;
math.VECTOR4D_Build( & curr_poly->tvlist[0], & curr_poly->tvlist[1], & u );
math.VECTOR4D_Build( & curr_poly->tvlist[0], & curr_poly->tvlist[1], & v );
math.VECTOR4D_CROSS( & u, &v, &n );
nl = math.VECTOR4D_length(&n);
//计算从表面到光源的向量
math.VECTOR4D_Build( &curr_poly->tvlist[0], & lights[curr_light].pos, &l );
//计算距离和衰减
dist = math.VECTOR4D_length( &l);
dp = math.VECTOR4D_DOT( &n, & lights[curr_light].dir );
if ( dp > 0 )
{
atten = ( lights[curr_light].kc + lights[curr_light].kl * dist + lights[curr_light].kq * dist * dist );
i = 128 * dp / ( nl * atten );
r_sum += ( lights[curr_light].c_diffuse.r * r_base * i ) / ( 256 * 128);
g_sum += ( lights[curr_light].c_diffuse.g * g_base * i ) / ( 256 * 128);
b_sum += ( lights[curr_light].c_diffuse.b * b_base * i ) / ( 256 * 128);
}
}
else
if ( lights[curr_light].attr & LIGHTV1_ATTR_SPOTLIGHT2 )
{
VECTOR4D u, v, n, d, s;
math.VECTOR4D_Build( & curr_poly->tvlist[0], & curr_poly->tvlist[1], & u );
math.VECTOR4D_Build( & curr_poly->tvlist[0], & curr_poly->tvlist[1], & v );
math.VECTOR4D_CROSS( & u, &v, &n );
nl = math.VECTOR4D_length(&n);
dp = math.VECTOR4D_DOT( &n, & lights[curr_light].dir );
if ( dp > 0 )
{
//计算从表面到光源的向量
math.VECTOR4D_Build( & lights[curr_light].pos, & curr_poly->tvlist[0], &s );
dist = math.VECTOR4D_length( &s);
float dpsl = math.VECTOR4D_DOT( & s, & lights[curr_light].dir ) / dist;
if ( dpsl > 0)
{
atten = ( lights[curr_light].kc + lights[curr_light].kl * dist + lights[curr_light].kq * dist * dist );
float dpsl_exp = dpsl;
for ( int e_index = 1; e_index < ( int ) lights[curr_light].pf; e_index++ )
{
dpsl *= dpsl;
}
i = 128 * dp * dpsl_exp / ( nl * atten );
r_sum += ( lights[curr_light].c_diffuse.r * r_base * i ) / ( 256 * 128);
g_sum += ( lights[curr_light].c_diffuse.g * g_base * i ) / ( 256 * 128);
b_sum += ( lights[curr_light].c_diffuse.b * b_base * i ) / ( 256 * 128);
}
}
}
}
//确保颜色分量不溢出
if ( r_sum > 255 )
{
r_sum = 255;
}
if ( g_sum > 255 )
{
g_sum = 255;
}
if ( b_sum > 255 )
{
b_sum = 255;
}
//写入颜色
if ( rgb_format == DD_PIXEL_FORMAT565 )
{
shaded_color = _RGB16BIT565( r_sum, g_sum, b_sum );
}
else
if ( rgb_format == DD_PIXEL_FORMAT555 )
{
shaded_color = _RGB16BIT555( r_sum, g_sum, b_sum );
}
curr_poly->color = ( int ) ( ( shaded_color << 16 ) | curr_poly->color );
}
else
{
// curr_poly->color = ( int ) ( ( curr_poly->color << 16 ) | curr_poly->color );
}
}
}
在GAME_Main()中光照处理列表
liushuixian.Light_RENDERLIST4DV1_World16( *math, DD_PIXEL_FORMAT565, &render_list, & cam, lightGroup, 4 );
然后进行Z排序,OK了。