3D中的相机 - 投影矩阵和视图矩阵
3D中的相机 - 投影矩阵和视图矩阵 3d游戏中,一般通过相机的设置来计算投影矩阵和视图矩阵,比如untiy和cocos,一般情况下我们不用关注如何计算, 可以直接在可视化的编辑器中调整参数就可以了,但是了解下总是好的。 具体计算可以参考: 可以参考现在cocos2dx的代码中的Camera源码,里面有根据相机的设置(位置等)计算上面两个矩阵的代码。 也可以参考下面这个,github上面一个项目,这个项目有很好的参考价值: https://github.com/wantnon2/3DToolKit-2-for-cocos2dx/blob/master/c3dToolKit/core/c3dCamera.h ``` // // c3dCamera.h // HelloCpp // // Created by Yang Chao (wantnon) on 14-1-7. // // #ifndef __HelloCpp__c3dCamera__ #define __HelloCpp__c3dCamera__ #include <iostream> using namespace std; #include "cocos2d.h" using namespace cocos2d; #include "c3dVector.h" #include "c3dMatrix.h" #include "c3dGLMath.h" #include "c3dCommonFunc.h" #include "c3dMatrixStackInfoGetor.h" #include "c3dRange.h" class Cc3dCamera:public CCCamera { public: Cc3dCamera(){ CCSize winSize=CCDirector::sharedDirector()->getWinSize(); m_fovy=60; m_aspect=winSize.width/winSize.height; m_zNear=1;//554/2;//0.5; m_zFar=1500; const float w=winSize.width;//11; const float h=winSize.height;//w*winSize.height/winSize.width; m_range.init(-w/2, -w/2+w, -h/2, -h/2+h, -1024,//yeah, better to use negative value 1024); m_projectionMode=ec3dPerspectiveMode; m_isViewMatDirty=false; m_isViewMatInverseDirty=false; } virtual ~Cc3dCamera(){ } Cc3dVector4 getEyePos()const; Cc3dVector4 getCenter()const; Cc3dVector4 getUp()const; void setEyePos(const Cc3dVector4&eyePos); void setCenter(const Cc3dVector4¢er); void setUp(const Cc3dVector4&up); float getFovy()const {return m_fovy;} float getAspect()const {return m_aspect;} float getzNear()const {return m_zNear;} float getzFar()const {return m_zFar;} void setFovy(float fovy){m_fovy=fovy;} void setAspect(float aspect){m_aspect=aspect;} void setzNear(float zNear){m_zNear=zNear;} void setzFar(float zFar){m_zFar=zFar;} Cc3dRange getRange()const {return m_range;} void setRange(const Cc3dRange&range){m_range=range;} Cc3dMatrix4 calculateViewMat(); Cc3dMatrix4 calculateViewMatInverse(); Cc3dMatrix4 calculateProjectionMat(); Ec3dProjectionMode getProjectionMode(){return m_projectionMode;} void setProjectionMode(Ec3dProjectionMode projectionMode){m_projectionMode=projectionMode;} void applyProjection(); void printProjectionMode()const; protected: //projection mode type Ec3dProjectionMode m_projectionMode; //perspective projection mode params float m_fovy; float m_aspect; float m_zNear; float m_zFar; //Ortho projection mode params Cc3dRange m_range;//in the camera space protected: //cache viewMat Cc3dMatrix4 m_viewMatCache; bool m_isViewMatDirty; Cc3dMatrix4 m_viewMatInverseCache; bool m_isViewMatInverseDirty; }; #endif /* defined(__HelloCpp__c3dCamera__) */ // // c3dCamera.cpp // HelloCpp // // Created by Yang Chao (wantnon) on 14-1-7. // // #include "c3dCamera.h" Cc3dVector4 Cc3dCamera::getEyePos()const{ //getEyeXYZ is not const, but i want getEyePos to be const //so i convert this from const to nonconst float eyex,eyey,eyez; ((Cc3dCamera*)this)->getEyeXYZ(&eyex, &eyey, &eyez); return Cc3dVector4(eyex,eyey,eyez,1); } Cc3dVector4 Cc3dCamera::getCenter()const{ //getCenterXYZ is not const, but i want getCenter to be const //so i convert this from const to nonconst float centerX,centerY,centerZ; ((Cc3dCamera*)this)->getCenterXYZ(¢erX, ¢erY, ¢erZ); return Cc3dVector4(centerX,centerY,centerZ,1); } Cc3dVector4 Cc3dCamera::getUp()const{ //getUpXYZ is not const, but i want getUp to be const //so i convert this from const to nonconst float upX,upY,upZ; ((Cc3dCamera*)this)->getUpXYZ(&upX, &upY, &upZ); return Cc3dVector4(upX,upY,upZ,0); } void Cc3dCamera::setEyePos(const Cc3dVector4&eyePos){ this->setEyeXYZ(eyePos.x(), eyePos.y(), eyePos.z()); m_isViewMatDirty=true; m_isViewMatInverseDirty=true; } void Cc3dCamera::setCenter(const Cc3dVector4¢er){ this->setCenterXYZ(center.x(), center.y(), center.z()); m_isViewMatDirty=true; m_isViewMatInverseDirty=true; } void Cc3dCamera::setUp(const Cc3dVector4&up){ this->setUpXYZ(up.x(), up.y(), up.z()); m_isViewMatDirty=true; m_isViewMatInverseDirty=true; } Cc3dMatrix4 Cc3dCamera::calculateViewMat(){ //why we not just return CCCamera::m_lookupMatrix? //because m_lookupMatrix may be dirty (m_lookupMatrix got updated only when locate is called) //so we calculate view matrix ourselves. Cc3dMatrix4 ret; if(m_isViewMatDirty){//dirty //calculate and cache ret=::calculateViewMatrix(getEyePos(), getCenter(), getUp()); m_viewMatCache=ret; }else{//not dirty //get from cache ret=m_viewMatCache; } return ret; }; Cc3dMatrix4 Cc3dCamera::calculateViewMatInverse(){ Cc3dMatrix4 ret; if(m_isViewMatInverseDirty){ ret=::calculateViewMatrixInverse(getEyePos(), getCenter(), getUp()); m_viewMatInverseCache=ret; }else{ ret=m_viewMatInverseCache; } return ret; } Cc3dMatrix4 Cc3dCamera::calculateProjectionMat(){ Cc3dMatrix4 projectionMat; switch (m_projectionMode) { case ec3dPerspectiveMode: projectionMat=::calculatePerspectiveProjectionMatrix(m_fovy, m_aspect, m_zNear, m_zFar); break; case ec3dOrthographicMode: projectionMat=::calculateOrthoProjectionMatrix(m_range.getMinX(), m_range.getMaxX(), m_range.getMinY(), m_range.getMaxY(), m_range.getMinZ(), m_range.getMaxZ()); break; default: assert(false); break; } return projectionMat; } void Cc3dCamera::applyProjection() //note: after apply projection matrix, will be back to modelview matrix stack { Cc3dMatrix4 projectionMat=calculateProjectionMat(); kmGLMatrixMode(KM_GL_PROJECTION); kmGLLoadIdentity(); kmMat4 projMat; memcpy(projMat.mat, projectionMat.getArray(), 16*sizeof(float)); kmGLMultMatrix(&projMat); //restore to model view stack kmGLMatrixMode(KM_GL_MODELVIEW); }; void Cc3dCamera::printProjectionMode()const{ if(m_projectionMode==ec3dPerspectiveMode){ C3DLOG("projectionMode: perspectiveMode"); }else if(m_projectionMode==ec3dOrthographicMode){ C3DLOG("projectionMode: orthographic"); }else{ assert(false); } } ```
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步