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&center);
    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(&centerX, &centerY, &centerZ);
    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&center){
    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);
    }
}
```

 

posted on 2016-10-09 13:56  ZhYQ_note  阅读(750)  评论(0编辑  收藏  举报

导航