简单的Viewing Frustum Culling
Viewing Frustum Culling是图形绘制流水线中,将不可见物体(即不在视锥体内的物体)提前剔除的操作。
在实践中,精确判断物体的可见性开销较大,因而通常用物体包围球或包围盒与视锥体(平截头体,View frustum)做相交测试,以此粗略判断物体是否可见。
进一步地,我们可以采用如下方式来大致判断一个球体与视锥体是否相交:
球与视锥体相交的必要(非充分)条件是:其中心P与视锥体的6个面的符号距离(Signed distance)d均小于球的半径R。注意对于一个平面aX + bY+ cZ + d = 0 ([a, b, c]为平面法线方向N,d为平面与原点的符号距离), 一个点P(x, y, z)与该平面的符号距离为ax + by + cz + d。因此要粗略判断物体与视锥体是否相交,只需要将其包围球与视锥体的6个面分别计算符号距离即可,如果其与任一面的符号距离大于R,则可安全剔除。
那么如何算得视锥体每个面的面方程呢?一个比较通用的方法是求出视锥体的8个顶点,然后分别利用叉积和点积求出6个面的法线和原点距。 但如果我们已经知道投影矩阵,也可以用如下更简单的方法算得面方程:(以Direct3D为例,OpenGL与之相似,但需要注意的是其规范化设备坐标系的Z取值范围为[-1,1]而非[0,1])
对于一个场景,设物体空间中有一球体,中心坐标为P,半径为R,由某一视锥体定义的物体空间到规范化设备空间的变换矩阵为M= World *View *Projection。现需要求该视锥体各个面在物体空间中的面方程。回顾规范化设备坐标系的定义,我们可以很容易得知,M的效果可以看做是将视锥体的6个面分别变换到X=1, X=-1, Y=1, Y=-1, Z=0, Z=1这6个面上。例如,视锥体的近剪裁面经过M,会变换到Z=0平面上,远剪裁面变换到Z=1平面上,其他4个面也是类似变换。那么,对于位于视锥体近剪裁面上的任一一点P(x, y, z, 1),P' =P*M应该满足P'.z / P'.w = 0, 即P'.z = 0,展开P*M可得:x*M._13 + y*M._23 + z*M._33 + M._43=0。这正是近剪裁面在物体空间中的平面方程。
同理,对于远剪裁面有P'.z / P'.w = 1,展开P*M有x*(M._13-M._14) + y**(M._23-M._24)+ z*(M._33-M._34)+(M._43-M._44)=0,为远剪裁面在物体空间中的平面方程。
同理可得很容易求得其他4个面的面方程。
如下示例了使用DirectXMath的求面方程以及相交测试的完整代码:
// mWVP is the Word-View-Projection Matrix XMFLOAT4 plane[6];
// x=1
plane[0].x = mWVP._11 - mWVP._14;
plane[0].y = mWVP._21 - mWVP._24;
plane[0].z = mWVP._31 - mWVP._34;
plane[0].w = mWVP._41 - mWVP._44;
// x=-1
plane[1].x = -mWVP._14 - mWVP._11;
plane[1].y = -mWVP._24 - mWVP._21;
plane[1].z = -mWVP._34 - mWVP._31;
plane[1].w = -mWVP._44 - mWVP._41;
// y=1
plane[2].x = mWVP._12 - mWVP._14;
plane[2].y = mWVP._22 - mWVP._24;
plane[2].z = mWVP._32 - mWVP._34;
plane[2].w = mWVP._42 - mWVP._44;
// y=-1
plane[3].x = -mWVP._14 - mWVP._12;
plane[3].y = -mWVP._24 - mWVP._22;
plane[3].z = -mWVP._34 - mWVP._32;
plane[3].w = -mWVP._44 - mWVP._42;
// z=1
plane[4].x = mWVP._13 - mWVP._14;
plane[4].y = mWVP._23 - mWVP._24;
plane[4].z = mWVP._33 - mWVP._34;
plane[4].w = mWVP._43 - mWVP._44;
// z=0
plane[5].x = -mWVP._13;
plane[5].y = -mWVP._23;
plane[5].z = -mWVP._33;
plane[5].w = -mWVP._43;
XMVECTOR xmPlane[6];
// load and normalize
for( UINT i=0; i<6; i++ )
{
xmPlane[i] = XMLoadFloat4( &plane[i] );
xmPlane[i] = XMPlaneNormalize( xmPlane[i] );
}
// cull
for( UINT s=0; s<objects.size(); s++ ) // traverse all objects
{
bool bInFrustum = true;
XMVECTOR xmCenter = XMLoadFloat3( &objects[s].bSphere.center ); // bounding sphere
float radius = objects[s].bSphere.radius;
for( UINT i=0; i<6; i++ )
{
XMVECTOR xmD = XMPlaneDotCoord( xmPlane[i], xmCenter );
float d;
XMStoreFloat( &d, xmD );
if( d > radius )
{
bInFrustum = false;
break;
}
}
objects[s].isInFrustum = bInFrustum;
}
补充1:需要注意的是,透视投影的视锥体并非立方体,因此存在满足前述判断条件且与视锥体不相交的球体,但这种情况并不多见,故不做进一步判断)
补充2:另外请注意上述代码中面方程的符号。(例如plane[4]=[ -mWVP._13, -mWVP._23, -mWVP._33, -mWVP._43]定义了法线方向指向视锥体外的平面,而如果写作[ mWVP._13, mWVP._23, mWVP._33, mWVP._43],则定义的是法线方向指向视锥体内的平面,此时需要将判断条件更改为“若d<-R,则剔除”。)
简单的Viewing Frustum Culling的更多相关文章
- 【翻译】View Frustum Culling --3 Clip Space Approach – Extracting the Planes
3.使用裁剪空间的方法提取平面 上一篇中,我们讨论了通过几何的方法提取视锥体的六个片面.在这一篇中,我们继续讨论通过裁剪空间的方法来提取视锥体的平面. 假设现在在世界坐标系中有一点p=(x,yz,1) ...
- 【翻译】View Frustum Culling --2 Geometric Approach – Extracting the Planes
在上一篇中,我们知道了视锥体的形状,并且也确定了我们进行裁剪时的步骤.那我们接下来要走的就是确定视锥体的六个平面: near, far, top, bottom, left and right 2.计 ...
- 【翻译】 View Frustum Culling --1 View Frustum’s Shape
这是一些列来自lighthouse3d的视锥体裁剪教程.旨在学习总结,及便于查阅. 1.视锥体的形状 在OpenGL中,透视投影是由两个函数定义的gluPerspective和gluLookAt.我们 ...
- Forward+ Rendering Framework
近几天啃各种新技术时又一个蛋疼的副产品...额,算是把AMD的Forward+ Sample抄了一遍吧. 其实个人感觉这个AMD大肆宣传的Forward+跟Intel很早之前提的Tiled-Based ...
- Occlusion Culling遮挡剔除理解设置和地形优化应用
这里使用的是unity5.5版本 具体解释网上都有,就不多说了,这里主要说明怎么使用,以及参数设置和实际注意点 在大场景地形的优化上,但也不是随便烘焙就能降低帧率的,必须结合实际情况来考虑,当然还有透 ...
- 转:关于 OGRE 与 OSG 的简单比较
1 前言 我曾经细致阅读过 OGRE 和 OSG 官方提供的文档,有<Pro OGRE 3D Programming>.OGRE自带手册(manual).王锐老师等翻译的<Ope ...
- 视锥体(frustum)裁剪
原文地址:http://www.linuxgraphics.cn/graphics/opengl_view_frustum_culling.html 背景 视锥体(frustum),是指场景中摄像机的 ...
- 关于OGRE与OSG的简单比较【转】
关于OGRE与OSG的简单比较 林乃养 lnychina{at}gmail.com 浙江大学CAD&CG实验室 2010年3月27日 1 前言 我曾经细致阅读过OGRE和OSG官方提供的文档, ...
- 关于 OGRE 与 OSG 的简单比较 (转)
关于 OGRE 与 OSG 的简单比较 1 前言 我曾经细致阅读过 OGRE 和 OSG 官方提供的文档,有<Pro OGRE 3D Programming>.OGRE自带手册(man ...
随机推荐
- GJM : 各大开发游戏引擎
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- Sharepoint学习笔记—习题系列--70-576习题解析 -(Q112-Q115)
Question 112 You are designing a public-facing SharePoint 2010 Web site for an elementary school th ...
- elasticsearch GIS空间查询问题解决
在GIS行业的应用越来越广泛,GIS最常用根据区域进行空间数据查询 我定义了两个方法,一起来看一下: /** * geodistance filter * 一个过滤器来过滤基于一个特定的距离从 ...
- tableview左滑按钮 tableviewcell自定义左滑按钮
当我们在使用tableview时,往往需要在cell左滑时显示一个或是多个按钮,但系统默认的只可显示一个,如常见的删除按钮,那么当我们的需求要求要有多个按钮时又该怎么办呢,我们往下看. 首先,现看看系 ...
- 初学HTML 表单交互标签
表单标签在网站中主要负责的是进行与用户间的交互, 如果没有了交互, 那么网站就只是一个展示, 会死气沉沉的. <form>表单标签 <form>表单标签可以把浏览者(也就是我们 ...
- Object-C关于GCD多线程的使用
```objc1 使用Crearte函数创建的并发队列和全局并发队列的主要区别: 1)全局并发队列在整个应用程序中本身是默认存在的并且对应有高优先级.默认优先级.低优先级和后台优先级一共四个并发队列, ...
- php 日期计算 总结
1 加 2天 date("Y-m-d", strtotime("$today + 2 days")); date("Y-m-d", strt ...
- Watir-WebDriver关于交互式等待方法,告别一味sleep时代
有交互就有等待,等待页面加载完毕的时间怎么处理呢? 有人说sleep: sleep N #等待N秒后继续执行 怎么才能告别毫无意义的命令呢? 接下来介绍一下Watir-Webdriver为我们提供等待 ...
- 错误解决:error while loading shared libraries: libcurl.so.4: cannot open shared object file: No such file or directory
执行以下代码,生成唯一的UID $fp = popen("/xxx/bin/tools/uuidgen system", "r");// $uid = frea ...
- rails程序文件名命名规范
1 一般文件名是用小写单词加下划线分割,但类的名字用骆驼法.例如 sessions_controller.rb中定义SessionsController. 2 helpers内的文件为辅助类,定义了许 ...