日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Android openGl 繪制簡單圖形的實現示例

瀏覽:128日期:2022-09-26 15:24:18

學習五部曲,弄清楚5個W一個H(when(什么時候使用)、where(在哪個地方使用?)、who(對誰使用)、what(是個什么東西)、why(為什么要這么用?).一個H即:how(到底該怎么用?)),基本的概念篇主要圍繞這幾個方面進行分析

1. What? openGl是什么?openGl ES又是什么?

相信很多人從事開發的都或多或少聽到過有關OpenGl這個東西,但是平時用的少,只知道有這么個東西,而且學起來不簡單,所以大多數人都不能講出個個所以然來。

官方對OpenGl的描述為:

OpenGL(Open Graphics Library開發圖形接口)是一個跨平臺的圖形API,用于指定3D圖形處理硬件中的標準軟件接口。

OpenGl的前身是SGI公司為其圖形工作站開發的IRIS GL,后來因為IRIS GL的移植性不好,所以在其基礎上,開發出了OpenGl。OpenGl一般用于在圖形工作站,PC端使用,由于性能各方面原因,在移動端使用OpenGl基本帶不動。為此,Khronos公司就為OpenGl提供了一個子集,OpenGl ES(OpenGl for Embedded System)

什么是OpenGl ES呢?

OpenGl ES是免費的跨平臺的功能完善的2D/3D圖形庫接口的API,是OpenGL的一個子集。

移動端使用到的基本上都是OpenGl ES,當然Android開發下還專門為OpenGl提供了android.opengl包,并且提供了GlSurfaceView,GLU,GlUtils等工具類。

2. How? Android中的openGL 如何使用?

在了解OpenGl的使用之前,我們需要了解兩個基本類別的Android框架:GlSurfaceView和GlSurfaceView.Renderer

3. GlSurfaceView是什么? GLSurfaceView的作用是什么? GLSurfaceView如何使用?

GlSurfaceView從名字就可以看出,它是一個SurfaceView,看源碼可知,GlSurfaceView繼承自SurfaceView。并增加了Renderer.它的作用就是專門為OpenGl顯示渲染使用的。

GLSurfaceView的使用方法: 可以通過創建的實例使用這個類,并增加你的Renderer.

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GLSurfaceView glSurfaceView = new GLSurfaceView(this); glSurfaceView.setRenderer(new GLSurfaceView.Renderer() { @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { } @Override public void onDrawFrame(GL10 gl) { } }); setContentView(glSurfaceView); }4. GlSurfaceView.Renderer是什么?GLSurfaceView.Renderer的作用?GLSurfaceView.Renderer的用法?

該接口定義了用于繪制在圖形所需的方法GLSurfaceView。你必須提供這個接口作為一個單獨的類的實現,并將其連接到您的GLSurfaceView使用實例 GLSurfaceView.setRenderer()。如上面的代碼所示。作用就是提供各種渲染方法,OpenGl的渲染操作均在此接口中實習。下面說下實現該接口的方法含義:

onSurfaceCreated():系統調用這個方法一次創建時GLSurfaceView。使用此方法來執行只需要發生一次的操作,比如設置OpenGL的環境參數或初始化的OpenGL圖形對象。 onDrawFrame():系統調用上的每個重繪此方法GLSurfaceView。使用此方法作為主要執行點用于繪制(和重新繪制)的圖形對象。 系統調用此方法時的GLSurfaceView幾何形狀的變化,包括尺寸變化GLSurfaceView或設備屏幕的取向。例如,當設備從縱向變為橫向的系統調用這個方法。使用此方法可以在變化做出反應GLSurfaceView容器。

介紹完了GlSurfaceView和GlSurfaceView.renderer之后,接下來說下如何使用GlSurfaceView; 1. 創建一個GlSurfaceView 2. 為這個GlSurfaceView設置渲染 3. 在GlSurfaceView.renderer中繪制處理顯示數據

5. OpenGl的簡單使用實例(繪制一個三角形)

在使用OpenGl之前,需要在AndroidManifest.xml中設置OpenGl的版本:這里我們使用的是OpenGl ES 2.0,所以需要添加如下說明:

<uses-feature android:glEsVersion='0x00020000' android:required='true' />

使用GLSufaceView(上面有介紹)

具體在GlSurfaceView.Renderer中的繪制步驟: 設置視圖展示窗口(viewport) :在onSurfaceChanged中調用GLES20.glViewport(0, 0, width, height); 創建圖形類,確定好頂點位置和圖形顏色,將頂點和顏色數據轉換為OpenGl使用的數據格式 加載頂點找色器和片段著色器用來修改圖形的顏色,紋理,坐標等屬性 創建投影和相機視圖來顯示視圖的顯示狀態,并將投影和相機視圖的轉換傳遞給著色器。 創建項目(Program),連接頂點著色器片段著色器。 將坐標數據傳入到OpenGl ES程序中: 使用OpenGl修改背景顏色

創建一個GlSurfaceView,并為其設置渲染OneGlRenderer;

public class OneGlSurfaceView extends GLSurfaceView { private final OneGlRenderer mRenderer; public OneGlSurfaceView(Context context) { super(context); // Create an OpenGL ES 2.0 context setEGLContextClientVersion(2); mRenderer = new OneGlRenderer(); // Set the Renderer for drawing on the GLSurfaceView setRenderer(mRenderer); }}

實現渲染接口

public class OneGlRenderer implements GLSurfaceView.Renderer { public void onSurfaceCreated(GL10 unused, EGLConfig config) { // Set the background frame color GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); } public void onDrawFrame(GL10 unused) { // Redraw background color GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); } public void onSurfaceChanged(GL10 unused, int width, int height) { GLES20.glViewport(0, 0, width, height); }}

展示渲染后的GlSurfaceView

public class OneOpenGlActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); OneGlSurfaceView glSurfaceView = new OneGlSurfaceView(this); setContentView(glSurfaceView); }}

效果如下:就是簡單給GlSurfaceView渲染一層黑色。

Android openGl 繪制簡單圖形的實現示例

使用OpenGl繪制幾何圖形

一:圖形創建

創建一個幾何圖形(這里主要列舉三角形和正方形),需要注意一點,我們設置圖形的頂點坐標后,需要將頂點坐標轉為ByteBuffer,這樣OpenGl才能進行圖形處理。

三角形圖形創建:

public class Triangle { private FloatBuffer vertexBuffer; // number of coordinates per vertex in this array static final int COORDS_PER_VERTEX = 3; static float triangleCoords[] = { // in counterclockwise order: 0.0f, 0.5f, 0.0f, // top -0.5f, -0.5f, 0.0f, // bottom left 0.5f, -0.5f, 0.0f // bottom right }; // Set color with red, green, blue and alpha (opacity) values float color[] = { 255, 0, 0, 1.0f }; public Triangle() { // 初始化ByteBuffer,長度為arr數組的長度*4,因為一個float占4個字節 ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4); // 數組排列用nativeOrder bb.order(ByteOrder.nativeOrder()); // 從ByteBuffer創建一個浮點緩沖區 vertexBuffer = bb.asFloatBuffer(); // 將坐標添加到FloatBuffer vertexBuffer.put(triangleCoords); // 設置緩沖區來讀取第一個坐標 vertexBuffer.position(0); }}

正方型圖:

public class Square { private FloatBuffer vertexBuffer; private ShortBuffer drawListBuffer; // number of coordinates per vertex in this array static final int COORDS_PER_VERTEX = 3; static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left -0.5f, -0.5f, 0.0f, // bottom left 0.5f, -0.5f, 0.0f, // bottom right 0.5f, 0.5f, 0.0f }; // top right private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices public Square() { // 初始化ByteBuffer,長度為arr數組的長度*4,因為一個float占4個字節 ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4); bb.order(ByteOrder.nativeOrder()); vertexBuffer = bb.asFloatBuffer(); vertexBuffer.put(squareCoords); vertexBuffer.position(0); // 初始化ByteBuffer,長度為arr數組的長度*2,因為一個short占2個字節 ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2); dlb.order(ByteOrder.nativeOrder()); drawListBuffer = dlb.asShortBuffer(); drawListBuffer.put(drawOrder); drawListBuffer.position(0); }}

創建圖形基本沒什么技巧可言,按部就班就行了,為什么數據需要轉換格式呢?主要是因為Java的緩沖區數據存儲結構為大端字節序(BigEdian),而OpenGl的數據為小端字節序(LittleEdian),因為數據存儲結構的差異,所以,在Android中使用OpenGl的時候必須要進行下轉換。當然,一般我們在使用的時候都會做個簡單的工具類。這里提供幾個簡單的封裝。(占幾個字節就初始化ByteBuffer長度的時候*幾)

將int[]轉成IntBuffer

private IntBuffer intBufferUtil(int[] arr) { IntBuffer mBuffer; // 初始化ByteBuffer,長度為arr數組的長度*4,因為一個int占4個字節 ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4); // 數組排列用nativeOrder qbb.order(ByteOrder.nativeOrder()); mBuffer = qbb.asIntBuffer(); mBuffer.put(arr); mBuffer.position(0); return mBuffer; }

將float[]數組轉為OpenGl 所需要的FloatBuffer

private FloatBuffer floatBufferUtil(float[] arr) { FloatBuffer mBuffer; // 初始化ByteBuffer,長度為arr數組的長度*4,因為一個int占4個字節 ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4); // 數組排列用nativeOrder qbb.order(ByteOrder.nativeOrder()); mBuffer = qbb.asFloatBuffer(); mBuffer.put(arr); mBuffer.position(0); return mBuffer; }

當然,依葫蘆畫瓢,如何將short[]轉ShortBuffer這個就照著寫就ok了

private ShortBuffer shortBufferUtil(short[] arr){ ShortBuffer mBuffer; // 初始化ByteBuffer,長度為arr數組的長度*2,因為一個short占2個字節 ByteBuffer dlb = ByteBuffer.allocateDirect(// (# of coordinate values * 2 bytes per short)arr.length * 2); dlb.order(ByteOrder.nativeOrder()); mBuffer = dlb.asShortBuffer(); mBuffer.put(arr); mBuffer.position(0); return mBuffer; }

創建完形狀之后,我們就要進行我們的第二步了,將這些形狀渲染到GlSurfaceView中去。主要可分為下面幾步: 1. 首先我們需要在GlSurfaceView.Renderer中初始化需要渲染的幾何圖形

private Triangle mTriangle; private Square mSquare; public void onSurfaceCreated(GL10 unused, EGLConfig config) { // 設置背景顏色 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 初始化triangle mTriangle = new Triangle(); // 初始化 square mSquare = new Square(); }

二.:繪制圖形,因為需要提供很多細節的圖形渲染管線,所以繪制圖形前至少需要一個頂點著色器來繪制形狀和一個片段著色器的顏色,形狀。這些著色器必須被編譯,然后加入到一個OpenGL ES程序,然后將其用于繪制形狀。簡單介紹下這幾個概念: - 頂點著色器(Vertex Shader)頂點著色器是GPU上運行的小程序,由名字可以知道,通過它來處理頂點,他用于渲染圖形頂點的OpenGL ES圖形代碼。頂點著色器可用來修改圖形的位置,顏色,紋理坐標,不過不能用來創建新的頂點坐標。 - 片段著色器(Fragment Shader ) 用于呈現與顏色或紋理的形狀的面的OpenGL ES代碼。 - 項目(Program) -包含要用于繪制一個或多個形狀著色器的OpenGL ES的對象。

下面給Triangle類定義一個基本的著色器代碼:

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;' + '}'; ...}

當然,上面我們創建了著色器的編譯代碼,代碼編寫完成,需要寫個方法來執行這段代碼,這里我們在渲染器中寫一個如下方法來執行著色器代碼:

public static int loadShader(int type, String shaderCode){ // 創造頂點著色器類型(GLES20.GL_VERTEX_SHADER) // 或者是片段著色器類型 (GLES20.GL_FRAGMENT_SHADER) int shader = GLES20.glCreateShader(type); // 添加上面編寫的著色器代碼并編譯它 GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; }

這里有一點需要注意,因為著色器的代碼執行是很昂貴滴,所以避免多次執行,需要我們一般將執行代碼的邏輯寫帶圖形類的構造方法中。比如上面的Triangle,我們就這么寫:

private final int mProgram;public Triangle() { ... ...//數據轉換 int vertexShader = OneGlRenderer.loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode); int fragmentShader = OneGlRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode); // 創建空的OpenGL ES程序 mProgram = GLES20.glCreateProgram(); // 添加頂點著色器到程序中 GLES20.glAttachShader(mProgram, vertexShader); // 添加片段著色器到程序中 GLES20.glAttachShader(mProgram, fragmentShader); // 創建OpenGL ES程序可執行文件 GLES20.glLinkProgram(mProgram); }

最后,所有繪制的所有基本配置都配置完成之后,我們來寫繪制圖形的方法,我們在圖形類(Triangle)中創建一個繪制的方法onDraw(),可以在onDraw()方法中設置繪制邏輯。

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 public void draw() { // 將程序添加到OpenGL ES環境 GLES20.glUseProgram(mProgram); // 獲取頂點著色器的位置的句柄 mPositionHandle = GLES20.glGetAttribLocation(mProgram, 'vPosition'); // 啟用三角形頂點位置的句柄 GLES20.glEnableVertexAttribArray(mPositionHandle); //準備三角形坐標數據 GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,GLES20.GL_FLOAT, false,vertexStride, vertexBuffer); // 獲取片段著色器的顏色的句柄 mColorHandle = GLES20.glGetUniformLocation(mProgram, 'vColor'); // 設置繪制三角形的顏色 GLES20.glUniform4fv(mColorHandle, 1, color, 0); // 繪制三角形 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount); // 禁用頂點數組 GLES20.glDisableVertexAttribArray(mPositionHandle); }

完成上面所有步驟,只需要在GlSurfaceView.Renderer的onDrawFrame()方法中調用圖形類的繪制方法即可(上面的onDraw()):

public void onDrawFrame(GL10 unused) { mTriangle.draw(); }

最后的呈現效果如下圖所示:

Android openGl 繪制簡單圖形的實現示例

運用投影和相機視圖

通常情況下,OpenGl中展示的視圖和在Android上顯示的圖形會有偏差。借用官方圖片:

Android openGl 繪制簡單圖形的實現示例

當然我們可以通過矩陣轉換來解決這種問題,讓OpenGl上的視圖在任何android設備上顯示的比例都是一樣的,這里說下什么是投影和相機視圖:

投影的定義

使用OpenGl繪制的3D圖形,需要展示在移動端2D設備上,這就是投影。Android OpenGl ES中有兩種投影方式:一種是正交投影,一種是透視投影:

正交投影投影物體的帶下不會隨觀察點的遠近而發生變化,我們可以使用下面方法來執行正交投影:

Matrix.orthoM (float[] m, //接收正交投影的變換矩陣int mOffset, //變換矩陣的起始位置(偏移量)float left, //相對觀察點近面的左邊距float right, //相對觀察點近面的右邊距float bottom, //相對觀察點近面的下邊距float top, //相對觀察點近面的上邊距float near, //相對觀察點近面距離float far) //相對觀察點遠面距離

透視投影:隨觀察點的距離變化而變化,觀察點越遠,視圖越小,反之越大,我們可以通過如下方法來設置透視投影:

Matrix.frustumM (float[] m, //接收透視投影的變換矩陣int mOffset, //變換矩陣的起始位置(偏移量)float left, //相對觀察點近面的左邊距float right, //相對觀察點近面的右邊距float bottom, //相對觀察點近面的下邊距float top, //相對觀察點近面的上邊距float near, //相對觀察點近面距離float far) //相對觀察點遠面距離

相機視圖

什么是相機視圖?簡單來說生活中我們拍照,你站的高度,拿相機的位置,姿勢不同,拍出來的照片也就不一樣,相機視圖就是來修改相機位置,觀察方式以及相機的傾斜角度等屬性。我們可以通過下面方法來修改相機視圖屬性:

Matrix.setLookAtM (float[] rm, //接收相機變換矩陣int rmOffset, //變換矩陣的起始位置(偏移量)float eyeX,float eyeY, float eyeZ, //相機位置float centerX,float centerY,float centerZ, //觀察點位置float upX,float upY,float upZ) //up向量在xyz上的分量

轉換矩陣(變換矩陣)

轉換矩陣用來做什么的呢?是否記得上面我們繪制的圖形坐標需要轉換為OpenGl中能處理的小端字節序(LittleEdian),沒錯,轉換矩陣就是用來將數據轉為OpenGl ES可用的數據字節,我們將相機視圖和投影設置的數據相乘,便得到一個轉換矩陣,然后我們再講此矩陣傳給頂點著色器,具體使用方法及參數說明如下:

Matrix.multiplyMM (float[] result, //接收相乘結果int resultOffset, //接收矩陣的起始位置(偏移量)float[] lhs, //左矩陣int lhsOffset, //左矩陣的起始位置(偏移量)float[] rhs, //右矩陣int rhsOffset) //右矩陣的起始位置(偏移量)

下面簡單講解下如何使用投影和相機視圖來實現矩陣變換并傳遞給頂點著色器;

定義一個投影:

// mMVPMatrix is an abbreviation for 'Model View Projection Matrix' private final float[] mMVPMatrix = new float[16]; private final float[] mProjectionMatrix = new float[16]; private final float[] mViewMatrix = new float[16]; public void onSurfaceChanged(GL10 unused, int width, int height) { GLES20.glViewport(0, 0, width, height); float ratio = (float) width / height; // 這個投影矩陣被應用于對象坐標在onDrawFrame()方法中 Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7); }

定義一個相機視圖

@Overridepublic void onDrawFrame(GL10 unused) { ... // Set the camera position (View matrix) Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); // Calculate the projection and view transformation Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); // Draw shape mTriangle.draw(mMVPMatrix);}

修改圖形類執行代碼

public class Triangle { private final String vertexShaderCode = // This matrix member variable provides a hook to manipulate // the coordinates of the objects that use this vertex shader 'uniform mat4 uMVPMatrix;' + 'attribute vec4 vPosition;' + 'void main() {' + // the matrix must be included as a modifier of gl_Position // Note that the uMVPMatrix factor *must be first* in order // for the matrix multiplication product to be correct. ' gl_Position = uMVPMatrix * vPosition;' + '}'; // Use to access and set the view transformation private int mMVPMatrixHandle; ...}

投影和相機視圖代碼到圖形類的繪制方法中去onDraw()

public void draw(float[] mvpMatrix){ ... ... // 得到形狀的變換矩陣的句柄 mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, 'uMVPMatrix'); // 將投影和視圖轉換傳遞給著色器 GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); // 畫三角形 GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount); // 禁用頂點數組 GLES20.glDisableVertexAttribArray(mPositionHandle); }

做完這些,我們就能得到如下圖:

Android openGl 繪制簡單圖形的實現示例

沒錯,這才沒有變形的視圖。到這里,基本的通過OpenGl繪制簡單圖形就over了,下面我們講解下如何添加一些交互動作。

添加動作

前面都是簡單的動作介紹,使用OpenGl在屏幕上繪制對象是使用openGl的基本功。下面我來說下如何添加旋轉形狀。使用OpenGl的描繪對象是相對簡單的,首先需要在渲染器中創建一組旋轉矩陣,然后使用之前提到過的投影和相機視圖變換矩陣結合起來使用:

private float[] mRotationMatrix = new float[16];public void onDrawFrame(GL10 gl) { float[] scratch = new float[16]; ... // 創建一個旋轉矩陣 long time = SystemClock.uptimeMillis() % 4000L; float angle = 0.090f * ((int) time); Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f); // 將旋轉矩陣與投影和相機視圖組合在一起 // Note that the mMVPMatrix factor *must be first* in order // for the matrix multiplication product to be correct. Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0); // Draw triangle mTriangle.draw(scratch);}

運行效果圖如下:

Android openGl 繪制簡單圖形的實現示例

修改頂點顏色

一個顏色是不是太單調了?如何讓做成多彩的呢?接下來我們來做一個多彩三角形,如何來做一個多彩三角形?我們通過頂點著色器來做?;谏厦娴拇a,我們只需要做一點點改動,下面是基本步驟: 1. 修改著色器代碼 2. 將顏色值修改為float數組并轉為floatBuffer 3. 將獲取的floatBuffer傳遞給頂點著色器。

修改著色器代碼:

private final String vertexShaderCode = 'attribute vec4 vPosition;' + 'uniform mat4 uMVPMatrix;'+ 'varying vec4 vColor;'+ 'attribute vec4 aColor;'+ 'void main() {' + ' gl_Position = uMVPMatrix*vPosition;' + ' vColor=aColor;'+ '}'; private final String fragmentShaderCode = 'precision mediump float;' + 'varying vec4 vColor;' + 'void main() {' + ' gl_FragColor = vColor;' + '}';

shader的變量類型(uniform,attribute和varying)的區別

關于shader的變量類型(uniform,attribute和varying)的區別及使用,下面做下說明: 1. uniform:uniform變量在vertex和fragment兩者之間聲明方式完全一樣,則它可以在vertex和fragment共享使用。(相當于一個被vertex和fragment shader共享的全局變量)uniform變量一般用來表示:變換矩陣,材質,光照參數和顏色等信息。在代碼中通過GLES20.glGetUniformLocation(int program, String name)來獲取屬性值。并通過 GLES20.glUniformMatrix4fv(int location, int count, boolean transpose, float[] value, int offset);方法將數據傳遞給著色器。 2. attribute:這個變量只能在頂點著色器中使用(vertex Shader),用來表示頂點的數據,比如頂點坐標,頂點顏色,法線,紋理坐標等。在繪制的時候通過GLES20.glGetAttribLocation(int program, String name)來獲取變量值,通過 GLES20.glEnableVertexAttribArray(int index)來啟動句柄,最后通過 GLES20.glVertexAttribPointer(int indx,int size,int type,boolean normalized,int stride,java.nio.Buffer ptr)來設置圖形數據。 3. varying變量:這個變量只能用來在vertex和fragment shader之間傳遞數據時使用,不可以通過代碼獲取其變量值。

接來下我們進行數據轉換:

float color[] = { 1.0f, 0f, 0f, 1.0f , 0f, 1.0f, 0f, 1.0f , 0f, 0f, 1.0f, 1.0f }; public Triangle() { ... ... ByteBuffer dd = ByteBuffer.allocateDirect( color.length * 4); dd.order(ByteOrder.nativeOrder()); colorBuffer = dd.asFloatBuffer(); colorBuffer.put(color); colorBuffer.position(0); }

最后我們需要獲取著色器的句柄并設置著色器的顏色:

public void draw(float[] mvpMatrix){ ... ... /* // 獲取片段著色器的vColor成員的句柄 mColorHandle = GLES20.glGetUniformLocation(mProgram, 'vColor'); // 設置繪制三角形的顏色 GLES20.glUniform4fv(mColorHandle, 1, colorBuffer, 0);*/ //獲取片元著色器的vColor成員的句柄 mColorHandle = GLES20.glGetAttribLocation(mProgram, 'aColor'); //設置繪制三角形的顏色 GLES20.glEnableVertexAttribArray(mColorHandle); GLES20.glVertexAttribPointer(mColorHandle,4,GLES20.GL_FLOAT,false,0,colorBuffer);... ...}

Android openGl 繪制簡單圖形的實現示例

6. 參考鏈接:

opengl官網

opengl的環境搭建及基本教程

7. 項目地址:

AserbaosAndroid此項目為博主所有的系列學習的代碼匯總項目,該文章的代碼位于:opengl/OneOpenGl/OneOpenGlActivity

到此這篇關于Android openGl 繪制簡單圖形的實現示例的文章就介紹到這了,更多相關Android openGl 繪制簡單圖形內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Android
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
久久a爱视频| 国产一区二区三区成人欧美日韩在线观看| 国产欧美一区| 亚洲福利免费| 欧美亚洲国产激情| 日韩大片在线观看| 国产成人精品三级高清久久91| 国产精品黑丝在线播放| 精品三级国产| 激情五月综合| 国产精品第一| 99久久亚洲精品| 在线看片日韩| 鲁大师精品99久久久| av高清不卡| 亚洲精品综合| 国产剧情在线观看一区| 久久精品青草| 天堂va在线高清一区| 亚洲二区视频| 日韩欧美一区二区三区在线视频 | av高清一区| 麻豆mv在线观看| 91精品国产自产在线观看永久∴| 一区二区亚洲精品| 国内亚洲精品| 免费观看在线综合色| 欧美日韩中文字幕一区二区三区 | 日韩午夜av在线| 自拍自偷一区二区三区| 久久影视三级福利片| 中文精品在线| 久久久777| 国产精品黄色| 久久高清免费观看| 久久久一二三| 福利一区二区三区视频在线观看| 国产精品极品在线观看| 亚洲精品麻豆| 欧美中文日韩| 日韩欧美2区| 夜夜嗨网站十八久久| 视频一区中文| 欧美在线看片| 久久久国产精品一区二区中文| 97精品中文字幕| 久久这里只有精品一区二区| 老色鬼久久亚洲一区二区| 日本v片在线高清不卡在线观看| 国产美女久久| 五月激情久久| 亚洲欧美久久| 国产精品成人自拍| 亚洲一级黄色| 日韩和欧美的一区| 久久蜜桃资源一区二区老牛| 亚洲手机在线| 国产精品成人3p一区二区三区| 久久亚州av| 久久一区二区中文字幕| 少妇久久久久| 最新日韩欧美| 美女精品网站| 五月亚洲婷婷 | 日韩精品视频在线看| 香蕉久久夜色精品国产| 亚洲激情二区| 色婷婷久久久| 中文无码久久精品| 国产欧美成人| 国产精品一区二区美女视频免费看| se01亚洲视频| 国产精品a级| 亚洲精品美女91| 国产伦理久久久久久妇女| 精品一区不卡| 91精品国产成人观看| 日韩avvvv在线播放| 国产黄大片在线观看| 婷婷亚洲成人| 欧美日韩一区二区综合| 国产精品一页| 视频在线观看国产精品| 欧美日韩视频网站| 国产精品v亚洲精品v日韩精品| 亚洲一级少妇| 亚洲一区二区三区高清不卡| 欧美日韩一区二区三区不卡视频| 91精品国产乱码久久久久久久| 黄色日韩在线| 捆绑调教美女网站视频一区| 99pao成人国产永久免费视频| 日韩精品a在线观看91| 日韩国产欧美三级| 精品日韩视频| 国产精品免费99久久久| 激情自拍一区| 久久av免费看| 亚洲免费播放| 成人av三级| 国产精品一在线观看| 免费在线观看精品| 天堂中文在线播放| 欧美一区自拍| 国产欧美日韩精品高清二区综合区 | 国产精品巨作av| 日韩欧美2区| 欧美午夜精彩| 精品欧美一区二区三区在线观看| 国产精品黄色片| 亚洲3区在线| 国产婷婷精品| 亚洲天堂成人| 亚洲综合在线电影| 日韩美女一区二区三区在线观看| 日韩av中文字幕一区| 国产精品久久久久久久久久齐齐| 亚洲国产专区校园欧美| 欧美三级第一页| 欧美亚洲二区| 九一精品国产| 亚洲一级少妇| 久久久噜噜噜| 黄色日韩在线| 国产精品试看| 亚洲深夜福利在线观看| 在线综合亚洲| 99精品视频在线观看免费播放| 欧美aa在线观看| 99国产精品免费视频观看| 美女久久久久| 国产主播一区| 欧美日韩视频一区二区三区| 亚洲高清激情| 国产婷婷精品| 久久激情婷婷| 麻豆久久久久久| 亚洲不卡视频| 欧美偷窥清纯综合图区| 国产精品日本一区二区不卡视频| 亚洲国产影院| 久久影院一区| 黄色国产精品| 亚洲一区二区毛片| 亚洲精品在线国产| 日本不卡高清| 日韩一区二区三区在线看| 亚洲三级在线| 亚洲人妖在线| 午夜在线精品| 亚洲专区视频| 日韩成人精品一区二区| 亚洲一区欧美二区| 欧美日韩一区二区三区不卡视频| 色网在线免费观看| 亚洲特色特黄| 国产乱子精品一区二区在线观看| 麻豆精品在线观看| 午夜在线视频观看日韩17c| 欧美一区影院| 久久精品123| 水野朝阳av一区二区三区| 欧美日韩亚洲一区三区| 99成人在线| 精品免费av一区二区三区| 伊人久久亚洲| 蜜桃tv一区二区三区| 国产欧美激情| 久久国产精品99国产| 成人影视亚洲图片在线| 国产麻豆一区二区三区| 国产精品日韩精品在线播放| 国产一区2区| 欧美va天堂| 欧美国产亚洲精品| 91成人精品观看| 在线视频日韩| 蜜桃av一区| 国产精品嫩草影院在线看| 精品72久久久久中文字幕| 久久久成人网| 天堂va在线高清一区| 丰满少妇一区| 亚洲一区欧美二区| 国产精品videossex| 欧美精品国产白浆久久久久| 免费在线观看日韩欧美| 欧美aa一级| 精品视频高潮| 久久精品99久久久| 日韩精选在线| 亚洲精品日本| 性欧美69xoxoxoxo| 亚洲欧洲日本mm| 欧美日韩水蜜桃| 精品国内亚洲2022精品成人| 日韩精品91亚洲二区在线观看| 日韩在线一二三区| 亚洲在线网站| 快she精品国产999|