OpenGL藍寶書源碼學習(七)第四章——ModelViewProjection.cpp

模型視圖投影源碼示例

// ModelviewProjection.cpp
// OpenGL SuperBible
// Demonstrates OpenGL the ModelviewProjection matrix
// Program by Richard S. Wright Jr.
#include 	// OpenGL toolkit
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#ifdef __APPLE__
#include 
#else
#define FREEGLUT_STATIC
#include 
#endif


// Global view frustum class
GLFrustum           viewFrustum;

// The shader manager
GLShaderManager     shaderManager;

// The torus
GLTriangleBatch     torusBatch;


// Set up the viewport and the projection matrix
void ChangeSize(int w, int h)
    {
	// Prevent a divide by zero
	if(h == 0)
		h = 1;
    
	// Set Viewport to window dimensions
    glViewport(0, 0, w, h);
    
    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 1000.0f);
    }


// Called to draw scene
void RenderScene(void)
	{
    // Set up time based animation
    static CStopWatch rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
    
	// Clear the window and the depth buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Matrix Variables
    M3DMatrix44f mTranslate, mRotate, mModelview, mModelViewProjection;
    
    // Create a translation matrix to move the torus back and into sight
    m3dTranslationMatrix44(mTranslate, 0.0f, 0.0f, -2.5f);
    
    // Create a rotation matrix based on the current value of yRot
    m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);
    
    // Add the rotation to the translation, store the result in mModelView
    m3dMatrixMultiply44(mModelview, mTranslate, mRotate);
    
    // Add the modelview matrix to the projection matrix, 
    // the final matrix is the ModelViewProjection matrix.
    m3dMatrixMultiply44(mModelViewProjection, viewFrustum.GetProjectionMatrix(),mModelview);
		
    // Pass this completed matrix to the shader, and render the torus
    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mModelViewProjection, vBlack);  
    torusBatch.Draw();


    // Swap buffers, and immediately refresh
    glutSwapBuffers();
    glutPostRedisplay();
	}

// This function does any needed initialization on the rendering
// context. 
void SetupRC()
	{
	// Black background
	glClearColor(0.8f, 0.8f, 0.8f, 1.0f );

    glEnable(GL_DEPTH_TEST);

    shaderManager.InitializeStockShaders();
  
    // This makes a torus
    gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);


    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}


///////////////////////////////////////////////////////////////////////////////
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
    {
	gltSetWorkingDirectory(argv[0]);
	
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
	glutInitWindowSize(800, 600);
	glutCreateWindow("ModelViewProjection Example");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
        
    
	GLenum err = glewInit();
	if (GLEW_OK != err) {
		fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
		return 1;
        }
	
	SetupRC();
    
	glutMainLoop();
	return 0;
    }

此源碼示例可以幫助我們理解模型、視圖和投影,相應的座標系及變換等。同時需要學習的是一些向量、矩陣等一些數學知識。

前述:

此示例作爲藍寶書第四章的第一個源碼示例,第三章的Primitives.cpp示例暫時先跳過,由於Primitives.cpp裏面涉及了第四章的知識點,所以在後面的學習在着重解析一下,可以更好的理解模型視圖投影的變換和照相機和角色的移動等知識。並且在GeoTest.cpp示例中已經大概地學習了一些模型視圖投影的知識,忘記了可以回顧一下

http://blog.csdn.net/perseverancep/article/details/72639777。但是此次來加深學習理解3D圖形的數學知識。

一、3D圖形數學基礎

在GeoTest.cpp示例中粗略地學習了一下角色參考幀(GLFrame)、平截頭體(GLFrustum)、矩陣堆棧(GLMatrixStack)等類型概念,然後這些重要的知識點都與最基本的數學知識——矩陣分不開。

1、向量

math3d庫有兩個數據類型,能夠表示一個三維或四維向量:M3DVector3f表示一個三維向量(X,Y,Z),M3DVector4可以表示一個(X,Y,Z,W)。典型情況下W座標設爲1.0。X、Y、Z值通過除以W來進行縮放,而除以1.0則本質上不改變XYZ的值。要將它們定義成數組,只需如下操作。

typedef float M3DVector3f[3]; typedef float M3DVector4f[4];

三分量聲明:

M3DVector3f  vVector;

四分量聲明並初始化:

M3DVector4f vVertex = {0.0f,0.0f,1.0f,1.0f}

點乘:

float m3dDotProduct3(contst M3DVector3f u,const M3DVector3f v);  參數是兩個3分量的單位向量,結果是一個標量(一個值)

兩個單位向量之間的點乘的結果是兩個向量之間的夾角的餘弦值,返回的結果將在-1.0和+1.0範圍之內。在後面的學習中,表面法向量和指向光源的向量之間會大量進行這種運算。

叉乘:

void m3dCrossProduct3(M3DVector3f result,const M3DVector3f u, const M3DVector3f v);參數1是叉乘的結果,參數2、3是進行叉乘的兩個向量

兩個向量之間叉乘所得結果是另一個向量,新向量與原來兩個向量定義的平面垂直。要進行叉乘,這兩個向量都不必爲單位向量。叉乘的順序非常的重要。從尋找三角形便面法線到構造變換矩陣,叉乘的應用數不勝數。

2、矩陣

在數學上,矩陣只不過是一組排列在統一的行和列中的數字而已——用程序設計的語言來說就是一個2維數組。在math3d庫中也有3x3和4x4矩陣類型:

typedef float M3DMatrix33f[9];

typedef float M3DMatrix44[16];

 可以聲明:M3DMatrix33  matrix1;M3DMatrix44  matrix2;

二、理解變換

大多數3D圖形其實並不是真正的3D的。只是使用3D概念和術語來描述物體,將3D數據被“壓扁”到一個2D的計算機屏幕上。這種將3D數據被“壓扁”成2D數據的處理過程叫投影。

1、視覺座標是相對於觀察者視角而言的,無論可能進行何種變換,我們都可以將它們視爲“絕對的”屏幕座標。

2、視圖變換是應用到場景中的第一種變換。它用來確定場景中的有利位置。視圖變換允許我們把觀察點放在所希望的任何位置,並允許在任何方向上觀察場景。確定視圖    就像在場景中防止照相機並讓它指向某個方向。從大局考慮,在應用任何其他模型變換之前,必須先應用視圖變換。這樣做是因爲,視圖變換移動了當前的工作座標系。

3、模型變換用於操縱模型和其中的特定對象。這些變換將對象移動到需要的位置,然後再對它進行旋轉和縮放。

4、視圖的二元性。實際上,視圖和模型變換按照它們的內部效果和對場景的最終外觀來說是一樣的。將兩者區分開純粹是爲了程序員的方便。將對象向後移動和將參考系

向前移動在視覺上沒有區別。視覺變換和模型變換一樣,都應用在整個場景中,在場景中的對象常常在進行視圖變換後單獨進行模型變換。術語“模型視圖”是指這兩種

變換在變換管線中進行組合,成爲一個單獨的矩陣,及模型視圖矩陣。

5、投影變換將在模型視圖變換之後應用到頂點上。這種投影實際上定義了視景體並創建了裁剪平面。

6、視口變換是把二維投影的圖形映射到屏幕上某處的窗口上。這種到物理窗口的映射是我們最後要做的變換,成爲視口變換。視口變換會將“規範化”設備座標重新映射到窗口座標上。

三、模型視圖矩陣

模型視圖矩陣是一個4x4矩陣,它表示變換後的座標系,我們可以用來設置對象和確定對象的方向。爲圖元提供的頂點將作爲一個單列矩陣的形式來使用,並乘以一個模型

視圖矩陣來獲得一個相對於視覺座標的經過變換的新座標。

1、單位矩陣

快捷創建方式:void m3dLoadIdentity44(M3DMatrix44f  m)

2、創建平移矩陣

void m3dTranslationMatrix44(M3DMatrix44f m,float x,float y,float z);

一個平移矩陣僅僅是將我們的頂點沿着3個座標軸的一個或多個進行平移。

3、創建旋轉矩陣

void m3dRotationMatrix44(M3DMatrix44f m,float angle,float x,float y,float z)

圍繞一個x、y和z變量指定的向量來進行旋轉。旋轉的角度沿逆時針方向按照弧度計算,由變量angle指定。可以圍繞一個軸進行旋轉,也可以圍繞任意一個由x、y、和z變量指定的向量來進行旋轉。

4、創建縮放矩陣

void m3dScaleMatrix44(M3DMatrix44f m,float xScale,float yScale,float zScale)

縮放矩陣可以沿着3個座標軸方向按照指定因子放大或縮小所有頂頂啊,以改變對象的大小。

5、綜合變換

將兩種變換加在加在一起就是綜合變換,只需將兩個矩陣相乘

void m3dMatrixMultiply44(M3DMatrix44f product,const M3DMatrix44f a,const M3DMatrix b)

四、部分源碼解析

1、void RenderScene(void)

//聲明一個測量運行時間的對象,並根據時間來設定旋轉的角度值

    static CStopWatch rotTimer;
    float yRot = rotTimer.GetElapsedSeconds() * 60.0f;

//清除顏色和深度緩衝器

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//聲明矩陣局部變量

M3DMatrix44f mTranslate, mRotate, mModelview, mModelViewProjection;

//創建一個平移矩陣(沿z軸向面向觀察者方向移動)

m3dTranslationMatrix44(mTranslate, 0.0f, 0.0f, -2.5f);

//創建一個旋轉矩陣(按時間的運行時間設定弧度值,繞y軸旋轉)

m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);

//將平移矩陣和旋轉矩陣相乘得到一個綜合矩陣(模型矩陣)

m3dMatrixMultiply44(mModelview, mTranslate, mRotate);

//將投影矩陣和模型視圖矩陣相乘得到模型視圖投影矩陣

m3dMatrixMultiply44(mModelViewProjection, viewFrustum.GetProjectionMatrix(),mModelview);

//把模型視圖投影矩陣提交給着色器,並且把圖形批次圖元也提交給着色器進行渲染

    GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
   
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mModelViewProjection, vBlack);  
    torusBatch.Draw();

//交換緩衝區,刷新顯示

    glutSwapBuffers();
    glutPostRedisplay();

五、小結

以上剪短的源碼示例,展示了矩陣變換的應用,應該多結合源碼理解模式視圖投影的變換及應用。可以結合GeoTest.cpp源碼示例理解記憶。

http://blog.csdn.net/perseverancep/article/details/72639777

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