/*
简单介绍一下物体剔除的原理:
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
;
}