獲取示例代碼
上一篇文章中說到了透視和正交兩種投影矩陣,文末提到了三個(gè)基本矩陣MVP恩伺。本文就以介紹MVP為開頭,然后再詳細(xì)講解攝像機(jī)的概念。
MVP表示的是模型矩陣(Model)蒸播,觀察矩陣(View)全景,投影矩陣(Projection)邪意。投影矩陣介紹過了。模型矩陣針對(duì)的是單個(gè)3D模型泰演,渲染每一個(gè)3D模型前,需要將各自的模型矩陣傳遞給Vertex Shader葱轩。觀察矩陣針對(duì)的是場景中的所有物體睦焕,當(dāng)觀察矩陣改變時(shí),所有頂點(diǎn)的位置都會(huì)受到影響靴拱,就好像你移動(dòng)現(xiàn)實(shí)世界的攝像機(jī)垃喊,拍攝到的場景就會(huì)變化一樣。所以觀察矩陣可以理解為OpenGL 3D世界中的攝像機(jī)袜炕。我們有了攝像機(jī)這個(gè)變換矩陣之后缔御,就可以很方便的在3D世界中游覽,就像第一人稱視角游戲中一樣妇蛀。
大概了解MVP之后耕突,我們開始使用代碼實(shí)現(xiàn)它們。首先要修改一下Vertex Shader评架。
attribute vec4 position;
attribute vec4 color;
uniform float elapsedTime;
uniform mat4 projectionMatrix;
uniform mat4 cameraMatrix;
uniform mat4 modelMatrix;
varying vec4 fragColor;
void main(void) {
fragColor = color;
mat4 mvp = projectionMatrix * cameraMatrix * modelMatrix;
gl_Position = mvp * position;
}
我把之前的uniform transform
換成了三個(gè)變換矩陣projectionMatrix
,cameraMatrix
,modelMatrix
,它們分別是投影矩陣眷茁,觀察矩陣,模型矩陣纵诞。將它們相乘projectionMatrix * cameraMatrix * modelMatrix
上祈,結(jié)果乘以position
賦值給gl_Position
。注意相乘的順序浙芙,這個(gè)順序的結(jié)果是先進(jìn)行模型矩陣變換登刺,再是觀察矩陣,最后是投影矩陣變換嗡呼。這樣Vertex Shader中的MVP就實(shí)現(xiàn)完了纸俭,很簡單是不是。
回到OC代碼南窗,我將之前的屬性transform換成了4個(gè)變換矩陣揍很,分別是兩個(gè)M和VP郎楼。本文的例子將繪制兩個(gè)矩形,所以我為它們分別定義了模型矩陣modelMatrix1
和modelMatrix2
窒悔。
@property (assign, nonatomic) GLKMatrix4 projectionMatrix; // 投影矩陣
@property (assign, nonatomic) GLKMatrix4 cameraMatrix; // 觀察矩陣
@property (assign, nonatomic) GLKMatrix4 modelMatrix1; // 第一個(gè)矩形的模型變換
@property (assign, nonatomic) GLKMatrix4 modelMatrix2; // 第二個(gè)矩形的模型變換
接下來初始化這些屬性呜袁。
// 使用透視投影矩陣
float aspect = self.view.frame.size.width / self.view.frame.size.height;
self.projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90), aspect, 0.1, 100.0);
// 設(shè)置攝像機(jī)在 0,0简珠,2 坐標(biāo)阶界,看向 0,0聋庵,0點(diǎn)膘融。Y軸正向?yàn)閿z像機(jī)頂部指向的方向
self.cameraMatrix = GLKMatrix4MakeLookAt(0, 0, 2, 0, 0, 0, 0, 1, 0);
// 先初始化矩形1的模型矩陣為單位矩陣
self.modelMatrix1 = GLKMatrix4Identity;
// 先初始化矩形2的模型矩陣為單位矩陣
self.modelMatrix2 = GLKMatrix4Identity;
投影矩陣使用了透視投影進(jìn)行初始化。兩個(gè)模型矩陣初始化為單位矩陣珍策。本文的主角觀察矩陣初始化為攝像機(jī)在 0托启,0,2 坐標(biāo)攘宙,看向 0屯耸,0,0點(diǎn)蹭劈,向上朝向0疗绣,1,0铺韧。GLKMatrix4MakeLookAt
提供了快捷創(chuàng)建觀察矩陣的方法多矮,需要傳遞9個(gè)參數(shù),攝像機(jī)的位置eyeX哈打,eyeY塔逃,eyeZ,攝像機(jī)看向的點(diǎn)centerX料仗,centerY湾盗,centerZ,攝像機(jī)向上的朝向upX, upY, upZ立轧。改變這幾個(gè)參數(shù)就能控制攝像機(jī)在3D世界中通過不同角度拍攝物體格粪。
我把上一篇的剖面示意圖做了一下修改。
圖中的lookAt就是center氛改。
我們可以這么理解觀察矩陣帐萎。在觀察矩陣的作用下,透視矩陣的原點(diǎn)變成了攝像機(jī)的位置eye胜卤。up決定了攝像機(jī)圍繞eye和lookAt形成的軸(本例中就是Z軸)的旋轉(zhuǎn)角度疆导,讀者可以修改本例的中的up值看看效果。lookAt決定了攝像機(jī)能看到的區(qū)域瑰艘,可以看做是控制攝像機(jī)在Y軸和X軸上的旋轉(zhuǎn)角度是鬼。
在第一人稱的游戲中肤舞,只要控制lookAt的位置就可以實(shí)現(xiàn)360度查看周邊景物的效果紫新,后面介紹到渲染3D場景的時(shí)候會(huì)深入講解均蜜。
初始化完后在update中為這些矩陣賦新的值。
- (void)update {
[super update];
float varyingFactor = (sin(self.elapsedTime) + 1) / 2.0; // 0 ~ 1
self.cameraMatrix = GLKMatrix4MakeLookAt(0, 0, 2 * (varyingFactor + 1), 0, 0, 0, 0, 1, 0);
GLKMatrix4 translateMatrix1 = GLKMatrix4MakeTranslation(-0.7, 0, 0);
GLKMatrix4 rotateMatrix1 = GLKMatrix4MakeRotation(varyingFactor * M_PI * 2, 0, 1, 0);
self.modelMatrix1 = GLKMatrix4Multiply(translateMatrix1, rotateMatrix1);
GLKMatrix4 translateMatrix2 = GLKMatrix4MakeTranslation(0.7, 0, 0);
GLKMatrix4 rotateMatrix2 = GLKMatrix4MakeRotation(varyingFactor * M_PI, 0, 0, 1);
self.modelMatrix2 = GLKMatrix4Multiply(translateMatrix2, rotateMatrix2);
}
float varyingFactor = (sin(self.elapsedTime) + 1) / 2.0;
的值從0到1芒率。
攝像機(jī)的Z軸坐標(biāo)為2 * (varyingFactor + 1)
囤耳,從2到4。
第一個(gè)矩形向左偏移0.7偶芍,繞Y軸旋轉(zhuǎn)varyingFactor * M_PI * 2
充择,從0到360度。
第二個(gè)矩形向右偏移0.7匪蟀,繞Z軸旋轉(zhuǎn)varyingFactor * M_PI * 2
椎麦,從0到360度。
最后給uniform賦值材彪。
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
[super glkView:view drawInRect:rect];
GLuint projectionMatrixUniformLocation = glGetUniformLocation(self.shaderProgram, "projectionMatrix");
glUniformMatrix4fv(projectionMatrixUniformLocation, 1, 0, self.projectionMatrix.m);
GLuint cameraMatrixUniformLocation = glGetUniformLocation(self.shaderProgram, "cameraMatrix");
glUniformMatrix4fv(cameraMatrixUniformLocation, 1, 0, self.cameraMatrix.m);
GLuint modelMatrixUniformLocation = glGetUniformLocation(self.shaderProgram, "modelMatrix");
// 繪制第一個(gè)矩形
glUniformMatrix4fv(modelMatrixUniformLocation, 1, 0, self.modelMatrix1.m);
[self drawRectangle];
// 繪制第二個(gè)矩形
glUniformMatrix4fv(modelMatrixUniformLocation, 1, 0, self.modelMatrix2.m);
[self drawRectangle];
}
先給uniform projectionMatrix
和uniform cameraMatrix
賦值观挎。每個(gè)矩形繪制之前,再將各自的modelMatrix賦值給uniform modelMatrix
段化,就像開頭說的那樣嘁捷,每個(gè)3D模型有自己的模型變換。
最終效果如下显熏。
本篇主要介紹了攝像機(jī)(觀察矩陣)雄嚣,三大基本矩陣MVP的概念。下一篇小試牛刀喘蟆,開始渲染真正的3D物體-正方體缓升。