游戏的在进行一次渲染的时候,通常会提交大量的渲染对象给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中的可见性检测的更多相关文章

  1. golang中的race检测

    golang中的race检测 由于golang中的go是非常方便的,加上函数又非常容易隐藏go. 所以很多时候,当我们写出一个程序的时候,我们并不知道这个程序在并发情况下会不会出现什么问题. 所以在本 ...

  2. iOS中使用 Reachability 检测网络

    iOS中使用 Reachability 检测网络 内容提示:下提供离线模式(Evernote).那么你会使用到Reachability来实现网络检测.   写本文的目的 了解Reachability都 ...

  3. 浅谈JavaScript中的能力检测

    引言 我们知道,各个版本的浏览器有着许多不一致性.理想状态下,应该是所有的浏览器都提供一套标准的API接口.但是现实中,各个版本的浏览器存在的怪癖非常多,我们通常都是使用客户端检测来作为补救措施.但是 ...

  4. Cocos2d 中的Sprite大小调整问题

    以前用UIImageView,比如  UIImageView *view = [[UIImageViewalloc] initWithImage:[UIImageimageNamed:@"b ...

  5. cocos2d 中判断CGPoint或者CGSize是否相等

    cocos2d 中判断CGPoint是否相等 调用CGPointEqualToPoint(point1, point2) 判断CGSize是否相等 调用CGSizeEqualToSize(size1, ...

  6. AndroidPN中的心跳检测

    在AndroidPN客户端里存在着心跳检测功能.就是每隔一段时间客户端向服务器端发送一个消息,以检测连接是否正常,发送的消息内容为: <presence id="h09Ke-13&qu ...

  7. cocos2d中如何使用图片纹理图集的加载来实现一个动画的功能

    cocos2d中要实现一个动画,一般采用纹理图集的方式,也就是说把几个连续动作的图片挨个显示切换这样就是动画 一: 首先先看下今天要实现的具体的目的,打飞机的时间屏幕上会有一个喷火的小飞机,飞机的尾部 ...

  8. Cocos2D中节点Z序的计算规则

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...

  9. Cocos2D中Action的进阶使用技巧(一)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 大家对Cocos2d中动作的使用大概都很清楚了,其实本身act ...

随机推荐

  1. android studio 开启genymotion 出现"failed to create framebuffer image"

    出现错误 Unable to start the virtul device To start virtual devices, make sure that your video card supp ...

  2. PureLayout和Masonry比较

    一年前那时我做iOS开发,为了自动布局适配多种屏幕,我一般使用Masonry,后来偶然地在一个视频教程中发现老师使用了UIView+Autolayout(现在作者改名为PureLayout)自动布局, ...

  3. android广播接收器BroadcastReceiver

    首先看一下什么是 BroadcastReceiver BroadcastReceiver:直译是"广播接收者",所以它的作用是用来接收发送过来的广播的. 那我们有必要知道:什么是广 ...

  4. 黑马程序员——【Java基础】——File类、Properties集合、IO包中的其他类

    ---------- android培训.java培训.期待与您交流! ---------- 一.File类 (一)概述 1.File类:文件和目录路径名的抽象表现形式 2.作用: (1)用来将文件或 ...

  5. React Native使用AsyncStorage本地持久化

    AsyncStorage AsyncStorage是一个简单的,未加密的,异步的,持久化,关键值存储系统,是全局的.类似于iOS中的NSUserDefault. 存值: import { AppReg ...

  6. Magento文件系统目录结构

    magento │  .htaccess│  cron.php //系统cron程序,修改 linux的cron运行,加入magento的一些定时处理│  cron.sh│  favicon.ico ...

  7. 修改LR自带的示例程序端口号

    问题:LoadRunner的HP Web Tours 应用程序服务启动不了,提示1080端口被占用的问题 解决方法: 查看占用1080端口的进程 Cmd 窗口输入netstat –ano  找到占用该 ...

  8. POJ 2533 动态规划入门 (LIS)

    Longest Ordered Subsequence Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 42914 Accepte ...

  9. Spring触发器配置Quartz

    参考文献:http://blog.csdn.net/liaq325/article/details/8269439 http://sundoctor.iteye.com/blog/441951 业务类 ...

  10. yii框架便利类CVarDumper使用

    1.类文件位置:path/to/yiiframework/utils/CVarDumper.php 2.作用:CVarDumper is intended to replace the buggy P ...