cocos2D-X源碼分析之從cocos2D-X學習OpenGL(10)----MVP矩陣

       上一篇介紹了openGL的變換和座標系,本篇就介紹遊戲引擎中一個重要的概念-MVP矩陣,首先涉及到透視投影和正交投影的概念,關於這個概念請參考之前的文章(文章地址:http://blog.csdn.net/bill_man/article/details/48199593),其中介紹了透視投影和正交投影的概念。

       上一篇文章介紹了MVP矩陣的概念,但是並沒有在代碼上涉及。

        在cocos2d-x中的GLProgram類中,有一個統一設置uniform變量的地方(如果你已經忘記了uniform變量,請翻閱之前的教程),那就是setUniformsForBuiltins函數,它會在onDraw函數調用時被調用:

auto glProgram = getGLProgram();
glProgram->use();
glProgram->setUniformsForBuiltins(transform);
       注意,當你要爲uniform設置值得時候,一定要保持那個着色器正被使用,而當你調用glGetUniformLocation並不需要,cocos2d-x做了一個整理統一,首先,這些經常會被使用的uniform變量,比如mvp變量:

void main()
{
    v_color = vec4(a_color.rgb * a_color.a, a_color.a);
    v_texcoord = a_texcoord;

    gl_Position = CC_MVPMatrix * a_position;
}
      這種大寫字母開頭,並且是CC開頭的,都是統一名字的uniform變量,第二,cocos2d-x把shader的處理高度的歸類統一化,首先是在updateUniforms獲取這些uniform變量變量,而且這個函數只在着色器創建或改變時才被調用,並且這個函數中會獲得這些uniform有沒有在着色器中使用,這節約了效率
    //獲取uniform位置
    _builtInUniforms[UNIFORM_AMBIENT_COLOR] = glGetUniformLocation(_program, UNIFORM_NAME_AMBIENT_COLOR);
    _builtInUniforms[UNIFORM_P_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_P_MATRIX);
    _builtInUniforms[UNIFORM_MV_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MV_MATRIX);
    _builtInUniforms[UNIFORM_MVP_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MVP_MATRIX);
    _builtInUniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_NORMAL_MATRIX);

    _builtInUniforms[UNIFORM_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_TIME);
    _builtInUniforms[UNIFORM_SIN_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_SIN_TIME);
    _builtInUniforms[UNIFORM_COS_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_COS_TIME);

    _builtInUniforms[UNIFORM_RANDOM01] = glGetUniformLocation(_program, UNIFORM_NAME_RANDOM01);

    _builtInUniforms[UNIFORM_SAMPLER0] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER0);
    _builtInUniforms[UNIFORM_SAMPLER1] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER1);
    _builtInUniforms[UNIFORM_SAMPLER2] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER2);
    _builtInUniforms[UNIFORM_SAMPLER3] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER3);
    //判斷是否使用了
    _flags.usesP = _builtInUniforms[UNIFORM_P_MATRIX] != -1;
    _flags.usesMV = _builtInUniforms[UNIFORM_MV_MATRIX] != -1;
    _flags.usesMVP = _builtInUniforms[UNIFORM_MVP_MATRIX] != -1;
    _flags.usesNormal = _builtInUniforms[UNIFORM_NORMAL_MATRIX] != -1;
    _flags.usesTime = (
                       _builtInUniforms[UNIFORM_TIME] != -1 ||
                       _builtInUniforms[UNIFORM_SIN_TIME] != -1 ||
                       _builtInUniforms[UNIFORM_COS_TIME] != -1
                       );
    _flags.usesRandom = _builtInUniforms[UNIFORM_RANDOM01] != -1;
       因爲glGetUniformLocation在找不到相應變量時會返回-1,所以這裏用這個來判斷uniform是否被使用。然後在setUniformsForBuiltins設置這些uniform:

    if (_flags.usesP)
        setUniformLocationWithMatrix4fv(_builtInUniforms[UNIFORM_P_MATRIX], matrixP.m, 1);

    if (_flags.usesMV)
        setUniformLocationWithMatrix4fv(_builtInUniforms[UNIFORM_MV_MATRIX], matrixMV.m, 1);

    if (_flags.usesMVP) {
        Mat4 matrixMVP = matrixP * matrixMV;
        setUniformLocationWithMatrix4fv(_builtInUniforms[UNIFORM_MVP_MATRIX], matrixMVP.m, 1);
    }
       

       每個本地座標轉換爲裁剪座標,都有要和MVP矩陣相乘,然後在裁剪空間中被計算成標準設備座標,從而映射到屏幕上,cocos2d-x中Model和View矩陣一般被結合在了一起,在visit函數中被父子節點之間傳遞,當在這一幀內調用了設置位置,縮放,旋轉等函數,就會調用getNodeToParentTransform函數修改MV矩陣。

       而投影矩陣則有Director中的setProjection函數控制,在之其中會區分2D和3D做不同的處理,

    switch (projection)
    {
        case Projection::_2D:
        {
            loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

            Mat4 orthoMatrix;
            Mat4::createOrthographicOffCenter(0, size.width, 0, size.height, -1024, 1024, &orthoMatrix);
            multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, orthoMatrix);
            loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
            break;
        }
            
        case Projection::_3D:
        {
            float zeye = this->getZEye();

            Mat4 matrixPerspective, matrixLookup;

            loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

            // issue #1334
            Mat4::createPerspective(60, (GLfloat)size.width/size.height, 10, zeye+size.height/2, &matrixPerspective);

            multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, matrixPerspective);

            Vec3 eye(size.width/2, size.height/2, zeye), center(size.width/2, size.height/2, 0.0f), up(0.0f, 1.0f, 0.0f);
            Mat4::createLookAt(eye, center, up, &matrixLookup);
            multiplyMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION, matrixLookup);
            
            loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
            break;
        }

        case Projection::CUSTOM:
            // Projection Delegate is no longer needed
            // since the event "PROJECTION CHANGED" is emitted
            break;

        default:
            CCLOG("cocos2d: Director: unrecognized projection");
            break;
    }
       可以看到2D和3D其實就是正交投影和透視投影的不同處理,createOrthographicOffCenter函數創建了一個正交投影矩陣,並把它傳到最後一個參數的地址,前四個參數第一個視錐的矩形,第五個參數和第六個參數定義了近平面和遠平面的大小。同樣的createPerspective函數創建了一個透視投影矩陣,第一個參數是視角的角度,第二個參數是寬高比,第三個參數和第四個參數分別定義了近平面和遠平面。不同的是透視投影這個矩陣的處理,下面加了一個眼睛位置,並且通過眼睛位置獲得了一個矩陣,其實一般的處理裏,這應該算作View矩陣的範疇,cocos2d-x把這個矩陣放在這裏可能有自己的原因,或者是歷史問題吧,至於這個函數中的三個參數,會在介紹攝像機時詳細介紹。

      下一篇介紹攝像機


      能力不足,水平有限,如有錯誤,歡迎指出。












發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章