在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Android/ 3D 繪圖基本概念
3D 繪圖基本概念
概述
真正的 3D 圖形
添加顏色
3D 坐標(biāo)變換
構(gòu)造
材質(zhì)渲染

3D 繪圖基本概念

前面介紹了使用 Android 編寫 OpenGL ES 應(yīng)用的程序框架,本篇介紹3D繪圖的一些基本構(gòu)成要素,最終將實(shí)現(xiàn)一個(gè)多邊形的繪制。

一個(gè) 3D 圖形通常是由一些小的基本元素(頂點(diǎn),邊,面,多邊形)構(gòu)成,每個(gè)基本元素都可以單獨(dú)來操作。

Vertex (頂點(diǎn))

頂點(diǎn)是 3D 建模時(shí)用到的最小構(gòu)成元素,頂點(diǎn)定義為兩條或是多條邊交會(huì)的地方。在 3D 模型中一個(gè)頂點(diǎn)可以為多條邊,面或是多邊形所共享。一個(gè)頂點(diǎn)也可以代表一個(gè)點(diǎn)光源或是 Camera 的位置。下圖中標(biāo)識(shí)為黃色的點(diǎn)為一個(gè)頂點(diǎn)(Vertex)。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/1.png" alt="" />

在 Android 系統(tǒng)中可以使用一個(gè)浮點(diǎn)數(shù)數(shù)組來定義一個(gè)頂點(diǎn),浮點(diǎn)數(shù)數(shù)組通常放在一個(gè) Buffer(java.nio)中來提高性能。

比如:下圖中定義了四個(gè)頂點(diǎn)和對應(yīng)的 Android 頂點(diǎn)定義:

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/2.png" alt="" />

private float vertices[] = {
 -1.0f,  1.0f, 0.0f,  // 0, Top Left
 -1.0f, -1.0f, 0.0f,  // 1, Bottom Left
 1.0f, -1.0f, 0.0f,  // 2, Bottom Right
 1.0f,  1.0f, 0.0f,  // 3, Top Right
};  

為了提高性能,通常將這些數(shù)組存放到 java.io 中定義的 Buffer 類中:

// a float is 4 bytes, therefore we multiply the
//number if vertices with 4.
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);  

有了頂點(diǎn)的定義,下面一步就是如何將它們傳給 OpenGL ES 庫,OpenGL ES 提供一個(gè)成為”管道 Pipeline ”的機(jī)制,這個(gè)管道定義了一些“開關(guān)”來控制 OpenGL ES 支持的某些功能,缺省情況這些功能是關(guān)閉的,如果需要使用 OpenGL ES 的這些功能,需要明確告知 OpenGL “管道”打開所需功能。因此對于我們的這個(gè)示例,需要告訴 OpenGL 庫打開 Vertex buffer 以便傳入頂點(diǎn)坐標(biāo) Buffer。要注意的使用完某個(gè)功能之后,要關(guān)閉這個(gè)功能以免影響后續(xù)操作:

// Enabled the vertex buffer for writing and to be used during rendering.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.
// Specifies the location and data format of an array of vertex
// coordinates to use when rendering.
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); // OpenGL docs.
When you are done with the buffer don't forget to disable it.
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.  

Edge(邊)

邊定義為兩個(gè)頂點(diǎn)之間的線段。邊是面和多邊形的邊界線。在 3D 模型中,邊可以被相鄰的兩個(gè)面或是多邊形形共享。對一個(gè)邊做變換將影響邊相接的所有頂點(diǎn),面或多邊形。在 OpenGL 中,通常無需直接來定義一個(gè)邊,而是通過頂點(diǎn)定義一個(gè)面,從而由面定義了其所對應(yīng)的三條邊??梢酝ㄟ^修改邊的兩個(gè)頂點(diǎn)來更改一條邊,下圖黃色的線段代表一條邊:

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/3.png" alt="" />

Face (面)

在 OpenGL ES 中,面特指一個(gè)三角形,由三個(gè)頂點(diǎn)和三條邊構(gòu)成,對一個(gè)面所做的變化影響到連接面的所有頂點(diǎn)和邊,面多邊形。下圖黃色區(qū)域代表一個(gè)面。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/4.png" alt="" />

定義面的頂點(diǎn)的順序很重要 在拼接曲面的時(shí)候,用來定義面的頂點(diǎn)的順序非常重要,因?yàn)轫旤c(diǎn)的順序定義了面的朝向(前向或是后向),為了獲取繪制的高性能,一般情況不會(huì)繪制面的前面和后面,只繪制面的“前面”。雖然“前面”“后面”的定義可以應(yīng)人而易,但一般為所有的“前面”定義統(tǒng)一的頂點(diǎn)順序(順時(shí)針或是逆時(shí)針方向)。

下面代碼設(shè)置逆時(shí)針方法為面的“前面”:

gl.glFrontFace(GL10.GL_CCW);  

打開 忽略“后面”設(shè)置:

gl.glEnable(GL10.GL_CULL_FACE);  

明確指明“忽略“哪個(gè)面的代碼如下:

gl.glCullFace(GL10.GL_BACK);  

Polygon (多邊形)

多邊形由多個(gè)面(三角形)拼接而成,在三維空間上,多邊形并一定表示這個(gè) Polygon 在同一平面上。這里我們使用缺省的逆時(shí)針方向代表面的“前面 Front),下圖黃色區(qū)域?yàn)橐粋€(gè)多邊形。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/5.png" alt="" />

來看一個(gè)多邊形的示例在 Android 系統(tǒng)如何使用頂點(diǎn)和 buffer 來定義,如下圖定義了一個(gè)正方形:

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/6.png" alt="" />

對應(yīng)的頂點(diǎn)和buffer 定義代碼:

private short[] indices = { 0, 1, 2, 0, 2, 3 };
To gain some performance we also put this ones in a byte buffer.
// short is 2 bytes, therefore we multiply the number if vertices with 2.
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
ShortBuffer indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);  

Render (渲染)

我們已定義好了多邊形,下面就要了解如和使用 OpenGL ES 的 API 來繪制(渲染)這個(gè)多邊形了。OpenGL ES 提供了兩類方法來繪制一個(gè)空間幾何圖形:

  • public abstract void glDrawArrays(int mode, int first, int count) 使用VetexBuffer 來繪制,頂點(diǎn)的順序由vertexBuffer中的順序指定。
  • public abstract void glDrawElements(int mode, int count, int type, Buffer indices) ,可以重新定義頂點(diǎn)的順序,頂點(diǎn)的順序由indices Buffer 指定。

前面我們已定義里頂點(diǎn)數(shù)組,因此我們將采用 glDrawElements 來繪制多邊形。

同樣的頂點(diǎn),可以定義的幾何圖形可以有所不同,比如三個(gè)頂點(diǎn),可以代表三個(gè)獨(dú)立的點(diǎn),也可以表示一個(gè)三角形,這就需要使用 mode 來指明所需繪制的幾何圖形的基本類型。

GL_POINTS

繪制獨(dú)立的點(diǎn)。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/7.png" alt="" />

GL_LINE_STRIP

繪制一系列線段。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/8.png" alt="" />

GL_LINE_LOOP

類同上,但是首尾相連,構(gòu)成一個(gè)封閉曲線。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/9.png" alt="" />

GL_LINES

頂點(diǎn)兩兩連接,為多條線段構(gòu)成。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/10.png" alt="" />

GL_TRIANGLES

每隔三個(gè)頂點(diǎn)構(gòu)成一個(gè)三角形,為多個(gè)三角形組成。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/11.png" alt="" />

GL_TRIANGLE_STRIP

每相鄰三個(gè)頂點(diǎn)組成一個(gè)三角形,為一系列相接三角形構(gòu)成。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/12.png" alt="" />

GL_TRIANGLE_FAN

以一個(gè)點(diǎn)為三角形公共頂點(diǎn),組成一系列相鄰的三角形。

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/13.png" alt="" />

下面可以來繪制正方形了,在項(xiàng)目中添加一個(gè) Square.java 定義如下:

package se.jayway.opengl.tutorial;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Square {
 // Our vertices.
 private float vertices[] = {
 -1.0f,  1.0f, 0.0f,  // 0, Top Left
 -1.0f, -1.0f, 0.0f,  // 1, Bottom Left
 1.0f, -1.0f, 0.0f,  // 2, Bottom Right
 1.0f,  1.0f, 0.0f,  // 3, Top Right
 };
 // The order we like to connect them.
 private short[] indices = { 0, 1, 2, 0, 2, 3 };
 // Our vertex buffer.
 private FloatBuffer vertexBuffer;
 // Our index buffer.
 private ShortBuffer indexBuffer;
 public Square() {
 // a float is 4 bytes, therefore we
 // multiply the number if
 // vertices with 4.
 ByteBuffer vbb
 = ByteBuffer.allocateDirect(vertices.length * 4);
 vbb.order(ByteOrder.nativeOrder());
 vertexBuffer = vbb.asFloatBuffer();
 vertexBuffer.put(vertices);
 vertexBuffer.position(0);
 // short is 2 bytes, therefore we multiply
 //the number if
 // vertices with 2.
 ByteBuffer ibb
 = ByteBuffer.allocateDirect(indices.length * 2);
 ibb.order(ByteOrder.nativeOrder());
 indexBuffer = ibb.asShortBuffer();
 indexBuffer.put(indices);
 indexBuffer.position(0);
 }
 /**
 * This function draws our square on screen.
 * @param gl
 */
 public void draw(GL10 gl) {
 // Counter-clockwise winding.
 gl.glFrontFace(GL10.GL_CCW);
 // Enable face culling.
 gl.glEnable(GL10.GL_CULL_FACE);
 // What faces to remove with the face culling.
 gl.glCullFace(GL10.GL_BACK);
 // Enabled the vertices buffer for writing
 //and to be used during
 // rendering.
 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
 // Specifies the location and data format of
 //an array of vertex
 // coordinates to use when rendering.
 gl.glVertexPointer(3, GL10.GL_FLOAT, 0,
 vertexBuffer);
 gl.glDrawElements(GL10.GL_TRIANGLES, indices.length
 GL10.GL_UNSIGNED_SHORT, indexBuffer);
 // Disable the vertices buffer.
 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
 // Disable face culling.
 gl.glDisable(GL10.GL_CULL_FACE);
 }
}  

在 OpenGLRenderer 中添加 Square 成員變量并初始化:

// Initialize our square.
Square square = new Square();  

并在 public void onDrawFrame(GL10 gl) 添加

// Draw our square.
square.draw(gl);  

來繪制這個(gè)正方形,編譯運(yùn)行,什么也沒顯示,這是為什么呢?這是因?yàn)?OpenGL ES 從當(dāng)前位置開始渲染,缺省坐標(biāo)為(0,0,0),和 View port 的坐標(biāo)一樣,相當(dāng)于把畫面放在眼前,對應(yīng)這種情況 OpenGL 不會(huì)渲染離 view Port 很近的畫面,因此我們需要將畫面向后退一點(diǎn)距離:

// Translates 4 units into the screen.
gl.glTranslatef(0, 0, -4);  

在編譯運(yùn)行,這次倒是有顯示了,當(dāng)正方形迅速后移直至看不見,這是因?yàn)槊看握{(diào)用onDrawFrame 時(shí),每次都再向后移動(dòng)4個(gè)單位,需要加上重置 Matrix 的代碼。

// Replace the current matrix with the identity matrix
gl.glLoadIdentity();  

最終 onDrawFrame 的代碼如下:

public void onDrawFrame(GL10 gl) {
 // Clears the screen and depth buffer.
 gl.glClear(GL10.GL_COLOR_BUFFER_BIT |
 GL10.GL_DEPTH_BUFFER_BIT);
 gl.glLoadIdentity();
 gl.glTranslatef(0, 0, -4);
 // Draw our square.
 square.draw(gl); // ( NEW )
}  

http://wiki.jikexueyuan.com/project/opengl-es-basics/images/14.png" alt="" />

上一篇:材質(zhì)渲染下一篇:構(gòu)造