cocos2d中的可见性检测
游戏的在进行一次渲染的时候,通常会提交大量的渲染对象给gpu。在这些需要渲染的对象中,并不是所有对象都会出现镜头中,即有一部分对象是不可见的。
通常有两种方式来完成不可见对象的剔除工作:
(1)直接交给图形库帮我剔除,即性能消耗在gpu端;
(2)在提交图元给gpu前,在游戏逻辑中进行剔除,即性能消耗在cpu端;
是将剔除操作放在cpu还是gpu来处理,没有一个具体的标准,个人认为,要根据实际情况,如果逻辑方面可以快速进行剔除,可以交由cpu来处理,但是gpu在这方面经过了优化,具有更快的处理能力,所以如果cpu端剔除操作过于复杂,可以交由gpu来处理。总之游戏开发中,cpu和gpu的性能都非常重要,所以应该在性能消耗方面尽量平衡,不应该让某一个端承担过多的任务。
opengl是剔除不可见的对象的过程:
一个最简单的模型,坐标点(x,y,z)-> 模型矩阵(modelMatrix)变换 -> 视图矩阵(viewMatrix)变换 -> 投影矩阵(projectMatrix)变换 -> 透视除法(除以齐次坐标中的w)-> 转换为齐次标准裁剪空间坐标 -> 在标准裁剪空间中进行裁剪,剔除不可见的图元
(1)首先在模型空间中定义坐标位置,模型坐标原点通常是(0,0,0),即世界坐标中心点,此时我们可以认为模型坐标系和世界坐标系是重合的,例如(2,2,2)表示相对模型坐标系原点的偏移位置,x正向偏移2,y正向偏移2,z正向偏移2,一个模型中的所有坐标点的变换都是相对于模型坐标系的原点进行设定的;
(2)然后通过视图矩阵将模型坐标系转换为世界坐标系,此时整个模型就显示在世界坐标系中了,例如视图矩阵是将某个模型向x正向偏移100,其实就是将整个模型的所有坐标点向x正向偏移100;
(3)投影矩阵是将世界坐标系中的所有3d坐标投影到2d平面上,游戏中主要采用透视投影,除此之外还有正交投影和斜视投影,正交投影形成的是一个平头截体(frustum),类似一个金字塔被削掉一部分顶部;
(4)透视投影之后形成的齐次坐标(x,y,z,w),为了形成近大远小的透视效果,需要将x/w,y/w,z/w,转换为标准裁剪空间的坐标;
(5)裁剪空间坐标系在不同的图形库中有所不同,opengl的裁剪空间坐标系是x:-1到+1,y:-1到+1,z:0到1的立方体。使用标准裁剪空间的目的:一是标准裁剪空间的剔除效率比在平头截体中剔除更快,相当于在2d矩形中进行剔除;二是标准裁剪空间可以独立于硬件设备。理论上,z坐标的保留在裁剪的时候是多余的,主要是为了后面的深度检测做准备;
备注:
(1)模型矩阵,视图矩阵,投影矩阵,按照规定的先后顺序可以依次结合,modelmatrix * viewmatrix * projectmatrix。由于矩阵乘法适用于结合律不适用于交换律,所以通常结合的方式是modelview矩阵或者viewproject矩阵,没有modelproject矩阵。计算方式有两种:左乘列向量(projectmatrix * viewmatrix * modelmatrix * vector),右乘行向量(vector * modelmatrix * viewmatrix * projectmatrix);
(2)裁剪过程不是简单的剔除不可见的坐标点,在剔除部分坐标点后,会导致一些图元被分割,因此opengl为帮助我们计算剔除后图元和裁剪空间的交点,交点会作为被分割的图元的新坐标点,用于后续的显示;
在游戏逻辑中检测不可见对象,在提交给gpu之前久提前进行了剔除(cocos2d为例):
Vec2 Camera::projectGL(const Vec3& src) const
{
Vec2 screenPos;
auto viewport = Director::getInstance()->getWinSize(); // 获取游戏的设计分辨率
Vec4 clipPos;
getViewProjectionMatrix().transformVector(Vec4(src.x, src.y, src.z, 1.0f), &clipPos); // 将坐标点通过透视投影进行变换,其实在cocos2d中,透视矩阵和一个相机定义的视图矩阵是结合在一起的
CCASSERT(clipPos.w != 0.0f, "clipPos.w can't be 0.0f!");
float ndcX = clipPos.x / clipPos.w; // 使用透视除法,转换成齐次标准裁剪空间坐标
float ndcY = clipPos.y / clipPos.w;
screenPos.x = (ndcX + 1.0f) * 0.5f * viewport.width; // 由于裁剪空间x坐标是从-1到1,要将裁剪空间的坐标映射到屏幕坐标,映射算法是(x - (-1)) / (1 - (-1)) * width
screenPos.y = (ndcY + 1.0f) * 0.5f * viewport.height;
return screenPos;
}
bool Renderer::checkVisibility(const Mat4 &transform, const Size &size)
{
auto scene = Director::getInstance()->getRunningScene();
//If draw to Rendertexture, return true directly.
// only cull the default camera. The culling algorithm is valid for default camera.
if (!scene || (scene && scene->_defaultCamera != Camera::getVisitingCamera()))
return true;
auto director = Director::getInstance();
Rect visiableRect(director->getVisibleOrigin(), director->getVisibleSize());
// transform center point to screen space
float hSizeX = size.width/2; // 用矩形中心点作为检测点
float hSizeY = size.height/2;
Vec3 v3p(hSizeX, hSizeY, 0);
transform.transformPoint(&v3p); // 使用模型视图矩阵去变换坐标,将其转换到世界坐标系中,cocos2d是将图元渲染在z为0的平面上
Vec2 v2p = Camera::getVisitingCamera()->projectGL(v3p); // 使用投影矩阵将世界坐标转换到屏幕坐标
// 计算右上和右下两个坐标点在模型坐标系中旋转后的坐标,用来计算矩形旋转后的最大边界值
// convert content size to world coordinates
float wshw = std::max(fabsf(hSizeX * transform.m[0] + hSizeY * transform.m[4]), fabsf(hSizeX * transform.m[0] - hSizeY * transform.m[4]));
float wshh = std::max(fabsf(hSizeX * transform.m[1] + hSizeY * transform.m[5]), fabsf(hSizeX * transform.m[1] - hSizeY * transform.m[5]));
// 增加可见范围的尺寸,检测可见性
// enlarge visible rect half size in screen coord
visiableRect.origin.x -= wshw;
visiableRect.origin.y -= wshh;
visiableRect.size.width += wshw * 2;
visiableRect.size.height += wshh * 2;
bool ret = visiableRect.containsPoint(v2p);
return ret;
}
cocos2d中的可见性检测的更多相关文章
- golang中的race检测
golang中的race检测 由于golang中的go是非常方便的,加上函数又非常容易隐藏go. 所以很多时候,当我们写出一个程序的时候,我们并不知道这个程序在并发情况下会不会出现什么问题. 所以在本 ...
- iOS中使用 Reachability 检测网络
iOS中使用 Reachability 检测网络 内容提示:下提供离线模式(Evernote).那么你会使用到Reachability来实现网络检测. 写本文的目的 了解Reachability都 ...
- 浅谈JavaScript中的能力检测
引言 我们知道,各个版本的浏览器有着许多不一致性.理想状态下,应该是所有的浏览器都提供一套标准的API接口.但是现实中,各个版本的浏览器存在的怪癖非常多,我们通常都是使用客户端检测来作为补救措施.但是 ...
- Cocos2d 中的Sprite大小调整问题
以前用UIImageView,比如 UIImageView *view = [[UIImageViewalloc] initWithImage:[UIImageimageNamed:@"b ...
- cocos2d 中判断CGPoint或者CGSize是否相等
cocos2d 中判断CGPoint是否相等 调用CGPointEqualToPoint(point1, point2) 判断CGSize是否相等 调用CGSizeEqualToSize(size1, ...
- AndroidPN中的心跳检测
在AndroidPN客户端里存在着心跳检测功能.就是每隔一段时间客户端向服务器端发送一个消息,以检测连接是否正常,发送的消息内容为: <presence id="h09Ke-13&qu ...
- cocos2d中如何使用图片纹理图集的加载来实现一个动画的功能
cocos2d中要实现一个动画,一般采用纹理图集的方式,也就是说把几个连续动作的图片挨个显示切换这样就是动画 一: 首先先看下今天要实现的具体的目的,打飞机的时间屏幕上会有一个喷火的小飞机,飞机的尾部 ...
- Cocos2D中节点Z序的计算规则
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...
- Cocos2D中Action的进阶使用技巧(一)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 大家对Cocos2d中动作的使用大概都很清楚了,其实本身act ...
随机推荐
- 网站后台调用winform MessageLoopApartment
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- apply和call
call和apply是定义在Function.prototype上的方法. 共同点:可以自由指定函数执行时内部this的指向 不同点:传参方式不同 call方法: 语法:call(thisObj,Ob ...
- 如何修改WAMP中mysql默认空密码 以及修改时报错的处理方法
WAMP安装好后,mysql密码是为空的,那么要如何修改呢?其实很简单,通过几条指令就行了,下面我就一步步来操作. 首先,通过WAMP打开mysql控制台. 提示输入密码,因为现在是空,所以直接按回车 ...
- UIImagePickerController 获取相片视频
1.UIImagePickerController的静态方法: imagepicker = [[UIImagePickerController alloc]init]; //UIImagePic ...
- Python OpenCV —— Arithmetic
图案的算术操作. # -*- coding: utf-8 -*- """ Created on Wed Sep 28 11:54:47 2016 @author: Adm ...
- hdu4691 Front compression ——暴力 || 后缀数组
link:http://acm.hdu.edu.cn/showproblem.php?pid=4691 暴力,数据明显太水了吧,n=10^5, O(n^2)的复杂度哎喂.想让大家暴力写直接让n=100 ...
- 修改Apache的最大连接数
Apache的最大连接数,默认为256个. 修改apache的最大连接数,方法如下: 一:先修改./apache/conf/httpd.conf文件. # vi httpd.conf 将“#Inclu ...
- Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题
标签:scrollview android 滑动 嵌套 scrollview 嵌套recyclerview 时,recyclerview不显示,这就需要我们自己计算recyclerview ...
- Java引用总结--StrongReference、SoftReference、WeakReference、PhantomReference
Java引用总结--StrongReference.SoftReference.WeakReference.PhantomReference 1 Java引用介绍 Java从1.2版本开始引入了4种引 ...
- 033. asp.netWeb用户控件之二将页面转换成web控件和使用Web控件显示热点新闻
访问Web用户控件的属性 ASP.NET提供的各种服务器控件都有其自身的属性和方法,程序开发人员可以灵活地使用服务器控件中的属性和方法开发程序.在用户控件中,程序开发人员也可以自行定义各种属性和方法, ...