Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> OpenglES2.0 for Android:來畫個立方體吧

OpenglES2.0 for Android:來畫個立方體吧

編輯:關於Android編程

前言:

前面一直在說OpenglES2.0二維圖形的繪制,接下來我們步入三維的世界 ,三維世界遠比二維要有趣的多,與此同時復雜性也要高得多,在unity3D中我們可以很容易的就創建 一個立方體,而在OpenglES2.0中這個過程要復雜得多,但是更加有趣 。先來看下我們的整個流程:   \


攝像機的設置:

想想你的攝像頭,它的位置不同,朝向不同,對同一個事物拍攝得到的畫面肯定是不同的,Opengl中的攝像頭和我們日常生活中的攝像頭是一樣的道理   \ (圖一)     在Opengl中攝像頭包含三部分的信息: 1. 攝像頭的位置 ,在三維空間中用 x y z 表示 2. 攝像頭的鏡頭的指向,這裡即觀察的物體的坐標,一般選取物體的center坐標(通過攝像頭的位置與觀察的物體的坐標可以確定一個向量,這個向量就可以決定觀察的方向) 3. 攝像頭的UP方向,攝像機頂端的指向   下面的人眼觀察物體的圖示更容易幫助我們理解:   \ (圖二 )   可以看出攝像機的位置,朝向,UP方向有很多不同的組合,對於不同的組合觀察同一物體會得到不同的結果 為了更好地理解,這裡給出國外大牛做的一個demo :   \   我們先做只需要看gluLookAt , eye 就是我們所說的攝像機的位置,center即攝像頭的鏡頭的指向 我們可以改變這些值,來觀察一下右上方的圖像的變化。   下載地址:http://download.csdn.net/detail/cassiepython/9541794  

透視投影

我們觀察物體,會有近大遠小的效果,透視投影即為了產生這種效果,和美術中 的透視是一個概念 \ (圖三)   其中,視點指攝像機的位置,近平面指距離視點較近的垂直於觀察方向的平面,視景體又叫做視錐體為椎台形區域。 透視投影的投影線互不平行,相較於視點,因此,對於同樣尺寸的物體,在近處投影出來大,在遠處投影出來小,由此產生近大遠小的效果。     \ (圖四)   大家可以繼續結合上面的小軟件修改參數試下來了解透視投影。  

立方體頂點坐標

OK,現在讓我們開始著手具體的編程,首先來定義立方體的頂點坐標,此時我們肯定不能只是X ,Y了 ,還要加入一個新的參數 Z ,Z和X, Y的范圍是一樣的, 也是從 -1 到 1 ,我們看向自己的手機屏幕,想象我們的視線穿過兩個平面,前面的為 1 後面的為 -1 。   我們接著上一節的工程來做,在shape包下新建一個類 ——Cube.java ,然後創建頂點數據 ,此時 Cube.java 代碼如下:
package com.cumt.shape;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import android.content.Context;

public class Cube {
	
	private FloatBuffer vertexBuffer;
	private Context context;
	//float類型的字節數
	private static final int BYTES_PER_FLOAT = 4;

	static float vertices[] = {
		//前面
    	0,0,1.0f,
    	1.0f,1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,1.0f,1.0f,
    	//後面
    	0,0,-1.0f,        	
    	1.0f,1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	//左面
    	-1.0f,0,0,      	
    	-1.0f,1.0f,1.0f,
    	-1.0f,1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	//右面
    	1.0f,0,0,   
    	1.0f,1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,-1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	1.0f,0,0,  
    	1.0f,1.0f,-1.0f,
    	1.0f,1.0f,1.0f,
    	//上面
    	0,1.0f,0,      
    	1.0f,1.0f,1.0f,
    	1.0f,1.0f,-1.0f,
    	0,1.0f,0,        	
    	1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,1.0f,0,       
    	-1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,1.0f, 	
    	0,1.0f,0,      
    	-1.0f,1.0f,1.0f,
    	1.0f,1.0f,1.0f,  	
    	//下面
    	0,-1.0f,0,        	
    	1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,-1.0f,0,  
    	-1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,   
    	-1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,    
    	1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,1.0f
	};
	
	public Cube(Context context){
		this.context = context;
		
		vertexBuffer = ByteBuffer
    			.allocateDirect(vertices.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
    	// 把坐標們加入FloatBuffer中
        vertexBuffer.put(vertices);
        // 設置buffer,從第一個坐標開始讀
        vertexBuffer.position(0);
	}
}
  我們每個面定義了12個頂點: \ 每一個面分為4個三角形,每個三角形包含3個點,共12個點(我們打算使用GL_TRIANGLES方式繪制 )   接下來看下我們的著色器代碼,頂點著色器我們使用仍然使用上一節的vertex_shader.glsl :  
uniform mat4 u_Matrix;
attribute vec4 a_Position;  
 
void main()                    
{                              
    gl_Position = u_Matrix * a_Position;
}   
  u_Matrix用於我們傳入最終的變幻矩陣 (投影矩陣 and 攝像機矩陣)。   然後我們編譯鏈接著色器 此時Cube類代碼 (Cube.java ):  
package com.cumt.shape;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import com.cumt.openglestwo_test_one.R;
import com.cumt.utils.ShaderHelper;
import com.cumt.utils.TextResourceReader;
import android.content.Context;
import android.opengl.GLES20;

public class Cube {
	
	private FloatBuffer vertexBuffer;
	private Context context;
	//float類型的字節數
	private static final int BYTES_PER_FLOAT = 4;
	//共有72個頂點坐標,每個面包含12個頂點坐標
	private static final int POSITION_COMPONENT_COUNT = 12*6;
	// 數組中每個頂點的坐標數
    private static final int COORDS_PER_VERTEX = 3;
	
	private static final String A_POSITION = "a_Position";
	private static final String U_COLOR = "u_Color";
	private static final String U_MATRIX = "u_Matrix";
	private int uMatrixLocation;
	private int uColorLocation;
	private int aPositionLocation;
	private int program;

	static float vertices[] = {
		//前面
    	0,0,1.0f,
    	1.0f,1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,1.0f,1.0f,
    	//後面
    	0,0,-1.0f,        	
    	1.0f,1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	//左面
    	-1.0f,0,0,      	
    	-1.0f,1.0f,1.0f,
    	-1.0f,1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	//右面
    	1.0f,0,0,   
    	1.0f,1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,-1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	1.0f,0,0,  
    	1.0f,1.0f,-1.0f,
    	1.0f,1.0f,1.0f,
    	//上面
    	0,1.0f,0,      
    	1.0f,1.0f,1.0f,
    	1.0f,1.0f,-1.0f,
    	0,1.0f,0,        	
    	1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,1.0f,0,       
    	-1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,1.0f, 	
    	0,1.0f,0,      
    	-1.0f,1.0f,1.0f,
    	1.0f,1.0f,1.0f,  	
    	//下面
    	0,-1.0f,0,        	
    	1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,-1.0f,0,  
    	-1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,   
    	-1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,    
    	1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,1.0f
	};
	
	public Cube(Context context){
		this.context = context;
		
		vertexBuffer = ByteBuffer
    			.allocateDirect(vertices.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
    	// 把坐標們加入FloatBuffer中
        vertexBuffer.put(vertices);
        // 設置buffer,從第一個坐標開始讀
        vertexBuffer.position(0);
        
        getProgram();
        
        uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);
		aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);
		uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);
		
		//---------傳入頂點數據數據
		GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,
				GLES20.GL_FLOAT, false, 0, vertexBuffer);
		GLES20.glEnableVertexAttribArray(aPositionLocation);
	}
	
	//獲取program
    private void getProgram(){
    	//獲取頂點著色器文本
    	String vertexShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.vertex_shader);
    	//獲取片段著色器文本
		String fragmentShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.simple_fragment_shader);
		//獲取program的id
		program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);
		GLES20.glUseProgram(program);
    }
}

接下來我們應該定義實現draw方法,在此之前先讓我們解決投影矩陣的問題


設置相機和投影

我們來定義一個工具類來獲得最終的變幻矩陣 ,我們需要使用兩個函數 :   \   \

這兩個函數的參數的含義與上面我們講解相機和投影時的那些參數是對應的,大家可以回到前面再看下,這裡不再重復。   我們在utils包中定義工具類——MatrixState 然後看我的工具類的代碼 (MatrixState.java):  
package com.cumt.utils;

import android.opengl.Matrix;

//存儲系統矩陣狀態的類
public class MatrixState {
	private static float[] mProjMatrix = new float[16];// 4x4矩陣 存儲投影矩陣
	private static float[] mVMatrix = new float[16];// 攝像機位置朝向9參數矩陣

	// 設置攝像機
	public static void setCamera(float cx, // 攝像機位置x
			float cy, // 攝像機位置y
			float cz, // 攝像機位置z
			float tx, // 攝像機目標點x
			float ty, // 攝像機目標點y
			float tz, // 攝像機目標點z
			float upx, // 攝像機UP向量X分量
			float upy, // 攝像機UP向量Y分量
			float upz // 攝像機UP向量Z分量
	) {
		Matrix.setLookAtM(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
	}

	// 設置透視投影參數
	public static void setProjectFrustum(float left, // near面的left
			float right, // near面的right
			float bottom, // near面的bottom
			float top, // near面的top
			float near, // near面距離
			float far // far面距離
	) {
		Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
	}

	// 獲取具體物體的總變換矩陣
	static float[] mMVPMatrix = new float[16];

	public static float[] getFinalMatrix() {
		Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
		return mMVPMatrix;
	}
}

這個工具類中有三個方法,我們在渲染類 (MyRender.java)中的 onSurfaceChanged中調用前兩個方法設置攝像機和投影矩陣,在Cube的draw方法中就可以通過第三個方法 getFinalMatrix 來獲取最終的變換矩陣 然後傳入著色器程序。 (我們注意multiplyMM函數,這個函數工作是將我們的投影矩陣和攝像機矩陣進行矩陣的乘法運算,存儲在 mMVPMatrix中,這個mMVPMatrix即為我們最終的變換矩陣,即我們需要傳入著色器程序的矩陣。   OK,看下完整的 Cube.java 類 和 MyRender.java :  
package com.cumt.shape;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import com.cumt.openglestwo_test_one.R;
import com.cumt.utils.MatrixState;
import com.cumt.utils.ShaderHelper;
import com.cumt.utils.TextResourceReader;
import android.content.Context;
import android.opengl.GLES20;

public class Cube {
	
	private FloatBuffer vertexBuffer;
	private Context context;
	//float類型的字節數
	private static final int BYTES_PER_FLOAT = 4;
	//共有72個頂點坐標,每個面包含12個頂點坐標
	private static final int POSITION_COMPONENT_COUNT = 12*6;
	// 數組中每個頂點的坐標數
    private static final int COORDS_PER_VERTEX = 3;
	
	private static final String A_POSITION = "a_Position";
	private static final String U_COLOR = "u_Color";
	private static final String U_MATRIX = "u_Matrix";
	private int uMatrixLocation;
	private int uColorLocation;
	private int aPositionLocation;
	private int program;

	static float vertices[] = {
		//前面
    	0,0,1.0f,
    	1.0f,1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,1.0f,1.0f,
    	//後面
    	0,0,-1.0f,        	
    	1.0f,1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	//左面
    	-1.0f,0,0,      	
    	-1.0f,1.0f,1.0f,
    	-1.0f,1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	//右面
    	1.0f,0,0,   
    	1.0f,1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,-1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	1.0f,0,0,  
    	1.0f,1.0f,-1.0f,
    	1.0f,1.0f,1.0f,
    	//上面
    	0,1.0f,0,      
    	1.0f,1.0f,1.0f,
    	1.0f,1.0f,-1.0f,
    	0,1.0f,0,        	
    	1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,1.0f,0,       
    	-1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,1.0f, 	
    	0,1.0f,0,      
    	-1.0f,1.0f,1.0f,
    	1.0f,1.0f,1.0f,  	
    	//下面
    	0,-1.0f,0,        	
    	1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,-1.0f,0,  
    	-1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,   
    	-1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,    
    	1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,1.0f
	};
	
	public Cube(Context context){
		this.context = context;
		
		vertexBuffer = ByteBuffer
    			.allocateDirect(vertices.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
    	// 把坐標們加入FloatBuffer中
        vertexBuffer.put(vertices);
        // 設置buffer,從第一個坐標開始讀
        vertexBuffer.position(0);
        
        getProgram();
        
        uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);
		aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);
		uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);
		
		//---------傳入頂點數據數據
		GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,
				GLES20.GL_FLOAT, false, 0, vertexBuffer);
		GLES20.glEnableVertexAttribArray(aPositionLocation);
	}
	
	//獲取program
    private void getProgram(){
    	//獲取頂點著色器文本
    	String vertexShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.vertex_shader);
    	//獲取片段著色器文本
		String fragmentShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.simple_fragment_shader);
		//獲取program的id
		program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);
		GLES20.glUseProgram(program);
    }
    
    public void draw(){
		GLES20.glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 0.0f);		
		GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, MatrixState.getFinalMatrix(),0);
		GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, POSITION_COMPONENT_COUNT);
    }
}
 
package com.cumt.render;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import com.cumt.utils.MatrixState;
import com.cumt.shape.Cube;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glViewport;

public class MyRender implements Renderer {
	
	private Context context;
	
	public MyRender(Context context){
		this.context = context;
	}
	
//	Circle circle;
	Cube cube;
	
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		Log.w("MyRender","onSurfaceCreated");
		//設置屏幕背景色RGBA
        glClearColor(0.5f,0.5f,0.5f, 1.0f);  
//		//打開深度檢測
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
//        //打開背面剪裁   
        GLES20.glEnable(GLES20.GL_CULL_FACE); 
//		circle = new Circle(context);
		cube = new Cube(context);
	}

	public void onSurfaceChanged(GL10 gl, int width, int height) {
		glViewport(0,0,width,height);
		float ratio = (float) width / height;
		//設置投影矩陣
//		circle.projectionMatrix(width, height);
		// 調用此方法計算產生透視投影矩陣
        MatrixState.setProjectFrustum(-ratio,ratio, -1, 1, 20, 100);
		// 調用此方法產生攝像機9參數位置矩陣
		MatrixState.setCamera(-16f, 8f, 45, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
	}

	public void onDrawFrame(GL10 gl) {
//		glClear(GL_COLOR_BUFFER_BIT);
		//清除深度緩沖與顏色緩沖
        glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
//      circle.draw();
		cube.draw();
	}
}
  然後我們回到MainActivity 設置屏幕顯示方式為豎屏,全屏 ,此時MainActivity代碼如下 (MainActivity.java):  
package com.cumt.openglestwo_test_one;

import com.cumt.render.MyRender;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity {

	private GLSurfaceView glSurfaceView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// 設置為全屏
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		// 設置為橫屏模式
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
		glSurfaceView = new GLSurfaceView(this);
		//OpenGL ES 2.0
		glSurfaceView.setEGLContextClientVersion(2);
		glSurfaceView.setRenderer(new MyRender(this));
		// 設置渲染模式為主動渲染
		glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
		setContentView(glSurfaceView);
	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		glSurfaceView.onPause();
	}

	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		glSurfaceView.onResume();
	}
}

快來運行一下 :   \  
一個全紅的立方體誕生了~~(大家還可以嘗試用線段的繪制方式來繪制一個 " 空心 " 的立方體),可是這樣看起來根本看不出來它的一些邊 ,我們來想辦法給它美化一下,在這節先不考慮紋理貼圖,我們把每個面設置成不同的顏色。   OK,先來看下我們接下來的過程 :   \   在Cube類中定義頂點坐標,並轉化為FloatBuffer類型 ,此時代碼如下 (Cube.java ) :  
package com.cumt.shape;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import com.cumt.openglestwo_test_one.R;
import com.cumt.utils.MatrixState;
import com.cumt.utils.ShaderHelper;
import com.cumt.utils.TextResourceReader;
import android.content.Context;
import android.opengl.GLES20;

public class Cube {
	
	//頂點坐標
	private FloatBuffer vertexBuffer;
	//顏色坐標
	private FloatBuffer colorBuffer;
	private Context context;
	//float類型的字節數
	private static final int BYTES_PER_FLOAT = 4;
	//共有72個頂點坐標,每個面包含12個頂點坐標
	private static final int POSITION_COMPONENT_COUNT = 12*6;
	// 數組中每個頂點的坐標數
    private static final int COORDS_PER_VERTEX = 3;
	
	private static final String A_POSITION = "a_Position";
	private static final String U_COLOR = "u_Color";
	private static final String U_MATRIX = "u_Matrix";
	private int uMatrixLocation;
	private int uColorLocation;
	private int aPositionLocation;
	private int program;

	static float vertices[] = {
		//前面
    	0,0,1.0f,
    	1.0f,1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,1.0f,1.0f,
    	//後面
    	0,0,-1.0f,        	
    	1.0f,1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	//左面
    	-1.0f,0,0,      	
    	-1.0f,1.0f,1.0f,
    	-1.0f,1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	//右面
    	1.0f,0,0,   
    	1.0f,1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,-1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	1.0f,0,0,  
    	1.0f,1.0f,-1.0f,
    	1.0f,1.0f,1.0f,
    	//上面
    	0,1.0f,0,      
    	1.0f,1.0f,1.0f,
    	1.0f,1.0f,-1.0f,
    	0,1.0f,0,        	
    	1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,1.0f,0,       
    	-1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,1.0f, 	
    	0,1.0f,0,      
    	-1.0f,1.0f,1.0f,
    	1.0f,1.0f,1.0f,  	
    	//下面
    	0,-1.0f,0,        	
    	1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,-1.0f,0,  
    	-1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,   
    	-1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,    
    	1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,1.0f
	};
	
	//頂點顏色值數組,每個頂點4個色彩值RGBA
    static float colors[]=new float[]{
    		//前面        
    		1,1,1,0,//中間為白色
    		1,0,0,0,
    		1,0,0,0,
    		1,1,1,0,//中間為白色
    		1,0,0,0,
    		1,0,0,0,
    		1,1,1,0,//中間為白色
    		1,0,0,0,
    		1,0,0,0,
    		1,1,1,0,//中間為白色
    		1,0,0,0,
    		1,0,0,0,
    		//後面
    		1,1,1,0,//中間為白色
    		0,0,1,0,
    		0,0,1,0, 
    		1,1,1,0,//中間為白色
    		0,0,1,0,
    		0,0,1,0, 
    		1,1,1,0,//中間為白色
    		0,0,1,0,
    		0,0,1,0, 
    		1,1,1,0,//中間為白色
    		0,0,1,0,
    		0,0,1,0, 
    		//左面
    		1,1,1,0,//中間為白色
    		1,0,1,0,
    		1,0,1,0, 
    		1,1,1,0,//中間為白色
    		1,0,1,0,
    		1,0,1,0, 
    		1,1,1,0,//中間為白色
    		1,0,1,0,
    		1,0,1,0, 
    		1,1,1,0,//中間為白色
    		1,0,1,0,
    		1,0,1,0, 
    		//右面
    		1,1,1,0,//中間為白色
    		1,1,0,0,
    		1,1,0,0,
    		1,1,1,0,//中間為白色
    		1,1,0,0,
    		1,1,0,0,
    		1,1,1,0,//中間為白色
    		1,1,0,0,
    		1,1,0,0,
    		1,1,1,0,//中間為白色
    		1,1,0,0,
    		1,1,0,0,
    		//上面
    		1,1,1,0,//中間為白色
    		0,1,0,0,
    		0,1,0,0,
    		1,1,1,0,//中間為白色
    		0,1,0,0,
    		0,1,0,0,
    		1,1,1,0,//中間為白色
    		0,1,0,0,
    		0,1,0,0,
    		1,1,1,0,//中間為白色
    		0,1,0,0,
    		0,1,0,0,        		
    		//下面
    		1,1,1,0,//中間為白色
    		0,1,1,0,
    		0,1,1,0,
    		1,1,1,0,//中間為白色
    		0,1,1,0,
    		0,1,1,0,
    		1,1,1,0,//中間為白色
    		0,1,1,0,
    		0,1,1,0,
    		1,1,1,0,//中間為白色
    		0,1,1,0,
    		0,1,1,0,
    };
	
	public Cube(Context context){
		this.context = context;
		
		vertexBuffer = ByteBuffer
    			.allocateDirect(vertices.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
    	// 把坐標們加入FloatBuffer中
        vertexBuffer.put(vertices);
        // 設置buffer,從第一個坐標開始讀
        vertexBuffer.position(0);
        
        //顏色buffer
        colorBuffer = ByteBuffer
    			.allocateDirect(colors.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
        colorBuffer.put(colors);
        colorBuffer.position(0);
        
        getProgram();
        
        uColorLocation = GLES20.glGetUniformLocation(program, U_COLOR);
		aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);
		uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);
		
		//---------傳入頂點數據數據
		GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,
				GLES20.GL_FLOAT, false, 0, vertexBuffer);
		GLES20.glEnableVertexAttribArray(aPositionLocation);
	}
	
	//獲取program
    private void getProgram(){
    	//獲取頂點著色器文本
    	String vertexShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.vertex_shader);
    	//獲取片段著色器文本
		String fragmentShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.simple_fragment_shader);
		//獲取program的id
		program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);
		GLES20.glUseProgram(program);
    }
    
    public void draw(){
		GLES20.glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 0.0f);		
		GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, MatrixState.getFinalMatrix(),0);
		GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, POSITION_COMPONENT_COUNT);
    }
}

創建新的頂點著色器和片段著色器程序 (vertex_shader_cube.glsl 和fragment_shader_cube.glsl ):  
//vertex_shader_cube.glsl
uniform mat4 u_Matrix;
attribute vec4 a_Position;  
attribute vec4 a_Color;    //頂點顏色
varying  vec4 v_Color;  //用於傳遞給片元著色器的變量
 
void main()                    
{                              
    gl_Position = u_Matrix * a_Position;
    v_Color = a_Color;//將接收的顏色傳遞給片元著色器
} 

//fragment_shader_cube.glsl
precision mediump float; 				
varying vec4 v_Color; //接收從頂點著色器過來的參數  							
  
void main()                    		
{                              	
    gl_FragColor = v_Color;                                  		
}
  去點原來的引入顏色的相關代碼,加入當前要傳遞的顏色相關的代碼,此時Cube類如下 (Cube.java ) :  
package com.cumt.shape;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import com.cumt.openglestwo_test_one.R;
import com.cumt.utils.MatrixState;
import com.cumt.utils.ShaderHelper;
import com.cumt.utils.TextResourceReader;
import android.content.Context;
import android.opengl.GLES20;

public class Cube {

	//頂點坐標
	private FloatBuffer vertexBuffer;
	//顏色坐標
	private FloatBuffer colorBuffer;
	private Context context;
	//float類型的字節數
	private static final int BYTES_PER_FLOAT = 4;
	//共有72個頂點坐標,每個面包含12個頂點坐標
	private static final int POSITION_COMPONENT_COUNT = 12*6;
	// 數組中每個頂點的坐標數
    private static final int COORDS_PER_VERTEX = 3;
    // 顏色數組中每個顏色的值數
    private static final int COORDS_PER_COLOR = 4;
	
	private static final String A_POSITION = "a_Position";
	private static final String A_COLOR = "a_Color";
	private static final String U_MATRIX = "u_Matrix";
	private int uMatrixLocation;
	private int aColorLocation;
	private int aPositionLocation;
	private int program;

	static float vertices[] = {
		//前面
    	0,0,1.0f,
    	1.0f,1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	-1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	0,0,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,1.0f,1.0f,
    	//後面
    	0,0,-1.0f,        	
    	1.0f,1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,0,-1.0f, 
    	-1.0f,1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	//左面
    	-1.0f,0,0,      	
    	-1.0f,1.0f,1.0f,
    	-1.0f,1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,1.0f,-1.0f,
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,-1.0f,
    	-1.0f,-1.0f,1.0f,
    	-1.0f,0,0,   
    	-1.0f,-1.0f,1.0f,
    	-1.0f,1.0f,1.0f,
    	//右面
    	1.0f,0,0,   
    	1.0f,1.0f,1.0f,
    	1.0f,-1.0f,1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,1.0f,
    	1.0f,-1.0f,-1.0f,
    	1.0f,0,0,   
    	1.0f,-1.0f,-1.0f,
    	1.0f,1.0f,-1.0f,
    	1.0f,0,0,  
    	1.0f,1.0f,-1.0f,
    	1.0f,1.0f,1.0f,
    	//上面
    	0,1.0f,0,      
    	1.0f,1.0f,1.0f,
    	1.0f,1.0f,-1.0f,
    	0,1.0f,0,        	
    	1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,-1.0f,
    	0,1.0f,0,       
    	-1.0f,1.0f,-1.0f,
    	-1.0f,1.0f,1.0f, 	
    	0,1.0f,0,      
    	-1.0f,1.0f,1.0f,
    	1.0f,1.0f,1.0f,  	
    	//下面
    	0,-1.0f,0,        	
    	1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,1.0f,
    	0,-1.0f,0,  
    	-1.0f,-1.0f,1.0f,
    	-1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,   
    	-1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,-1.0f,
    	0,-1.0f,0,    
    	1.0f,-1.0f,-1.0f,
    	1.0f,-1.0f,1.0f
	};
	
	//頂點顏色值數組,每個頂點4個色彩值RGBA
    static float colors[]=new float[]{
    		//前面        
    		1,1,1,0,//中間為白色
    		1,0,0,0,
    		1,0,0,0,
    		1,1,1,0,//中間為白色
    		1,0,0,0,
    		1,0,0,0,
    		1,1,1,0,//中間為白色
    		1,0,0,0,
    		1,0,0,0,
    		1,1,1,0,//中間為白色
    		1,0,0,0,
    		1,0,0,0,
    		//後面
    		1,1,1,0,//中間為白色
    		0,0,1,0,
    		0,0,1,0, 
    		1,1,1,0,//中間為白色
    		0,0,1,0,
    		0,0,1,0, 
    		1,1,1,0,//中間為白色
    		0,0,1,0,
    		0,0,1,0, 
    		1,1,1,0,//中間為白色
    		0,0,1,0,
    		0,0,1,0, 
    		//左面
    		1,1,1,0,//中間為白色
    		1,0,1,0,
    		1,0,1,0, 
    		1,1,1,0,//中間為白色
    		1,0,1,0,
    		1,0,1,0, 
    		1,1,1,0,//中間為白色
    		1,0,1,0,
    		1,0,1,0, 
    		1,1,1,0,//中間為白色
    		1,0,1,0,
    		1,0,1,0, 
    		//右面
    		1,1,1,0,//中間為白色
    		1,1,0,0,
    		1,1,0,0,
    		1,1,1,0,//中間為白色
    		1,1,0,0,
    		1,1,0,0,
    		1,1,1,0,//中間為白色
    		1,1,0,0,
    		1,1,0,0,
    		1,1,1,0,//中間為白色
    		1,1,0,0,
    		1,1,0,0,
    		//上面
    		1,1,1,0,//中間為白色
    		0,1,0,0,
    		0,1,0,0,
    		1,1,1,0,//中間為白色
    		0,1,0,0,
    		0,1,0,0,
    		1,1,1,0,//中間為白色
    		0,1,0,0,
    		0,1,0,0,
    		1,1,1,0,//中間為白色
    		0,1,0,0,
    		0,1,0,0,        		
    		//下面
    		1,1,1,0,//中間為白色
    		0,1,1,0,
    		0,1,1,0,
    		1,1,1,0,//中間為白色
    		0,1,1,0,
    		0,1,1,0,
    		1,1,1,0,//中間為白色
    		0,1,1,0,
    		0,1,1,0,
    		1,1,1,0,//中間為白色
    		0,1,1,0,
    		0,1,1,0,
    };
	
	public Cube(Context context){
		this.context = context;
		
		vertexBuffer = ByteBuffer
    			.allocateDirect(vertices.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
    	// 把坐標們加入FloatBuffer中
        vertexBuffer.put(vertices);
        // 設置buffer,從第一個坐標開始讀
        vertexBuffer.position(0);
        
        //顏色buffer
        colorBuffer = ByteBuffer
    			.allocateDirect(colors.length * BYTES_PER_FLOAT)
    			.order(ByteOrder.nativeOrder())
    			.asFloatBuffer();
        colorBuffer.put(colors);
        colorBuffer.position(0);
        
        getProgram();
        
        aColorLocation = GLES20.glGetAttribLocation(program, A_COLOR);
		aPositionLocation = GLES20.glGetAttribLocation(program, A_POSITION);
		uMatrixLocation = GLES20.glGetUniformLocation(program, U_MATRIX);
		
		//---------傳入頂點數據數據
		GLES20.glVertexAttribPointer(aPositionLocation, COORDS_PER_VERTEX,
				GLES20.GL_FLOAT, false, 0, vertexBuffer);
		GLES20.glEnableVertexAttribArray(aPositionLocation);
		//---------傳入顏色數據
		GLES20.glVertexAttribPointer(aColorLocation, COORDS_PER_COLOR,
				GLES20.GL_FLOAT, false, 0, colorBuffer);
		GLES20.glEnableVertexAttribArray(aColorLocation);
	}
	
	//獲取program
    private void getProgram(){
    	//獲取頂點著色器文本
    	String vertexShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.vertex_shader_cube);
    	//獲取片段著色器文本
		String fragmentShaderSource = TextResourceReader
				.readTextFileFromResource(context, R.raw.fragment_shader_cube);
		//獲取program的id
		program = ShaderHelper.buildProgram(vertexShaderSource, fragmentShaderSource);
		GLES20.glUseProgram(program);
    }
    
    public void draw(){
		GLES20.glUniformMatrix4fv(uMatrixLocation, 1, false, MatrixState.getFinalMatrix(),0);
		GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, POSITION_COMPONENT_COUNT);
    }
}
  運行一下看看結果 :   \     哈 現在我們的立方體就完成了 ,是不是很漂亮 。 關於顏色設置,這裡用到了OpenglEs 的平滑著色 ,如果有不明白的 可以去按照 “opengl es 平滑著色 ” 這個關鍵字搜索一下 。這裡不再講解。  
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved