cocos2dx 3.x 相机机制
一,3.x相机使用方法:
CCSize winSize=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
Vec3 eyePosOld=camera->getPosition3D();
Vec3 eyePos=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,view,model,…)
而在3.x中相机不是隶属于节点的,而是全局的,所以节点没有自己的局部view矩阵,只有一个起始的view矩阵,即矩阵堆栈将形如:(proj,view,model,model,model,…)
三,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(), cameras.end(), this);
if (it == cameras.end())
_scene->_cameras.push_back(this);
}
}
}
下面解释3.x是如何实现相机与节点通过cameraFlag/cameraMask值进行配对儿的ÿ