cocos2dx 3.x 相机机制

前端之家收集整理的这篇文章主要介绍了cocos2dx 3.x 相机机制前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

http://www.cnblogs.com/wantnon/p/4158135.htmlv

一,3.x相机使用方法

 CCSizewinSize=CCDirector::sharedDirector()->getWinSize();

Camera*camera=Camera::create();

camera->setCameraFlag(CameraFlag::USER1);

this->addChild(camera);

sprite->setCameraMask(2); //因为2 & CameraFlag::USER1 !=0,所以cameraMask=2与CameraFlag::USER1匹配,sprite将使用上面创建的camera

Vec3eyePosOld=camera->getPosition3D();

Vec3eyePos=Vec3(x,y,eyePosOld.z);

camera->setPosition3D(eyePos);

  assert(eyePos.z>0);

camera->lookAt(Vec3(eyePos.x,eyePos.y,0),Vec3(0,1,0));

注意,这里有个坑:camera->lookAt必须在camera->setPostion3D之后,因为lookAt中有一句

Vec3::subtract(this->getPosition3D(),lookAtPos,&zaxis),即相减得出相机空间z轴,

使用了getPosition3D。所以必须先设定好position3D再调lookAt才能得到正确结果。

参考:

http://www.cocos2d-x.org/news/344

cocos2d_tests - Camera3DTest.cpp

二,3.x与2.x相机的差别:

cocos2dx 3.x中的相机机制与cocos2dx 2.x中差别很大。

在2.x中每个节点都有camera,所以每个节点都有自己的局部view矩阵。矩阵堆栈将形如:(proj,view,model,...)

而在3.x中相机不是隶属于节点的,而是全局的,所以节点没有自己的局部view矩阵,只有一个起始的view矩阵,即矩阵堆栈将形如:(proj,...)

三,3.x相机实现原理:

前面已经看到,使用3.x相机关键有三点:

1,用户自己创建相机并指定cameraFlag。

2,为节点指定与cameraFlg按位与不为0的cameraMask,则此节点即使用此相机。

3,相机可addChild到任意一个节点(尽量使用根节点)。

自定义相机的cameraFlag可取USER1~USER8,定义如下:

enum class CameraFlag

{

DEFAULT = 1,

USER1 = 1 << 1,

USER2 = 1 << 2,

USER3 = 1 << 3,

USER4 = 1 << 4,

USER5 = 1 << 5,

USER6 = 1 << 6,

USER7 = 1 << 7,

USER8 = 1 << 8,

};

Node::setCameraMask(unsigned short mask,bool applyChildren)用来指定cameraMask,其第二个参数用来指明子节点是否递归地使用相同的mask,默认为true。要特别注意:node->setCameraMask(mask,true)只能使node的当前所有子节点的cameraMask设置为mask,但在此之后新添加的子节点则不会受影响(仍然是默认camera),需要记着手动进行设置,这里很容易被坑。又比如在Layer::init()里开头写了一句this->setCameraMask(mask,true)紧接着加了些子节点,那么要意识到这些子节点是不会被设置的,要么对每个子节点都手动调一次setCameraMask,要不就把this->setCameraMask写到init函数的末尾。

不管camera被addChild到哪个节点,其都会被添加到Scene的_cameras成员中。如果Scene中任何一个节点都没有添加用户自定义相机,则scene的_cameras成员中只含有一个默认相机,就是Scene::_defaultCamera所引用的相机;如果Scene中某些节点添加用户自定义相机,则_cameras[0]是默认相机,其余元素是用户相机。

至于camera是如何被添加到_cameras中的,逻辑在Camera的onEnter函数中,如下:

void Camera::onEnter()

{

if (_scene == nullptr)

{

auto scene = getScene();

if (scene)

setScene(scene);

}

Node::onEnter();

}

void Camera::setScene(Scene* scene)

{

if (_scene != scene)

{

//remove old scene

if (_scene)

{

auto& cameras = _scene->_cameras;

auto it = std::find(cameras.begin(),cameras.end(),this);

if (it != cameras.end())

cameras.erase(it);

_scene = nullptr;

}

//set new scene

if (scene)

{

_scene = scene;

auto& cameras = _scene->_cameras;

auto it = std::find(cameras.begin(),this);

if (it == cameras.end())

_scene->_cameras.push_back(this);

}

}

}

下面解释3.x是如何实现相机与节点通过cameraFlag/cameraMask值进行配对儿的:

只需看Scene::render(Renderer* renderer)函数

void Scene::render(Renderer* renderer)

{

auto director = Director::getInstance();

Camera* defaultCamera = nullptr;

for (const auto& camera : _cameras)

{

Camera::_visitingCamera = camera;

if (Camera::_visitingCamera->getCameraFlag() == CameraFlag::DEFAULT)

{

defaultCamera = Camera::_visitingCamera;

continue;

}

director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,Camera::_visitingCamera->getViewProjectionMatrix());

//visit the scene

visit(renderer,Mat4::IDENTITY,0);

renderer->render();

director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

}

//draw with default camera

if (defaultCamera)

{

Camera::_visitingCamera = defaultCamera;

director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,0);

renderer->render();

director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

}

Camera::_visitingCamera = nullptr;

}

上面函数逻辑看起来写得很墨迹,其实意思很简单,就是:

对于这个Scene,用其_cameras中各相机分别render一遍。

那么问题来了,假如_cameras里有十个相机,那么Scene就要render十遍,这不坑爹吗?其实也不算很坑爹,因为每遍render只render与当前相机匹配的节点,所以总起来仍然是每个节点render一次。

从哪里可以看出每次render只render与当前相机匹配的节点呢?下面Node::visit(...)中的bool visibleByCamera = isVisitableByVisitingCamera()一句就是这个作用。

void Node::visit(Renderer* renderer,const Mat4 &parentTransform,uint32_t parentFlags)

{

// quick return if not visible. children won't be drawn.

if (!_visible)

{

return;

}

uint32_t flags = processParentFlags(parentTransform,parentFlags);

// IMPORTANT:

// To ease the migration to v3.0,we still support the Mat4 stack,

// but it is deprecated and your code should not rely on it

Director* director = Director::getInstance();

director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW,_modelViewTransform);

bool visibleByCamera = isVisitableByVisitingCamera();

int i = 0;

if(!_children.empty())

{

sortAllChildren();

// draw children zOrder < 0

for( ; i < _children.size(); i++ )

{

auto node = _children.at(i);

if ( node && node->_localZOrder < 0 )

node->visit(renderer,_modelViewTransform,flags);

else

break;

}

// self draw

if (visibleByCamera)

this->draw(renderer,flags);

for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)

(*it)->visit(renderer,flags);

}

else if (visibleByCamera)

{

this->draw(renderer,flags);

}

director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

// FIX ME: Why need to set _orderOfArrival to 0??

// Please refer tohttps://github.com/cocos2d/cocos2d-x/pull/6920

// reset for next frame

// _orderOfArrival = 0;

}

bool Node::isVisitableByVisitingCamera() const

{

auto camera = Camera::getVisitingCamera();

bool visibleByCamera = camera ? (unsigned short)camera->getCameraFlag() & _cameraMask : true;

return visibleByCamera;

}

猜你在找的Cocos2d-x相关文章