矩陣
矩陣是一種功能非常強(qiáng)大的數(shù)學(xué)工具亿遂,它大大簡(jiǎn)化了了求解變量之間有復(fù)雜關(guān)系的方程式或者方程組的過(guò)程已维。矩陣在坐標(biāo)變換中運(yùn)用得非常廣泛。例如:如果在空間有一個(gè)點(diǎn)瓤帚,由x,y和z坐標(biāo)定義涩赢,將它圍繞任意點(diǎn)沿任意方向旋轉(zhuǎn)一定的角度后戈次,我們需要知道這個(gè)點(diǎn)現(xiàn)在的位置,就要用到矩陣筒扒。因?yàn)樾碌膞坐標(biāo)不僅與原來(lái)的x坐標(biāo)和其他旋轉(zhuǎn)參數(shù)有關(guān)怯邪,還與y和z坐標(biāo)值有關(guān)。這種變量與解之間的相關(guān)性就是矩陣最擅長(zhǎng)解決的問(wèn)題花墩。-
基礎(chǔ)變換
由于我們的屏幕是2D的悬秉,在把3D圖形數(shù)據(jù)顯示在2D屏幕上的這個(gè)過(guò)程中,我們需要對(duì)頂點(diǎn)數(shù)據(jù)進(jìn)行幾何變換:視圖變換冰蘑、模型變換和投影變換和泌。變 換 應(yīng) ? 視圖 指定觀察者位置 模型 在場(chǎng)景中移動(dòng)物體 模型視圖 描述視圖/模型變換的?二元性 投影 改變視景體?大?小和設(shè)置它的投影?方式 視口 偽變化,對(duì)窗?口上最終輸出進(jìn)?行行縮放 -
模型視圖矩陣
模型視圖矩陣是一個(gè)4x4矩陣,它表示一個(gè)變換后的坐標(biāo)系祠肥,我們可以用來(lái)放置對(duì)象和確定對(duì)象的方向武氓。我們?yōu)閳D元提供的頂點(diǎn)將作為一個(gè)單列矩陣的形式來(lái)使用,并乘以一個(gè)模型視圖矩陣來(lái)獲得一個(gè)相對(duì)于視覺坐標(biāo)系的經(jīng)過(guò)變換的新坐標(biāo)仇箱。- 我們可以調(diào)用math3d庫(kù)中
m3dTranslationMatrix44
函數(shù)來(lái)使用變換矩陣void m3dTranslationMatrix44(M3DMatrix44f m, float x, float y, float z)
- 旋轉(zhuǎn)
void m3dRotationMatrix44(M3DMatrix44f m, float angle, float x, float y, float z);
- 縮放
void m3dScaleMatrix44(M3DMatrix44f m, float xScale, float yScale, float zScale)
- 綜合變換:將兩個(gè)矩陣相乘并返回結(jié)果
void m3dMatrixMultiply44(M3DMatrix44f product, const M3DMatrix44f a, const M3DMatrix44f b);
提示:如果不知道參數(shù)是什么意思县恕,可以進(jìn)入看源碼,非常的清晰剂桥。
- 我們可以調(diào)用math3d庫(kù)中
-
投影矩陣
投影分為正投影和透視投影忠烛。- 正投影會(huì)產(chǎn)生一個(gè)平行投影,這種投影在繪制從遠(yuǎn)處觀察不產(chǎn)生任何透視縮短的特定物體時(shí)非常有用渊额。
// 用這個(gè)函數(shù)設(shè)置正投影 GLFrustum::SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, GLfloat zMin, GLfloat zMax);
- 透視投影會(huì)有一個(gè)3D效果况木,看起來(lái)更加逼真,渲染3D圖形時(shí)常用透視投影旬迹。
// 用這個(gè)函數(shù)設(shè)置透視投影 GLFrustum::SetPerspective(float fFov, float fAspect, float fNear, float fFar);
- 正投影會(huì)產(chǎn)生一個(gè)平行投影,這種投影在繪制從遠(yuǎn)處觀察不產(chǎn)生任何透視縮短的特定物體時(shí)非常有用渊额。
-
頂點(diǎn)變換管線
原始頂點(diǎn)數(shù)據(jù)到顯示在窗口上的變化過(guò)程火惊,這個(gè)過(guò)程都是用矩陣記錄每一次放射變換,然后應(yīng)用到頂點(diǎn)數(shù)據(jù)上奔垦。
屏幕快照 2019-05-21 22.43.51.png
- 使用矩陣?yán)?/li>
// GLTool.h頭文件包含了大部分GLTool中類似C語(yǔ)言的獨(dú)立函數(shù)
#include "GLTools.h"
// 矩陣?工具類,?用來(lái)快速設(shè)置正/透視投影
#include "GLFrustum.h"
// 三?角形批次類,幫助類,利利?用它可以傳輸頂點(diǎn)/光照/紋理理/顏?色數(shù)據(jù)到存儲(chǔ)著?色器?中
#include "GLBatch.h"
#include "StopWatch.h"
// 數(shù)學(xué)庫(kù)
#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
// 設(shè)置圖元繪制時(shí)的投影方式
GLFrustum viewFrustum;
// 存儲(chǔ)著?色器?管理理?工具類.
GLShaderManager shaderManager;
GLTriangleBatch torusBatch;
// 設(shè)置視口和投影矩陣
void ChangeSize(int w, int h)
{
//防止除以零
if(h == 0)
h = 1;
//將視口設(shè)置為窗口尺寸
glViewport(0, 0, w, h);
//設(shè)置透視投影
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 1000.0f);
}
//召喚場(chǎng)景
void RenderScene(void)
{
//清除屏幕屹耐、深度緩存區(qū)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//1.建立基于時(shí)間變化的動(dòng)畫
static CStopWatch rotTimer;
//當(dāng)前時(shí)間 * 60s
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
//2.矩陣變量
/*
mTranslate: 平移
mRotate: 旋轉(zhuǎn)
mModelview: 模型視圖
mModelViewProjection: 模型視圖投影MVP
*/
M3DMatrix44f mTranslate, mRotate, mModelview, mModelViewProjection;
//創(chuàng)建一個(gè)4*4矩陣變量,將花托沿著Z軸負(fù)方向移動(dòng)2.5個(gè)單位長(zhǎng)度
m3dTranslationMatrix44(mTranslate, 0.0f, 0.0f, -2.5f);
//創(chuàng)建一個(gè)4*4矩陣變量,將花托在Y軸上渲染yRot度惶岭,yRot根據(jù)經(jīng)過(guò)時(shí)間設(shè)置動(dòng)畫幀率
m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);
//為mModerView 通過(guò)矩陣旋轉(zhuǎn)矩陣寿弱、移動(dòng)矩陣相乘,將結(jié)果添加到mModerView上
m3dMatrixMultiply44(mModelview, mTranslate, mRotate);
// 將投影矩陣乘以模型視圖矩陣按灶,將變化結(jié)果通過(guò)矩陣乘法應(yīng)用到mModelViewProjection矩陣上
//注意順序: 投影 * 模型 != 模型 * 投影
m3dMatrixMultiply44(mModelViewProjection, viewFrustum.GetProjectionMatrix(),mModelview);
//繪圖顏色
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
//通過(guò)平面著色器提交矩陣症革,和顏色。
shaderManager.UseStockShader(GLT_SHADER_FLAT, mModelViewProjection, vBlack);
//開始繪圖
torusBatch.Draw();
// 交換緩沖區(qū)鸯旁,并立即刷新
glutSwapBuffers();
glutPostRedisplay();
}
void SetupRC()
{
//1.
glClearColor(0.8f, 0.8f, 0.8f, 1.0f );
shaderManager.InitializeStockShaders();
glEnable(GL_DEPTH_TEST);
//2.形成一個(gè)球
gltMakeSphere(torusBatch, 0.4f, 10, 20);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
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;
}
-
矩陣堆棧介紹
1. 矩陣堆棧常用函數(shù)//這個(gè)類的構(gòu)造函數(shù)允許指定堆棧的最大深度噪矛,默認(rèn)的堆棧深度為64,這個(gè)矩陣堆棧在初始化時(shí)已經(jīng)在堆棧中包含了單元矩陣铺罢。 GLMatrixStack::GLMatrixStack(int iStackDepth = 64); //在堆棧頂部載?一個(gè)單元矩陣 void GLMatrixStack::LoadIdentity(void); //在堆棧頂部載入任何矩陣.參數(shù):4*4矩陣 void GLMatrixStack::LoadMatrix(const M3DMatrix44f m); //矩陣乘以矩陣堆棧頂部矩陣艇挨,相乘結(jié)果存儲(chǔ)到堆棧的頂部 void GLMatrixStack::MultMatrix(const M3DMatrix44f); //使用GetMatrix 函數(shù)獲取矩陣堆棧頂部的值,這個(gè)函數(shù)可以進(jìn)行兩次重載韭赘,以適應(yīng)GLShaderMananger的使?用缩滨,或者僅僅是獲取頂部矩陣的副本 const M3DMatrix44f & GLMatrixStack::GetMatrix(void); void GLMatrixStack::GetMatrix(M3DMatrix44f mMatrix);
- 壓棧.出棧
一個(gè)矩陣的真正價(jià)值在于通過(guò)壓棧操作存儲(chǔ)一個(gè)狀態(tài),然后通過(guò)出椚埃恢復(fù)這個(gè)狀態(tài)脉漏。
//將當(dāng)前矩陣壓?入堆棧 void GLMatrixStack::PushMatrix(void); //將M3DMatrix44f 矩陣對(duì)象壓入當(dāng)前矩陣堆棧 void PushMatrix(const M3DMatrix44f mMatrix); //將GLFame 對(duì)象壓入矩陣對(duì)象 void PushMatrix(GLFame &frame); //出棧(出棧指的是移除頂部的矩陣對(duì)象) void GLMatrixStack::PopMatrix(void);
3.仿射變換
GLMatrixStack類也內(nèi)建了對(duì)創(chuàng)建旋轉(zhuǎn)、平移和縮放矩陣的支持袖牙。相應(yīng)的函數(shù)如下://Rotate 函數(shù)angle參數(shù)是傳遞的度數(shù)鸠删,而不是弧度 void MatrixStack::Rotate(GLfloat angle,GLfloat x,GLfloat y,GLfloat z); void MatrixStack::Translate(GLfloat x,GLfloat y,GLfloat z); void MatrixStack::Scale(GLfloat x,GLfloat y,GLfloat z);
這三個(gè)函數(shù)都可以創(chuàng)建相應(yīng)的矩陣,然后用這個(gè)矩陣乘以矩陣堆棧頂部的元素贼陶,實(shí)際上就是對(duì)當(dāng)前矩陣添加變換刃泡。
- 壓棧.出棧
矩陣堆棧的使用完整例子,代碼如下:
#include "GLTools.h"
#include "GLShaderManager.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLMatrixStack.h"
#include "GLGeometryTransform.h"
#include "StopWatch.h"
#include <math.h>
#include <stdio.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
GLShaderManager shaderManager; // 著色器管理器
GLMatrixStack modelViewMatrix; // 模型視圖矩陣
GLMatrixStack projectionMatrix; // 投影矩陣
GLFrustum viewFrustum; // 視景體
GLGeometryTransform transformPipeline; // 幾何圖形變換管道
GLTriangleBatch torusBatch; // 花托批處理
//角色幀 照相機(jī)角色幀
GLFrame cameraFrame;
void SetupRC()
{
// 初始化著色器管理器
shaderManager.InitializeStockShaders();
//開啟深度測(cè)試
glEnable(GL_DEPTH_TEST);
//設(shè)置清屏顏色到顏色緩存區(qū)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//繪制甜甜圈
gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
}
// 屏幕更改大小或已初始化
void ChangeSize(int nWidth, int nHeight)
{
glViewport(0, 0, nWidth, nHeight);
// 創(chuàng)建投影矩陣碉怔,烘贴。
viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
//并將其加載到投影矩陣堆棧上
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
// 設(shè)置變換管道以使用兩個(gè)矩陣堆棧(變換矩陣modelViewMatrix ,投影矩陣projectionMatrix)
//初始化GLGeometryTransform 的實(shí)例transformPipeline.通過(guò)將它的內(nèi)部指針設(shè)置為模型視圖矩陣堆棧 和 投影矩陣堆棧實(shí)例撮胧,來(lái)完成初始化
//當(dāng)然這個(gè)操作也可以在SetupRC 函數(shù)中完成桨踪,但是在窗口大小改變時(shí)或者窗口創(chuàng)建時(shí)設(shè)置它們并沒有壞處。而且這樣可以一次性完成矩陣和管線的設(shè)置芹啥。
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
//進(jìn)行調(diào)用以繪制場(chǎng)景
void RenderScene(void)
{
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
// 基于時(shí)間動(dòng)畫
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
// 清除顏色緩存區(qū)和深度緩沖區(qū)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//**3锻离、設(shè)置照相機(jī)矩陣
M3DMatrix44f mCamera;
//**3、從camraFrame中獲取一個(gè)4*4的矩陣墓怀;
cameraFrame.GetCameraMatrix(mCamera);
//**3汽纠、將照相機(jī)矩陣壓入模型視圖堆棧中
modelViewMatrix.PushMatrix(mCamera);
// 繪制旋轉(zhuǎn)甜甜圈
//modelViewMatrix 頂部矩陣沿著z軸移動(dòng)2.5單位
modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
modelViewMatrix.PushMatrix();
//modelViewMatrix 頂部矩陣旋轉(zhuǎn)yRot度
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
//使用平面著色器 變換管道中的投影矩陣 和 變換矩陣 相乘的矩陣,指定甜甜圈顏色
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(),vTorusColor);
//開始繪制
torusBatch.Draw();
// 恢復(fù)modelViewMatrix矩陣傀履,移除矩陣堆棧
//使用PopMatrix推出剛剛變換的矩陣虱朵,然后恢復(fù)到單位矩陣
modelViewMatrix.PopMatrix();
//**恢復(fù)矩陣** push跟pop一一對(duì)應(yīng),push幾次就要pop幾次。
modelViewMatrix.PopMatrix();
// 執(zhí)行緩存區(qū)交換
glutSwapBuffers();
// 告訴glut在顯示一遍
glutPostRedisplay();
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800,600);
glutCreateWindow("OpenGL SphereWorld");
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;
}