前面的渲染流程一篇说过,每个Node节点的渲染都是在自己的draw函数中生成渲染命令,然后添加到渲染队列中。我们看下Sprite的draw函数。
void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
if (_texture == nullptr)
{
return;
}
#if CC_USE_CULLING
// Don't calculate the culling if the transform was not updated
auto visitingCamera = Camera::getVisitingCamera();
auto defaultCamera = Camera::getDefaultCamera();
if (visitingCamera == nullptr) { //如果没有观察的摄像头,则默认可见
_insideBounds = true;
}
else if (visitingCamera == defaultCamera) { //判断待渲染的纹理是否在可见区域
_insideBounds = ((flags & FLAGS_TRANSFORM_DIRTY) || visitingCamera->isViewProjectionUpdated()) ? renderer->checkVisibility(transform, _contentSize) : _insideBounds;
}
else
{
// XXX: this always return true since
_insideBounds = renderer->checkVisibility(transform, _contentSize);
}
if(_insideBounds)
#endif
{
//初始化_trianglesCommand
_trianglesCommand.init(_globalZOrder,
_texture,
getGLProgramState(),
_blendFunc,
_polyInfo.triangles,
transform,
flags);
//添加到渲染队列
renderer->addCommand(&_trianglesCommand);
}
}
从代码中看到,draw函数比较简单,大致分为两步,第一步首先判断该sprite是否可见,第二部是初始化渲染命令_trianglesCommand并加入队列中。
我们看下可见性判断函数Renderer::checkVisibility(),代码如下
bool Renderer::checkVisibility(const Mat4 &transform, const Size &size)
{
auto director = Director::getInstance();
auto scene = director->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; //如果默认摄像头不是visiting摄像头,则表示当前是离屏渲染?
//visibleRect是当前场景的可视化区域
Rect visibleRect(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); //v3p是要显示对象的矩形的中点
transform.transformPoint(&v3p); //对v3p做变换
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
visibleRect.origin.x -= wshw; //扩大它的可视化区域
visibleRect.origin.y -= wshh;
visibleRect.size.width += wshw * 2;
visibleRect.size.height += wshh * 2;
bool ret = visibleRect.containsPoint(v2p); //判断是否包含在可视化区域
return ret;
}
分析在注释里,比如下图:
![](https://img.haomeiwen.com/i5994163/b75aa9a17eb9f642.png)
图中最大的矩形是扩大后的可见区域,较小的矩形是没扩展前的可见区域,可以理解为屏幕。阴影矩形是要显示的对象,由图可知,虽然它的中点v2p在屏幕之外,但是因为它在扩展后的可见区域内,它还是有一部分是可见的。
网友评论