Android下使用OpenGL繪製三角形
阿新 • • 發佈:2018-12-12
在Android下影象渲染基本都用的是OpenGL ES,在使用opengl過程中需要注意幾個關鍵點:
1、頂點著色器
2、色彩著色器
3、座標
特別提到座標,是因為opengl中的座標與手機螢幕的座標是不一致的,在使用opengl座標時需要自己進行轉換一下:
這裡使用OpenGL來繪製一個三角形:
專案地址:
1、使用opengl 2.0版本:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
2、MainActivity.java檔案:
package com.example.tongjiangsong.opengltriangle; import android.opengl.GLSurfaceView; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { private GLSurfaceView mGLView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLView = new MyGLSurfaceView(this); setContentView(mGLView); } }
3、MyGLRenderer.java檔案:
package com.example.tongjiangsong.opengltriangle; import android.opengl.EGLConfig; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import javax.microedition.khronos.opengles.GL10; public class MyGLRenderer implements GLSurfaceView.Renderer { private Triangle mTriangle; @Override public void onSurfaceCreated(GL10 gl, javax.microedition.khronos.egl.EGLConfig config) { GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//白色不透明 mTriangle = new Triangle(); } @Override public void onSurfaceChanged(GL10 unused, int width, int height) {//當view的幾何形狀發生變化時呼叫,比如裝置螢幕方向改變時 //繪製視窗 GLES20.glViewport(0, 0, width, height); } public void onDrawFrame(GL10 unused) {//每次重繪view時呼叫 //重繪背景色 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); mTriangle.draw(); } public static int loadShader(int type, String shaderCode){ //建立一個vertex shader型別(GLES20.GL_VERTEX_SHADER) //或一個fragment shader型別(GLES20.GL_FRAGMENT_SHADER) int shader = GLES20.glCreateShader(type); // 將原始碼新增到shader並編譯它 GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } }
4、MyGLSurfaceView.java檔案:
package com.example.tongjiangsong.opengltriangle; import android.content.Context; import android.opengl.EGLConfig; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import javax.microedition.khronos.opengles.GL10; class MyGLSurfaceView extends GLSurfaceView { private final MyGLRenderer mRenderer; public MyGLSurfaceView(Context context){ super(context); // 建立OpenGL ES 2.0的上下文 setEGLContextClientVersion(2); mRenderer = new MyGLRenderer(); //設定Renderer用於繪圖 setRenderer(mRenderer); //只有在繪製資料改變時才繪製view,可以防止GLSurfaceView幀重繪 setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); } }
5、Triangle.java檔案:
package com.example.tongjiangsong.opengltriangle;
import android.opengl.GLES20;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
public class Triangle {
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private FloatBuffer vertexBuffer;
//設定每個頂點的座標數
static final int COORDS_PER_VERTEX = 3;
//設定三角形頂點陣列
static float triangleCoords[] = { //預設按逆時針方向繪製
0.0f, 1.0f, 0.0f, // 頂點
-1.0f, -0.5f, 0.0f, // 左下角
1.0f, -0.5f, 0.0f // 右下角
};
// 設定三角形顏色和透明度(r,g,b,a)
float color[] = {1.0f, 1.0f, 0f, 1.0f};//綠色不透明
private int mPositionHandle;
private int mColorHandle;
private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private int mProgram;
public void draw() {
// 新增program到OpenGL ES環境中
GLES20.glUseProgram(mProgram);
// 獲取指向vertex shader的成員vPosition的handle
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// 啟用一個指向三角形的頂點陣列的handle
GLES20.glEnableVertexAttribArray(mPositionHandle);
//準備三角形的座標資料
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// 獲取指向fragment shader的成員vColor的handle
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// 繪製三角形
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// 禁用指向三角形的頂點陣列
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
public Triangle() {
// 初始化頂點位元組緩衝區,用於存放形狀的座標
ByteBuffer bb = ByteBuffer.allocateDirect(//(每個浮點數佔用4個位元組
triangleCoords.length * 4);
//設定使用裝置硬體的原生位元組序
bb.order(ByteOrder.nativeOrder());
//從ByteBuffer中建立一個浮點緩衝區
vertexBuffer = bb.asFloatBuffer();
// 把座標都新增到FloatBuffer中
vertexBuffer.put(triangleCoords);
//設定buffer從第一個座標開始讀
vertexBuffer.position(0);
// 編譯shader程式碼
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
// 建立空的OpenGL ES Program
mProgram = GLES20.glCreateProgram();
// 將vertex shader新增到program
GLES20.glAttachShader(mProgram, vertexShader);
// 將fragment shader新增到program
GLES20.glAttachShader(mProgram, fragmentShader);
// 建立可執行的 OpenGL ES program
GLES20.glLinkProgram(mProgram);
}
}
執行結果如下: