/*
简单介绍一下物体剔除的原理:
1 , 计算物体中心点坐标
2 , 以物体中心点作为球体圆点, max_radius为半径。
3 , 对于Z轴来说,需要比较球体是否在远截面和近截面内部
4 , 对于X轴来说, 首先需要在透视明面上计算x的边界值
公式如下 : float x_test = 0.5f * lpCamera3D->viewplant_width * sphere_pos.z / lpCamera3D->view_dist_h
那么为什么之后还要进行x_test += (lpObject3D->max_radius); 请看下图
(槽图 +槽字,有时间会提高图片质量,见谅啦 :))
由于在程序中一般默认的相机视野角是90度,那么当物体进行横向偏移的时候,物体侧面会出现在视野内, 那么这个侧面出现的视野X长度是多少呢?由上图可见, 最大值就是max_radius的值
所以为了保证当物体正好移除视野时,程序就能捕捉到,而不会浪费循环去绘制已经不再视野范围内的物体,则需要将x_test + max_radius
对于y 道理是一样的。唯一需要提及的是,由于有的程序他的屏幕宽高比并不是1:1,那么这个时候,他侧面所出现的长度就不会是max_radius, 而是max_dius * (1/lpCamera3D->ratio)
用这种方式计算 x, y轴边界物体剔除问题,效果不错, 笔者测试了一下, 当物体刚刚移出视野,则程序就会捕捉到,而不会浪费系统循环区绘制已经不在视野内的物体。
*/
由于在程序中一般默认的相机视野角是90度,那么当物体进行横向偏移的时候,物体侧面会出现在视野内, 那么这个侧面出现的视野X长度是多少呢?由上图可见, 最大值就是max_radius的值
所以为了保证当物体正好移除视野时,程序就能捕捉到,而不会浪费循环去绘制已经不再视野范围内的物体,则需要将x_test + max_radius
对于y 道理是一样的。唯一需要提及的是,由于有的程序他的屏幕宽高比并不是1:1,那么这个时候,他侧面所出现的长度就不会是max_radius, 而是max_dius * (1/lpCamera3D->ratio)
用这种方式计算 x, y轴边界物体剔除问题,效果不错, 笔者测试了一下, 当物体刚刚移出视野,则程序就会捕捉到,而不会浪费系统循环区绘制已经不在视野内的物体。
*/
int C3DENGINE :: Cull_Object ( __LPOBJECT3D lpObject3D , __LPCAMERA3D lpCamera3D)
{
if(NULL == lpObject3D)
{
CLOG_MARKER("error" , "C3DENGINE
:: Cull_Object");
CLOG_GETOBJECT("error" )->write( "ERROR:
illegal [in]parameter -> lpObject3D is NULL!");
exit(-1);
}
__POINT3DF sphere_pos ;
/*
lpObject3D->world_pos 物体世界坐标
lpCamera3D->mcam 相机旋转平移矩阵
sphere_pos, 物体中心点坐标
*/
Mult_VM3D(sphere_pos, lpObject3D-> world_pos, lpCamera3D ->mcam);
/*
lpCamera3D->far_clip 相机远截面
lpCamera3D->near_clip 相机近截面
lpObject3D->max_radius 以sphere_pos为中心点的球体半径
*/
if(sphere_pos.z
- lpObject3D->max_radius > lpCamera3D->far_clip ||
sphere_pos. z +
lpObject3D->max_radius < lpCamera3D->near_clip)
{
lpObject3D-> bCulled = TRUE ;
//write
error log
return _CULL_MODE_Z ;
}
float x_test
= 0.5f * lpCamera3D->viewplant_width * sphere_pos.z
/ lpCamera3D->view_dis_h;
x_test +=
(lpObject3D ->max_radius);
if(sphere_pos.x - lpObject3D->max_radius
> x_test ||
sphere_pos.x
+ lpObject3D->max_radius < -x_test )
{
lpObject3D->bCulled = TRUE;
//write
error log
return _CULL_MODE_X ;
}
float y_test
= 0.5f * lpCamera3D->viewplant_height * sphere_pos.z
/ lpCamera3D->view_dis_h;
y_test +=
((lpObject3D ->max_radius)*(1/lpCamera3D-> ratio));
if(sphere_pos .y
-lpObject3D->max_radius > y_test
||
sphere_pos.y
+ lpObject3D->max_radius < -y_test)
{
lpObject3D->bCulled = TRUE;
//write
error log
return _CULL_MODE_Y ;
}
return _CULL_MODE_NONE ;
}