前言
在3D游戲當中,我們經常會使用到照相機這個東西,無論你使用的是哪一款引擎,都會用到,同時,照相機這個東西涉及到的東西比較多,基礎知識需要扎實一些才可以。
如何使用
很久之前做項目的時候用到過一次,已經忘記的差不多了。為此,我找了cpp test中的示例代碼,找了一個相對簡單的代碼,我把關鍵代碼貼出來。
auto layer3D=Layer::create();
addChild(layer3D,0);
_layer3D=layer3D;
_shader =GLProgram::createWithFilenames("Sprite3DTest/fog.vert","Sprite3DTest/fog.frag");
_state = GLProgramState::create(_shader);
_sprite3D1 = Sprite3D::create("Sprite3DTest/teapot.c3b");
_sprite3D2 = Sprite3D::create("Sprite3DTest/teapot.c3b");
_sprite3D1->setGLProgramState(_state);
_sprite3D2->setGLProgramState(_state);
//pass mesh's attribute to shader
long offset = 0;
auto attributeCount = _sprite3D1->getMesh()->getMeshVertexAttribCount();
for (auto i = 0; i < attributeCount; i++) {
auto meshattribute = _sprite3D1->getMesh()->getMeshVertexAttribute(i);
_state->setVertexAttribPointer(s_attributeNames[meshattribute.vertexAttrib],
meshattribute.size,
meshattribute.type,
GL_FALSE,
_sprite3D1->getMesh()->getVertexSizeInBytes(),
(GLvoid*)offset);
offset += meshattribute.attribSizeBytes;
}
long offset1 = 0;
auto attributeCount1 = _sprite3D2->getMesh()->getMeshVertexAttribCount();
for (auto i = 0; i < attributeCount1; i++) {
auto meshattribute = _sprite3D2->getMesh()->getMeshVertexAttribute(i);
_state->setVertexAttribPointer(s_attributeNames[meshattribute.vertexAttrib],
meshattribute.size,
meshattribute.type,
GL_FALSE,
_sprite3D2->getMesh()->getVertexSizeInBytes(),
(GLvoid*)offset1);
offset1 += meshattribute.attribSizeBytes;
}
_state->setUniformVec4("u_fogColor", Vec4(0.5,0.5,0.5,1.0));
_state->setUniformFloat("u_fogStart",10);
_state->setUniformFloat("u_fogEnd",60);
_state->setUniformInt("u_fogEquation" ,0);
_layer3D->addChild(_sprite3D1);
_sprite3D1->setPosition3D( Vec3( 0, 0,0 ) );
_sprite3D1->setScale(2.0f);
_sprite3D1->setRotation3D(Vec3(-90,180,0));
_layer3D->addChild(_sprite3D2);
_sprite3D2->setPosition3D( Vec3( 0, 0,-20 ) );
_sprite3D2->setScale(2.0f);
_sprite3D2->setRotation3D(Vec3(-90,180,0));
// 在所有子節點都創建完了以后才創建照相機
if (_camera == nullptr)
{
// 創建投影的攝像機
_camera=Camera::createPerspective(60, (GLfloat)s.width/s.height, 1, 1000);
// 設置標識符
_camera->setCameraFlag(CameraFlag::USER1);
_camera->setPosition3D(Vec3(0, 30, 40));
// 設置攝像機看着目標
_camera->lookAt(Vec3(0,0,0), Vec3(0, 1, 0));
// 記得把攝像機加入到場景中
_layer3D->addChild(_camera);
}
_layer3D->setCameraMask(2);
這段代碼其實就是創建了一個3d的模型,並且讓照相機照着這個3d模型,可以重點看創建照相機的代碼。
源碼分析
源碼中的英文注釋已經說的很詳細了,但我還是用英文來寫一下。
.h文件代碼:
****************************************************************************/
#ifndef _CCCAMERA_H__
#define _CCCAMERA_H__
#include "2d/CCNode.h"
#include "3d/CCFrustum.h"
#include "renderer/CCQuadCommand.h"
#include "renderer/CCCustomCommand.h"
#include "renderer/CCFrameBuffer.h"
NS_CC_BEGIN
class Scene;
class CameraBackgroundBrush;
/**
* Note:
* Scene creates a default camera. And the default camera mask of Node is 1, therefore it can be seen by the default camera.
* During rendering the scene, it draws the objects seen by each camera in the added order except default camera. The default camera is the last one being drawn with.
* It's usually a good idea to render 3D objects in a separate camera.
* And set the 3d camera flag to CameraFlag::USER1 or anything else except DEFAULT. Dedicate The DEFAULT camera for UI, because it is rendered at last.
* You can change the camera order to get different result when depth test is not enabled.
* For each camera, transparent 3d sprite is rendered after opaque 3d sprite and other 2d objects.
*/
// 上面英文就已經介紹的很好了,
// 相機的標識符,每個Node中有個_cameraMask的屬性,當相機的_cameraFlag & _cameraMask為true時,
// 該Node可以被相機看到
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,
};
/**
* Defines a camera .
*/
class CC_DLL Camera :public Node
{
friend class Scene;
friend class Director;
friend class EventDispatcher;
public:
/**
* The type of camera.
*/
// 相機類型,分別是投影和正交
enum class Type
{
PERSPECTIVE = 1,
ORTHOGRAPHIC = 2
};
public:
/**
* Creates a perspective camera.
*
* @param fieldOfView The field of view for the perspective camera (normally in the range of 40-60 degrees).
* @param aspectRatio The aspect ratio of the camera (normally the width of the viewport divided by the height of the viewport).
* @param nearPlane The near plane distance.
* @param farPlane The far plane distance.
*/
/**
創建一個透視相機。
參數:
fieldOfView 透視相機的可視角度 (一般是在40-60度之間).
aspectRatio 相機的長寬比(通常會使用視窗的寬度除以視窗的高度)。
nearPlane 近平面的距離。
farPlane 遠平面的距離。
*/
static Camera* createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane);
/**
* Creates an orthographic camera.
*
* @param zoomX The zoom factor along the X-axis of the orthographic projection (the width of the ortho projection).
* @param zoomY The zoom factor along the Y-axis of the orthographic projection (the height of the ortho projection).
* @param nearPlane The near plane distance.
* @param farPlane The far plane distance.
*/
/**
創建一個正交相機。
參數:
zoomX 沿x軸的正交投影的縮放因子(正交投影的寬度)。
zoomY 沿y軸的正交投影的縮放因子(正交投影的高度)。
nearPlane 近平面的距離。
farPlane 遠平面的距離。
*/
static Camera* createOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane);
/** create default camera, the camera type depends on Director::getProjection, the depth of the default camera is 0 */
/**
創建默認的相機,相機的類型取決於Director::getProjection,默認的相機深度是0
*/
static Camera* create();
/**
* Gets the type of camera.
*
* @return The camera type.
*/
Camera::Type getType() const { return _type; }
/**get & set Camera flag*/
CameraFlag getCameraFlag() const { return (CameraFlag)_cameraFlag; }
void setCameraFlag(CameraFlag flag) { _cameraFlag = (unsigned short)flag; }
/**
* Make Camera looks at target
*
* @param target The target camera is point at
* @param up The up vector, usually it's Y axis
*/
/**
使相機看着目標
參數:
target 目標的位置
up 相機向上的向量,通常這是Y軸
*/
virtual void lookAt(const Vec3& target, const Vec3& up = Vec3::UNIT_Y);
/**
* Gets the camera's projection matrix.
*
* @return The camera projection matrix.
*/
/**
獲取相機的投影矩陣。
返回:
相機投影矩陣。
*/
const Mat4& getProjectionMatrix() const;
/**
* Gets the camera's view matrix.
*
* @return The camera view matrix.
*/
/**
獲取相機的視圖矩陣。
返回:
相機視圖矩陣。
*/
const Mat4& getViewMatrix() const;
/**get view projection matrix*/
/**
得到視圖投影矩陣。
*/
const Mat4& getViewProjectionMatrix() const;
/* convert the specified point in 3D world-space coordinates into the screen-space coordinates.
*
* Origin point at left top corner in screen-space.
* @param src The world-space position.
* @return The screen-space position.
*/
/*
把指定坐標點從世界坐標轉換為屏幕坐標。 原點在屏幕坐標系的左上角。
參數:
src 世界的位置。
返回:
屏幕的位置。
*/
Vec2 project(const Vec3& src) const;
/* convert the specified point in 3D world-space coordinates into the GL-screen-space coordinates.
*
* Origin point at left bottom corner in GL-screen-space.
* @param src The 3D world-space position.
* @return The GL-screen-space position.
*/
/*
把指定坐標點從3D世界坐標轉換為GL坐標。 原點在GL屏幕坐標系的左下角。
參數:
src 3D世界的位置。
返回:
GL屏幕空間的位置。
*/
Vec2 projectGL(const Vec3& src) const;
/**
* Convert the specified point of screen-space coordinate into the 3D world-space coordinate.
*
* Origin point at left top corner in screen-space.
* @param src The screen-space position.
* @return The 3D world-space position.
*/
// 和上面的相反
Vec3 unproject(const Vec3& src) const;
/**
* Convert the specified point of GL-screen-space coordinate into the 3D world-space coordinate.
*
* Origin point at left bottom corner in GL-screen-space.
* @param src The GL-screen-space position.
* @return The 3D world-space position.
*/
// 和上面的相反
Vec3 unprojectGL(const Vec3& src) const;
/**
* Convert the specified point of screen-space coordinate into the 3D world-space coordinate.
*
* Origin point at left top corner in screen-space.
* @param size The window size to use.
* @param src The screen-space position.
* @param dst The 3D world-space position.
*/
void unproject(const Size& size, const Vec3* src, Vec3* dst) const;
/**
* Convert the specified point of GL-screen-space coordinate into the 3D world-space coordinate.
*
* Origin point at left bottom corner in GL-screen-space.
* @param size The window size to use.
* @param src The GL-screen-space position.
* @param dst The 3D world-space position.
*/
void unprojectGL(const Size& size, const Vec3* src, Vec3* dst) const;
/**
* Is this aabb visible in frustum
*/
/**
aabb在視椎體內是否可見
*/
bool isVisibleInFrustum(const AABB* aabb) const;
/**
* Get object depth towards camera
*/
/**
獲取朝向相機的物體深度。
*/
float getDepthInView(const Mat4& transform) const;
/**
* set depth, camera with larger depth is drawn on top of camera with smaller depth, the depth of camera with CameraFlag::DEFAULT is 0, user defined camera is -1 by default
*/
/**
設置深度,相比深度小的,深度較大的相機會繪制在頂端,標識是CameraFlag::DEFAULT的相機深度是0,用戶定義的相機深度默認為-1
*/
void setDepth(int8_t depth);
/**
* get depth, camera with larger depth is drawn on top of camera with smaller depth, the depth of camera with CameraFlag::DEFAULT is 0, user defined camera is -1 by default
*/
int8_t getDepth() const { return _depth; }
/**
get rendered order
*/
/**
獲取渲染順序。
*/
int getRenderOrder() const;
/**
* Get the frustum's far plane.
*/
/**
獲取視椎體遠平面。
*/
float getFarPlane() const { return _farPlane; }
/**
* Get the frustum's near plane.
*/
/**
獲取視椎體近平面。
*/
float getNearPlane() const { return _nearPlane; }
//override
virtual void onEnter() override;
virtual void onExit() override;
/**
* Get the visiting camera , the visiting camera shall be set on Scene::render
*/
/**
獲取繪制的相機,繪制的相機會在Scene::render中設置。
*/
static const Camera* getVisitingCamera() { return _visitingCamera; }
/**
* Get the default camera of the current running scene.
*/
/**
獲取到當前運行場景的默認相機。
*/
static Camera* getDefaultCamera();
/**
Before rendering scene with this camera, the background need to be cleared. It clears the depth buffer with max depth by default. Use setBackgroundBrush to modify the default behavior
*/
/**
在相機渲染所屬的場景前,需要對背景進行清除。它以默認的深度值清除緩存,可以通過setBackgroundBrush 函數獲取深度值。
*/
void clearBackground();
/**
Apply the FBO, RenderTargets and viewport.
*/
/**
應用幀緩沖,渲染目標和視圖。
*/
void apply();
/**
Set FBO, which will attach several render target for the rendered result.
*/
/**
設置幀緩沖,從中可以獲取到一些需要渲染的目標。
*/
void setFrameBufferObject(experimental::FrameBuffer* fbo);
/**
Set Viewport for camera.
*/
/**
設置相機視口。
*/
void setViewport(const experimental::Viewport& vp) { _viewport = vp; }
/**
* Whether or not the viewprojection matrix was updated since the last frame.
* @return True if the viewprojection matrix was updated since the last frame.
*/
/**
視圖矩陣是否在上一幀被更新。
*/
bool isViewProjectionUpdated() const {return _viewProjectionUpdated;}
/**
* set the background brush. See CameraBackgroundBrush for more information.
* @param clearBrush Brush used to clear the background
*/
/**
設置背景刷,通過CameraBackgroundBrush 查看更多詳情。
*/
void setBackgroundBrush(CameraBackgroundBrush* clearBrush);
/**
* Get clear brush
*/
CameraBackgroundBrush* getBackgroundBrush() const { return _clearBrush; }
/**
遍歷所有子節點,並且循環遞歸得發送它們的渲染指令。
參數:
renderer 指定一個渲染器
parentTransform 父節點放射變換矩陣
parentFlags 渲染器標簽
重載 Node .
*/
virtual void visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags) override;
bool isBrushValid();
CC_CONSTRUCTOR_ACCESS:
Camera();
~Camera();
/**
* Set the scene,this method shall not be invoke manually
*/
/**
設置場景,這個方法不應該手動調用 .
*/
void setScene(Scene* scene);
/**set additional matrix for the projection matrix, it multiplies mat to projection matrix when called, used by WP8*/
void setAdditionalProjection(const Mat4& mat);
/** init camera */
/**
初始化相機。包括透視相機和正交相機。
*/
bool initDefault();
bool initPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane);
bool initOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane);
void applyFrameBufferObject();
void applyViewport();
protected:
Scene* _scene; //Scene camera belongs to
Mat4 _projection;
mutable Mat4 _view;
mutable Mat4 _viewInv;
mutable Mat4 _viewProjection;
Vec3 _up;
Camera::Type _type;
float _fieldOfView;
float _zoom[2];
float _aspectRatio;
float _nearPlane;
float _farPlane;
mutable bool _viewProjectionDirty;
bool _viewProjectionUpdated; //Whether or not the viewprojection matrix was updated since the last frame.
unsigned short _cameraFlag; // camera flag
mutable Frustum _frustum; // camera frustum
mutable bool _frustumDirty;
int8_t _depth; //camera depth, the depth of camera with CameraFlag::DEFAULT flag is 0 by default, a camera with larger depth is drawn on top of camera with smaller depth
static Camera* _visitingCamera;
CameraBackgroundBrush* _clearBrush; //brush used to clear the back ground
experimental::Viewport _viewport;
experimental::FrameBuffer* _fbo;
protected:
static experimental::Viewport _defaultViewport;
public:
static const experimental::Viewport& getDefaultViewport() { return _defaultViewport; }
static void setDefaultViewport(const experimental::Viewport& vp) { _defaultViewport = vp; }
};
.cpp文件代碼
****************************************************************************/
#include "2d/CCCamera.h"
#include "2d/CCCameraBackgroundBrush.h"
#include "base/CCDirector.h"
#include "platform/CCGLView.h"
#include "2d/CCScene.h"
#include "renderer/CCRenderer.h"
#include "renderer/CCQuadCommand.h"
#include "renderer/CCGLProgramCache.h"
#include "renderer/ccGLStateCache.h"
#include "renderer/CCFrameBuffer.h"
#include "renderer/CCRenderState.h"
NS_CC_BEGIN
Camera* Camera::_visitingCamera = nullptr;
experimental::Viewport Camera::_defaultViewport;
Camera* Camera::getDefaultCamera()
{
auto scene = Director::getInstance()->getRunningScene();
if(scene)
{
return scene->getDefaultCamera();
}
return nullptr;
}
Camera* Camera::create()
{
Camera* camera = new (std::nothrow) Camera();
camera->initDefault();
camera->autorelease();
camera->setDepth(0.f);
return camera;
}
Camera* Camera::createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
{
auto ret = new (std::nothrow) Camera();
if (ret)
{
ret->initPerspective(fieldOfView, aspectRatio, nearPlane, farPlane);
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
Camera* Camera::createOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane)
{
auto ret = new (std::nothrow) Camera();
if (ret)
{
ret->initOrthographic(zoomX, zoomY, nearPlane, farPlane);
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
Camera::Camera()
: _scene(nullptr)
, _viewProjectionDirty(true)
, _cameraFlag(1)
, _frustumDirty(true)
, _depth(-1)
, _fbo(nullptr)
{
_frustum.setClipZ(true);
_clearBrush = CameraBackgroundBrush::createDepthBrush(1.f);
_clearBrush->retain();
}
Camera::~Camera()
{
CC_SAFE_RELEASE_NULL(_fbo);
CC_SAFE_RELEASE(_clearBrush);
}
const Mat4& Camera::getProjectionMatrix() const
{
return _projection;
}
const Mat4& Camera::getViewMatrix() const
{
Mat4 viewInv(getNodeToWorldTransform());
static int count = sizeof(float) * 16;
if (memcmp(viewInv.m, _viewInv.m, count) != 0)
{
_viewProjectionDirty = true;
_frustumDirty = true;
_viewInv = viewInv;
_view = viewInv.getInversed();
}
return _view;
}
void Camera::lookAt(const Vec3& lookAtPos, const Vec3& up)
{
//camera->lookAt必須在camera->setPostion3D之后,因為其在運行過程中調用了getPosition3D()
//定義y方向的歸一化向量。
Vec3 upv = up;
upv.normalize();
//計算x、y、z、方向上的向量。
Vec3 zaxis;
Vec3::subtract(this->getPosition3D(), lookAtPos, &zaxis);
zaxis.normalize();
Vec3 xaxis;
Vec3::cross(upv, zaxis, &xaxis);
xaxis.normalize();
Vec3 yaxis;
Vec3::cross(zaxis, xaxis, &yaxis);
yaxis.normalize();
//將上面計算的向量值構造旋轉矩陣
Mat4 rotation;
rotation.m[0] = xaxis.x;
rotation.m[1] = xaxis.y;
rotation.m[2] = xaxis.z;
rotation.m[3] = 0;
rotation.m[4] = yaxis.x;
rotation.m[5] = yaxis.y;
rotation.m[6] = yaxis.z;
rotation.m[7] = 0;
rotation.m[8] = zaxis.x;
rotation.m[9] = zaxis.y;
rotation.m[10] = zaxis.z;
rotation.m[11] = 0;
/*
定義四元數,將旋轉矩陣轉換為四元數。
通過四元數來設置3D空間中的旋轉角度。要保證四元數是經過歸一化的。
*/
Quaternion quaternion;
Quaternion::createFromRotationMatrix(rotation,&quaternion);
quaternion.normalize();
setRotationQuat(quaternion);
}
const Mat4& Camera::getViewProjectionMatrix() const
{
getViewMatrix();
if (_viewProjectionDirty)
{
_viewProjectionDirty = false;
Mat4::multiply(_projection, _view, &_viewProjection);
}
return _viewProjection;
}
void Camera::setAdditionalProjection(const Mat4& mat)
{
_projection = mat * _projection;
getViewProjectionMatrix();
}
bool Camera::initDefault()
{
auto size = Director::getInstance()->getWinSize();
//create default camera
auto projection = Director::getInstance()->getProjection();
switch (projection)
{
case Director::Projection::_2D:
{
initOrthographic(size.width, size.height, -1024, 1024);
setPosition3D(Vec3(0.0f, 0.0f, 0.0f));
setRotation3D(Vec3(0.f, 0.f, 0.f));
break;
}
case Director::Projection::_3D:
{
float zeye = Director::getInstance()->getZEye();
initPerspective(60, (GLfloat)size.width / size.height, 10, zeye + size.height / 2.0f);
Vec3 eye(size.width/2, size.height/2.0f, zeye), center(size.width/2, size.height/2, 0.0f), up(0.0f, 1.0f, 0.0f);
setPosition3D(eye);
lookAt(center, up);
break;
}
default:
CCLOG("unrecognized projection");
break;
}
return true;
}
bool Camera::initPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
{
_fieldOfView = fieldOfView;
_aspectRatio = aspectRatio;
_nearPlane = nearPlane;
_farPlane = farPlane;
Mat4::createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane, &_projection);
_viewProjectionDirty = true;
_frustumDirty = true;
return true;
}
bool Camera::initOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane)
{
_zoom[0] = zoomX;
_zoom[1] = zoomY;
_nearPlane = nearPlane;
_farPlane = farPlane;
Mat4::createOrthographicOffCenter(0, _zoom[0], 0, _zoom[1], _nearPlane, _farPlane, &_projection);
_viewProjectionDirty = true;
_frustumDirty = true;
return true;
}
Vec2 Camera::project(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);
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;
screenPos.y = (1.0f - (ndcY + 1.0f) * 0.5f) * viewport.height;
return screenPos;
}
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);
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;
screenPos.y = (ndcY + 1.0f) * 0.5f * viewport.height;
return screenPos;
}
Vec3 Camera::unproject(const Vec3& src) const
{
Vec3 dst;
unproject(Director::getInstance()->getWinSize(), &src, &dst);
return dst;
}
Vec3 Camera::unprojectGL(const Vec3& src) const
{
Vec3 dst;
unprojectGL(Director::getInstance()->getWinSize(), &src, &dst);
return dst;
}
void Camera::unproject(const Size& viewport, const Vec3* src, Vec3* dst) const
{
CCASSERT(src && dst, "vec3 can not be null");
Vec4 screen(src->x / viewport.width, ((viewport.height - src->y)) / viewport.height, src->z, 1.0f);
screen.x = screen.x * 2.0f - 1.0f;
screen.y = screen.y * 2.0f - 1.0f;
screen.z = screen.z * 2.0f - 1.0f;
getViewProjectionMatrix().getInversed().transformVector(screen, &screen);
if (screen.w != 0.0f)
{
screen.x /= screen.w;
screen.y /= screen.w;
screen.z /= screen.w;
}
dst->set(screen.x, screen.y, screen.z);
}
void Camera::unprojectGL(const Size& viewport, const Vec3* src, Vec3* dst) const
{
CCASSERT(src && dst, "vec3 can not be null");
Vec4 screen(src->x / viewport.width, src->y / viewport.height, src->z, 1.0f);
screen.x = screen.x * 2.0f - 1.0f;
screen.y = screen.y * 2.0f - 1.0f;
screen.z = screen.z * 2.0f - 1.0f;
getViewProjectionMatrix().getInversed().transformVector(screen, &screen);
if (screen.w != 0.0f)
{
screen.x /= screen.w;
screen.y /= screen.w;
screen.z /= screen.w;
}
dst->set(screen.x, screen.y, screen.z);
}
bool Camera::isVisibleInFrustum(const AABB* aabb) const
{
if (_frustumDirty)
{
_frustum.initFrustum(this);
_frustumDirty = false;
}
return !_frustum.isOutOfFrustum(*aabb);
}
float Camera::getDepthInView(const Mat4& transform) const
{
Mat4 camWorldMat = getNodeToWorldTransform();
const Mat4 &viewMat = camWorldMat.getInversed();
float depth = -(viewMat.m[2] * transform.m[12] + viewMat.m[6] * transform.m[13] + viewMat.m[10] * transform.m[14] + viewMat.m[14]);
return depth;
}
void Camera::setDepth(int8_t depth)
{
if (_depth != depth)
{
_depth = depth;
if (_scene)
{
//notify scene that the camera order is dirty
_scene->setCameraOrderDirty();
}
}
}
void Camera::onEnter()
{
if (_scene == nullptr)
{
auto scene = getScene();
if (scene)
{
setScene(scene);
}
}
Node::onEnter();
}
void Camera::onExit()
{
// remove this camera from scene
setScene(nullptr);
Node::onExit();
}
// 設置成當前的場景,把之前的場景刪除掉,並且把自己加入到場景的照相機當中
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);
//notify scene that the camera order is dirty
_scene->setCameraOrderDirty();
}
}
}
}
void Camera::clearBackground()
{
if (_clearBrush)
{
_clearBrush->drawBackground(this);
}
}
void Camera::setFrameBufferObject(experimental::FrameBuffer *fbo)
{
CC_SAFE_RETAIN(fbo);
CC_SAFE_RELEASE_NULL(_fbo);
_fbo = fbo;
if(_scene)
{
_scene->setCameraOrderDirty();
}
}
void Camera::applyFrameBufferObject()
{
if(nullptr == _fbo)
{
experimental::FrameBuffer::applyDefaultFBO();
}
else
{
_fbo->applyFBO();
}
}
void Camera::apply()
{
applyFrameBufferObject();
applyViewport();
}
void Camera::applyViewport()
{
if(nullptr == _fbo)
{
glViewport(getDefaultViewport()._left, getDefaultViewport()._bottom, getDefaultViewport()._width, getDefaultViewport()._height);
}
else
{
glViewport(_viewport._left * _fbo->getWidth(), _viewport._bottom * _fbo->getHeight(),
_viewport._width * _fbo->getWidth(), _viewport._height * _fbo->getHeight());
}
}
int Camera::getRenderOrder() const
{
int result(0);
if(_fbo)
{
result = _fbo->getFID()<<8;
}
else
{
result = 127 <<8;
}
result += _depth;
return result;
}
void Camera::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags)
{
_viewProjectionUpdated = _transformUpdated;
return Node::visit(renderer, parentTransform, parentFlags);
}
void Camera::setBackgroundBrush(CameraBackgroundBrush* clearBrush)
{
CC_SAFE_RETAIN(clearBrush);
CC_SAFE_RELEASE(_clearBrush);
_clearBrush = clearBrush;
}
bool Camera::isBrushValid()
{
return _clearBrush != nullptr && _clearBrush->isValid();
}
暫時就這些。