好久没进行了,看看吧,与DEMO7-2的区别,只看不同的地方,相机类型不同,归一化平面改为2*2/ar,视口为640*480,执行了背面消除,(就是判断面元向量与面元到视点向量的点乘,>0,则可见,否则,消除)
这一步是在物体剔除后和世界坐标到相机坐标变换之前进行背面消除,
先建立4D向量,两点确定一个向量,SO EASY如下。
void ddraw_math::VECTOR4D_Build( VECTOR4D_PTR init, VECTOR4D_PTR term, VECTOR4D_PTR result )
{
result->x = term->x -init->x;
result->y = term->y - init->y;
result->z = term->z - init->z;
result->w = 1;
}
再做个准备工作,4元数之间的叉乘
void ddraw_math::VECTOR4D_CROSS( VECTOR4D_PTR va, VECTOR4D_PTR vb, VECTOR4D_PTR vn )
{
vn->x = (( va->y * vb->z) - ( va->z * vb->y));
vn->y = - ( ( va->x * vb->z) - ( va->z * vb->x ));
vn->z = ( ( va->x * vb->y ) - ( va->y * vb->x));
vn->w = 1;
}
四元数之间的点乘
float ddraw_math::VECTOR4D_DOT( VECTOR4D_PTR va, VECTOR4D_PTR vb )
{
return ( ( va->x * vb->x ) + ( va->y * vb->y ) + ( va->z + vb->z ) );
}
背面消除函数如下
void ddraw_liushuixian::Remove_Backfaces_OBJECT4DV1(OBJECT4DV1_PTR obj, CAM4DV1_PTR cam, ddraw_math math)
{
//检查物体是否已经被剔除
//在执行物体提出之后和世界坐标到相机坐标变换之前进行背面消除
if ( obj->state & OBJECT4DV1_STATE_CULLED )
{
return;
}
//处理物体的每个多边形
for( int poly = 0; poly < obj->num_polys; poly ++ )
{
//获取多边形
POLY4DV1_PTR curr_poly = & obj->plist[poly];
//该多边形是否有效?
//判断该多边形是否没被裁剪掉,没有被剔除,处于活动状态,可见且不是双面的
if ( ! ( curr_poly->state & POLY4DV1_STATE_ACTIVE ) ||
( curr_poly->state & POLY4DV1_STATE_CLIPPED) ||
( curr_poly->state & POLY4DV1_ATTR_2SIDED) ||
( curr_poly->state & POLY4DV1_STATE_BACKFACE))
{
continue;
}
//获取顶点列表中的顶点索引
int vindex_0 = curr_poly->vert[0];
int vindex_1 = curr_poly->vert[1];
int vindex_2 = curr_poly->vert[2];
//计算多边形的面法线,
//顶点是按照顺时针方向排列的,u=p0->p1,v=p0->p2,n=UXV;
VECTOR4D u, v, n;
//计算u和v
math.VECTOR4D_Build( & obj->vlist_trans[vindex_0], & obj->vlist_trans[vindex_1], & u );
math.VECTOR4D_Build( & obj->vlist_trans[vindex_0], & obj->vlist_trans[vindex_2], & v );
//计算叉积
math.VECTOR4D_CROSS( & u, &v, &n );
//创建指向视点的向量
VECTOR4D view;
math.VECTOR4D_Build( & obj->vlist_trans[vindex_0], & cam->pos, & view );
//计算点积
float dp = math.VECTOR4D_DOT( &n, &view );
if ( dp<= 0)
{
SET_BIT( curr_poly->state, POLY4DV1_STATE_BACKFACE );
}
}
}
现在看看在主函数中怎么改动,首先,在GAME_INIT()中,加载cube2.plg,
WINDOW_HEIGHT);
//加载模型
liushuixian.Load_OBJECT4DV1_PLG( & obj, "cube2.plg", & vscale, & vpos, & vrot );
在Game_Main()中加上背面消除
。。。。。。
liushuixian.Build_CAM4DV1_Matrix_Euler( *math, & cam, CAM_ROT_SEQ_ZYX );
//Build_CAM4DV1_Matrix_Euler( & cam, CAM_ROT_SEQ_ZYX );
liushuixian.Remove_Backfaces_OBJECT4DV1( & obj, &cam, * math );
liushuixian.World_To_Camera_OBJECT4DV1( *math, &obj, & cam );
。。。。。。
如下图所示
说明背面消除没有起作用,将
if ( dp>0 )
{
SET_BIT( curr_poly->state, POLY4DV1_STATE_BACKFACE );
}
发现也是整个显示,说明没起作用。
输出到文件的方法
void Remove_Backfaces_OBJECT4DV1(OBJECT4DV1_PTR obj, CAM4DV1_PTR cam)
{
FILE * fp = fopen( "test.txt", "w");
fprintf( fp, "removebackface函数起效果了\n" );
;
//检查物体是否已经被剔除
//在执行物体提出之后和世界坐标到相机坐标变换之前进行背面消除
if ( obj->state & OBJECT4DV1_STATE_CULLED )
{
return;
}
fprintf(fp, "有不是OBJECT4DV1_STATE_CULLED的点\n");
//处理物体的每个多边形
for( int poly = 0; poly < obj->num_polys; poly ++ )
{
//获取多边形
POLY4DV1_PTR curr_poly = & obj->plist[poly];
//该多边形是否有效?
//判断该多边形是否没被裁剪掉,没有被剔除,处于活动状态,可见且不是双面的
if ( ! ( curr_poly->state & POLY4DV1_STATE_ACTIVE ) ||
( curr_poly->state & POLY4DV1_STATE_CLIPPED) ||
( curr_poly->state & POLY4DV1_ATTR_2SIDED) ||
( curr_poly->state & POLY4DV1_STATE_BACKFACE))
{
fprintf(fp, "第%d个顶点没经过计算\n",poly);
continue;
}
fprintf(fp, "有进行计算的点\n");
//获取顶点列表中的顶点索引
int vindex_0 = curr_poly->vert[0];
int vindex_1 = curr_poly->vert[1];
int vindex_2 = curr_poly->vert[2];
//计算多边形的面法线,
//顶点是按照顺时针方向排列的,u=p0->p1,v=p0->p2,n=UXV;
VECTOR4D u, v, n;
//计算u和v
VECTOR4D_Build( & obj->vlist_trans[vindex_0], & obj->vlist_trans[vindex_1], & u );
VECTOR4D_Build( & obj->vlist_trans[vindex_0], & obj->vlist_trans[vindex_2], & v );
//计算叉积
VECTOR4D_Cross( & u, &v, &n );
//创建指向视点的向量
VECTOR4D view;
VECTOR4D_Build( & obj->vlist_trans[vindex_0], & cam->pos, & view );
//计算点积
float dp =VECTOR4D_Dot( &n, &view );
if ( dp<0 )
{
SET_BIT( curr_poly->state, POLY4DV1_STATE_BACKFACE );
}
; fprintf(fp, "第%d个面法线与视线点积为%f", poly, dp );
}
fclose( fp);
}
发现test.txt的显示内容是
removebackface函数起效果了
有不是OBJECT4DV1_STATE_CULLED的点
第0个顶点没经过计算,共12个顶点
第1个顶点没经过计算,共12个顶点
第2个顶点没经过计算,共12个顶点
第3个顶点没经过计算,共12个顶点
第4个顶点没经过计算,共12个顶点
第5个顶点没经过计算,共12个顶点
第6个顶点没经过计算,共12个顶点
第7个顶点没经过计算,共12个顶点
第8个顶点没经过计算,共12个顶点
第9个顶点没经过计算,共12个顶点
第10个顶点没经过计算,共12个顶点
第11个顶点没经过计算,共12个顶点
说明全continue了,再往前看状态。
结果发现太马虎了,应该是
curr_poly->attr & POLY4DV1_ATTR_2SIDED
而不是
curr_poly->state & POLY4DV1_ATTR_2SIDED
另外点乘最后一项应该是×而不是+,即原来是
float ddraw_math::VECTOR4D_DOT( VECTOR4D_PTR va, VECTOR4D_PTR vb )
{
return ( ( va->x * vb->x ) + ( va->y * vb->y ) + ( va->z + vb->z ) );
}
应改为
float ddraw_math::VECTOR4D_DOT( VECTOR4D_PTR va, VECTOR4D_PTR vb )
{
return ( ( va->x * vb->x ) + ( va->y * vb->y ) + ( va->z * vb->z ) );
}
修正后结果如下所示,OK了