學習OpenGL ES之攝像機

本系列所有文章目錄

獲取示例代碼


上一篇文章中說到了透視和正交兩種投影矩陣,文末提到了三個基本矩陣MVP。本文就以介紹MVP為開頭,然后再詳細講解攝像機的概念。
MVP表示的是模型矩陣(Model),觀察矩陣(View),投影矩陣(Projection)。投影矩陣介紹過了。模型矩陣針對的是單個3D模型,渲染每一個3D模型前,需要將各自的模型矩陣傳遞給Vertex Shader。觀察矩陣針對的是場景中的所有物體,當觀察矩陣改變時,所有頂點的位置都會受到影響,就好像你移動現實世界的攝像機,拍攝到的場景就會變化一樣。所以觀察矩陣可以理解為OpenGL 3D世界中的攝像機。我們有了攝像機這個變換矩陣之后,就可以很方便的在3D世界中游覽,就像第一人稱視角游戲中一樣。
大概了解MVP之后,我們開始使用代碼實現它們。首先要修改一下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換成了三個變換矩陣projectionMatrix,cameraMatrix,modelMatrix,它們分別是投影矩陣,觀察矩陣,模型矩陣。將它們相乘projectionMatrix * cameraMatrix * modelMatrix,結果乘以position賦值給gl_Position。注意相乘的順序,這個順序的結果是先進行模型矩陣變換,再是觀察矩陣,最后是投影矩陣變換。這樣Vertex Shader中的MVP就實現完了,很簡單是不是。

回到OC代碼,我將之前的屬性transform換成了4個變換矩陣,分別是兩個M和VP。本文的例子將繪制兩個矩形,所以我為它們分別定義了模型矩陣modelMatrix1modelMatrix2

@property (assign, nonatomic) GLKMatrix4 projectionMatrix; // 投影矩陣
@property (assign, nonatomic) GLKMatrix4 cameraMatrix; // 觀察矩陣
@property (assign, nonatomic) GLKMatrix4 modelMatrix1; // 第一個矩形的模型變換
@property (assign, nonatomic) GLKMatrix4 modelMatrix2; // 第二個矩形的模型變換

接下來初始化這些屬性。

    // 使用透視投影矩陣
    float aspect = self.view.frame.size.width / self.view.frame.size.height;
    self.projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90), aspect, 0.1, 100.0);
    
    // 設置攝像機在 0,0,2 坐標,看向 0,0,0點。Y軸正向為攝像機頂部指向的方向
    self.cameraMatrix = GLKMatrix4MakeLookAt(0, 0, 2, 0, 0, 0, 0, 1, 0);
    
    // 先初始化矩形1的模型矩陣為單位矩陣
    self.modelMatrix1 = GLKMatrix4Identity;
    // 先初始化矩形2的模型矩陣為單位矩陣
    self.modelMatrix2 = GLKMatrix4Identity;

投影矩陣使用了透視投影進行初始化。兩個模型矩陣初始化為單位矩陣。本文的主角觀察矩陣初始化為攝像機在 0,0,2 坐標,看向 0,0,0點,向上朝向0,1,0。GLKMatrix4MakeLookAt提供了快捷創建觀察矩陣的方法,需要傳遞9個參數,攝像機的位置eyeX,eyeY,eyeZ,攝像機看向的點centerX,centerY,centerZ,攝像機向上的朝向upX, upY, upZ。改變這幾個參數就能控制攝像機在3D世界中通過不同角度拍攝物體。
我把上一篇的剖面示意圖做了一下修改。

圖中的lookAt就是center。

我們可以這么理解觀察矩陣。在觀察矩陣的作用下,透視矩陣的原點變成了攝像機的位置eye。up決定了攝像機圍繞eye和lookAt形成的軸(本例中就是Z軸)的旋轉角度,讀者可以修改本例的中的up值看看效果。lookAt決定了攝像機能看到的區域,可以看做是控制攝像機在Y軸和X軸上的旋轉角度。

在第一人稱的游戲中,只要控制lookAt的位置就可以實現360度查看周邊景物的效果,后面介紹到渲染3D場景的時候會深入講解。

初始化完后在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。
攝像機的Z軸坐標為2 * (varyingFactor + 1),從2到4。
第一個矩形向左偏移0.7,繞Y軸旋轉varyingFactor * M_PI * 2,從0到360度。
第二個矩形向右偏移0.7,繞Z軸旋轉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");
    // 繪制第一個矩形
    glUniformMatrix4fv(modelMatrixUniformLocation, 1, 0, self.modelMatrix1.m);
    [self drawRectangle];
    
    // 繪制第二個矩形
    glUniformMatrix4fv(modelMatrixUniformLocation, 1, 0, self.modelMatrix2.m);
    [self drawRectangle];
}

先給uniform projectionMatrixuniform cameraMatrix賦值。每個矩形繪制之前,再將各自的modelMatrix賦值給uniform modelMatrix,就像開頭說的那樣,每個3D模型有自己的模型變換。

最終效果如下。

本篇主要介紹了攝像機(觀察矩陣),三大基本矩陣MVP的概念。下一篇小試牛刀,開始渲染真正的3D物體-正方體。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容