游戏的在进行一次渲染的时候,通常会提交大量的渲染对象给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. 学习Nim语言.rar(nim语言中文教程下载)

    学习Nim语言 nim 语法上类似python ,是一门静态编译型语言,nim 使用空格缩进标示语句块的开始和结束, 喜欢python风格的程序员应该也会很容易适应和喜欢nim的风格. nim语言官方 ...

  2. webshell

    webshell就是以asp.php.jsp或者cgi等网页文件形式存在的一种命令执行环境,也可以将其称做为一种网页后门.黑客在入侵了一个网站后,通常会将asp或php后门文件与网站服务器WEB目录下 ...

  3. Python学习路程day8

    Socket语法及相关 socket概念 A network socket is an endpoint of a connection across a computer network. Toda ...

  4. Spring框架学习(一)

    一.概述 spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器.为软件开发提供全方位支持的应用程序框架. 二.控制反转(In ...

  5. 初试微信小程序

    2016年11月3日,微信小程序终于公测了,大家可以正式开发了.早在这之前,应公司要求,和同事就早早的试了一下微信小程序的开发,特此记录一下: 微信官方小程序文档:https://mp.weixin. ...

  6. php之无限极分类

    首先建立分类信息表: CREATE TABLE IF NOT EXISTS `category` ( `categoryId` smallint(5) unsigned NOT NULL AUTO_I ...

  7. VNC-Server安装及配置

    一.什么是VNC? VNC (Virtual Network Computer)是虚拟网络计算机的缩写.VNC 是一款优秀的远程控制工具软件,由著名的 AT&T 的欧洲研究实验室开发的.VNC ...

  8. 深入解读Linux与Android的相互关系(转-lining)

    大家都知道Android是基于Linux内核的操作系统,也曾经和Linux基金会因为内核问题产生过分歧,本文将开始对Android的内核进行剖析,主要介绍Android和Linux之间的关系,后续还会 ...

  9. 使用Condition Variables 实现一个线程安全队列

    使用Condition Variables实现一个线程安全队列 测试机: i7-4800MQ .7GHz, logical core, physical core, 8G memory, 256GB ...

  10. pt-ioprofile分析查看mysql的真实IO情况

    针对IO密集型应用做系统调优的时候,我们通常都需要知道系统cpu  内存  io 网络等系统性能 和 使用率,结合应用本身的访问量,以及 mysql的性能指标来综合分析.比如说:我们将系统压力情况分为 ...