OpenGL ES渲染管線概述(一)
渲染管線一般是由顯示芯片GPU內(nèi)部處理圖形信號的并行處理單元組成,這些并行處理單元之間是獨(dú)立的,從另一個(gè)角度看,渲染管線實(shí)際上也是一系列繪制過程,這一系列過程的輸入是待繪制物體的相關(guān)描述信息,輸出的是要顯示的圖像幀數(shù)據(jù)。
OpenGL ES管線主要包括:
讀取頂點(diǎn)數(shù)據(jù)—>頂點(diǎn)著色器—>組裝圖元—>光柵化圖元—>片元著色器—>寫入幀緩沖區(qū)—>顯示到屏幕上
- 讀取頂點(diǎn)數(shù)據(jù)指的是將待繪制的圖形的頂點(diǎn)數(shù)據(jù)傳遞給渲染管線中。
- 頂點(diǎn)著色器最終生成每個(gè)定點(diǎn)的最終位置,執(zhí)行頂點(diǎn)的各種變換,它會針對每個(gè)頂點(diǎn)執(zhí)行一次,確定了最終位置后,OpenGL就可以把這些頂點(diǎn)集合按照給定的參數(shù)類型組裝成點(diǎn),線或者三角形。
- 組裝圖元階段包括兩部分:圖元的組裝和圖元處理,圖元組裝指的是頂點(diǎn)數(shù)據(jù)根據(jù)設(shè)置的繪制方式參數(shù)結(jié)合成完整的圖元,例如點(diǎn)繪制方式中每個(gè)圖元就只包含一個(gè)點(diǎn),線段繪制方式中每個(gè)圖源包含兩個(gè)點(diǎn);圖元處理主要是剪裁以使得圖元位于視景體內(nèi)部的部分傳遞到下一個(gè)步驟,視景體外部的部分進(jìn)行剪裁。視景體的概念與投影有關(guān)。
- 光柵化圖元主要指的是將一個(gè)圖元離散化成可顯示的二維單元片段,這些小單元稱為片元。一個(gè)片元對應(yīng)了屏幕上的一個(gè)或多個(gè)像素,片元包括了位置,顏色,紋理坐標(biāo)等信息,這些值是由圖元的頂點(diǎn)信息進(jìn)行插值計(jì)算得到的。
- 片元著色器為每個(gè)片元生成最終的顏色,針對每個(gè)片元都會執(zhí)行一次。一旦每個(gè)片元的顏色確定了,OpenGL就會把它們寫入到幀緩沖區(qū)中。
在OpenGL ES2.0中主要的兩個(gè)部分就是上面的可編程頂點(diǎn)著色器和片段著色器。學(xué)習(xí)OpenGL ES主要是要了解渲染管線,了解CPU的渲染過程,主要編程工作在于頂點(diǎn)著色器和片元著色器的編寫。
繪制一個(gè)六邊形
效果如圖所示

六邊形類
public class SixShape {
private FloatBuffer mVertexBuffer;
private FloatBuffer mColorBuffer;
private int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int muMVPMatrixHandle;
public SixShape(float r) {
initVetexData(r);
}
public void initVetexData(float r) {
// 初始化頂點(diǎn)坐標(biāo)
float[] vertexArray = new float[8*3];
// 初始化頂點(diǎn)顏色
float[] colorArray=new float[8*4];
int j = 0, k = 0;
vertexArray[j++] = 0;
vertexArray[j++] = 0;
vertexArray[j++] = 0;
colorArray[k++] = 1;
colorArray[k++] = 1;
colorArray[k++] = 1;
colorArray[k++] = 0;
for (int angle = 0; angle <= 360; angle += 60) {
vertexArray[j++] = (float) (r*Math.cos(Math.toRadians(angle)));
vertexArray[j++] = (float) (r*Math.sin(Math.toRadians(angle)));
vertexArray[j++] = 0;
colorArray[k++] = 1;
colorArray[k++] = 0;
colorArray[k++] = 0;
colorArray[k++] = 0;
}
ByteBuffer buffer = ByteBuffer.allocateDirect(vertexArray.length * 4);
buffer.order(ByteOrder.nativeOrder());
mVertexBuffer = buffer.asFloatBuffer();
mVertexBuffer.put(vertexArray);
mVertexBuffer.position(0);
ByteBuffer cbb=ByteBuffer.allocateDirect(colorArray.length*4);
cbb.order(ByteOrder.nativeOrder());
mColorBuffer=cbb.asFloatBuffer();
mColorBuffer.put(colorArray);
mColorBuffer.position(0);
int vertexShader = loaderShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loaderShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, vertexShader);
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glLinkProgram(mProgram);
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
}
public void draw(float[] mvpMatrix) {
GLES20.glUseProgram(mProgram);
// 將頂點(diǎn)數(shù)據(jù)傳遞到管線,頂點(diǎn)著色器
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexBuffer);
// 將頂點(diǎn)顏色傳遞到管線,頂點(diǎn)著色器
GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false,4*4, mColorBuffer);
// 將變換矩陣傳遞到管線
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glEnableVertexAttribArray(mColorHandle);
// 繪制圖元
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 8);
}
private int loaderShader(int type, String shaderCode) {
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
private String vertexShaderCode = "uniform mat4 uMVPMatrix;"
+ "attribute vec3 aPosition;"
+ "attribute vec4 aColor;"
+ "varying vec4 aaColor;"
+ "void main(){"
+ "gl_Position = uMVPMatrix * vec4(aPosition,1);"
+ "aaColor = aColor;"
+ "}";
private String fragmentShaderCode = "precision mediump float;"
+ "varying vec4 aaColor;"
+ "void main(){"
+ "gl_FragColor = aaColor;"
+ "}";
}
六邊形View
public class SixView extends GLSurfaceView{
public SixView(Context context) {
super(context);
setEGLContextClientVersion(2);
setRenderer(new MyRender());
}
class MyRender implements GLSurfaceView.Renderer {
private SixShape circle;
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1);
circle = new SixShape(0.5f);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
}
// 投影矩陣
private final float[] mProjectionMatrix = new float[16];
// 視圖矩陣
private final float[] mViewMatrix = new float[16];
// 模型矩陣
private final float[] mMMatrix = new float[16];
private final float[] mViewProjectionMatrix = new float[16];
private final float[] mMVPMatrix = new float[16];
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio= (float) width / height;
// 設(shè)置正交投影
Matrix.orthoM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 0, 5);
// 設(shè)置視圖矩陣
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
Matrix.multiplyMM(mViewProjectionMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// 設(shè)置模型矩陣
Matrix.setIdentityM(mMMatrix, 0);
Matrix.translateM(mMMatrix,0,0,0,1);
Matrix.rotateM(mMMatrix, 0, 30, 0, 0, 1);
Matrix.multiplyMM(mMVPMatrix, 0, mViewProjectionMatrix, 0, mMMatrix, 0);
circle.draw(mMVPMatrix);
}
}
}
接下來在Activity中就可以使用這個(gè)View了。上面的例子雖然簡單,但是包括了使用OpenGL ES編程的主要流程,包括生成頂點(diǎn)數(shù)據(jù),編寫頂點(diǎn)著色器,片元著色器,傳遞數(shù)據(jù)給頂點(diǎn)/片元著色器,這里最主要的就是著色器語言。此外包括投影,平移,旋轉(zhuǎn)等操作。在后面會詳細(xì)學(xué)習(xí)每個(gè)細(xì)節(jié)以及上面例子沒有涉及到的光照,紋理等OpenGL的知識。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- OpenGL關(guān)于glStencilFuncSeparate()和glStencilFunc()函數(shù)的區(qū)別講解
- SDL2和OpenGL使用踩坑筆記經(jīng)驗(yàn)分享
- Android利用OpenGLES繪制天空盒實(shí)例教程
- android使用OPENGL ES繪制圓柱體
- opengl實(shí)現(xiàn)任意兩點(diǎn)間畫圓柱體
- OpenGL ES紋理詳解
- OpenGL ES透視投影實(shí)現(xiàn)方法(四)
- OpenGL ES正交投影實(shí)現(xiàn)方法(三)
- OpenGL ES著色器使用詳解(二)
- OpenGL中的glutInitDisplayMode()函數(shù)的理解
相關(guān)文章
Android IPC機(jī)制利用Messenger實(shí)現(xiàn)跨進(jìn)程通信
這篇文章主要介紹了Android IPC機(jī)制中 Messager 實(shí)現(xiàn)跨進(jìn)程通信的知識,對Android學(xué)習(xí)通信知識非常重要,需要的同學(xué)可以參考下2016-07-07
Android學(xué)習(xí)教程之下拉刷新實(shí)現(xiàn)代碼(11)
這篇文章主要為大家詳細(xì)介紹了Android學(xué)習(xí)教程之下拉刷新實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Android中兩個(gè)類讓你再也不用實(shí)現(xiàn)onActivityResult()
這篇文章主要給大家介紹了關(guān)于Android中兩個(gè)類讓你再也不用實(shí)現(xiàn)onActivityResult()的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧2018-08-08
Android中的webview監(jiān)聽每次URL變化實(shí)例
這篇文章主要介紹了Android中的webview監(jiān)聽每次URL變化實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android TextWatcher三個(gè)回調(diào)以及監(jiān)聽EditText的輸入案例詳解
這篇文章主要介紹了Android TextWatcher三個(gè)回調(diào)以及監(jiān)聽EditText的輸入案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
Android WebView調(diào)用本地相冊的方法
這篇文章主要為大家詳細(xì)介紹了Android WebView調(diào)用本地相冊的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
Android中WebView無法后退和js注入漏洞的解決方案
這篇文章主要介紹了Android中WebView無法后退和js注入漏洞解決方案,其中js注入主要針對安卓4.2及以下版本中WebView的漏洞,需要的朋友可以參考下2016-02-02

