1. android進行螢幕上圖畫 點和點之間畫線
Android畫筆里里是可以設置斷斷續續的風格的,可是你的代碼里沒有設置,估計就是你模擬器的問題了
2. 如何使用Android中的OpenGL ES媒體效果
Android的媒體效果框架允許開發者可以很容易的應用多種令人印象深刻的視覺效果到照片或視頻之上。作為這個媒體效果的框架,它使用GPU來處理圖片處理的過程,它僅僅接收OpenGL的紋理(texture)作為輸入。在本次教程中,你將會學習到如何使用OpenGL ES2.0將圖片資源轉化為紋理,以及如何使用框架為圖片應用不同的處理效果。
准備
為了開始本次的教程,你必須具備:
1.一款支持Android開發的IDE,如果你沒有的話,可以在Android Developer website下載最新版本的Android studio。
2.一款運行Android4.0之上Android手機,並且GPU支持OpenGL ES2.0
3.對OpenGL的基本知識了解
設置OpenGL ES環境
創建GLSurfaceView
為了顯示OpenGL的圖形,你需要使用GLSurfaceView類,就像其他任何的View子類意義,你可以將它添加到你的Activity或Fragment之上,通過在布局xml文件中定義或者在代碼中創建實例。
在本次的教程中,我們使用GLSurfaceView作為唯一的View在我們的Activity中,因此,為了簡便,我們在代碼中創建GLSurfaceView的實例並將其傳入setContentView中,這樣它將會填充你的整個手機屏幕。Activity中的onCreate方法如下:
<code class="hljs" java="">protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GLSurfaceView view = new GLSurfaceView(this);
setContentView(view);
}</code>
因為媒體效果的框架僅僅支持OpenGL ES2.0及以上的版本,所以在setEGLContextClientVersion 方法中傳入2;
<code avrasm="" class="hljs">view.setEGLContextClientVersion(2);</code>
為了確保GLSurfaceView僅僅在必要的時候進行渲染,我們在setRenderMode 方法中進行設置:
<code avrasm="" class="hljs">view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);</code>
創建Renderer
Renderer負責渲染GLSurfaceView中的內容。
創建類實現介面GLSurfaceView.Renderer,在這里我們打算將這個類命名為EffectsRenderer,添加構造函數並覆寫介面中的抽象方法,如下:
<code class="hljs" java="">public class EffectsRenderer implements GLSurfaceView.Renderer {
public EffectsRenderer(Context context){
super();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
}
@Override
public void onDrawFrame(GL10 gl) {
}
}</code>
回到Activity中調用setRenderer方法,讓GLSurfaceView使用我們創建的Renderer:
<code class="hljs" cs="">view.setRenderer(new EffectsRenderer(this));</code>
編寫Manifest文件
如果你想要發布你的App到谷歌商店,在AndroidManifest.xml文件中添加如下語句:
<code class="hljs" xml=""><uses-feature android:glesversion="0x00020000" android:required="true"></uses-feature></code>
這會確保你的app只能被安裝在支持OpenGL ES2.0的設備之上。現在OpenGL環境准備完畢。
創建一個OpenGL平面
定義頂點
GLSurfaceView是不能直接顯示一張照片的,照片首先應該被轉化為紋理,應用在OpenGL square之上。在本次教程中,我將創建一個2D平面,並且具有4個頂點。為了簡單,我將使用一個長方形,現在,創建一個新的類Square,用它來代表形狀。
<code class="hljs" cs="">public class Square {
}</code>
默認的OpenGL系統的坐標系中的原點是在中心,因此4個角的坐標可以表示為:
左下角: (-1, -1) 右下角:(1, -1) 右上角:(1, 1) 左上角:(-1, 1)
我們使用OpenGL繪制的所有的物體都應該是由三角形決定的,為了畫一個方形,我們需要兩個具有一條公共邊的三角形,那意味著這些三角形的坐標應該是:
triangle 1: (-1, -1), (1, -1), 和 (-1, 1) triangle 2: (1, -1), (-1, 1), 和 (1, 1)
創建一個float數組來代表這些頂點:
<code class="hljs" cpp="">private float vertices[] = {
-1f, -1f,
1f, -1f,
-1f, 1f,
1f, 1f,
};</code>
為了在square上定位紋理,需要確定紋理的頂點坐標,創建另一個數組來表示紋理頂點的坐標:
<code class="hljs" cpp="">private float textureVertices[] = {
0f,1f,
1f,1f,
0f,0f,
1f,0f
};</code>
創建緩沖區
這些坐標數組應該被轉變為緩沖字元(byte buffer)在OpenGL可以使用之前,接下來進行定義:
<code class="hljs" cs="">private FloatBuffer verticesBuffer;
private FloatBuffer textureBuffer;</code>
在initializeBuffers方法中去初始化這些緩沖區:使用ByteBuffer.allocateDirect來創建緩沖區,因為float是4個位元組,那麼我們需要的byte數組的長度應該為float的4倍。
下面使用ByteBuffer.nativeOrder方法來定義在底層的本地平台上的byte的順序。使用asFloatBuffer方法將ByteBuffer轉化為FloatBuffer,在FloatBuffer被創建後,我們調用put方法來將float數組放入緩沖區,最後,調用position方法來保證我們是由緩沖區的開頭進行讀取。
<code avrasm="" class="hljs">private void initializeBuffers(){
ByteBuffer buff = ByteBuffer.allocateDirect(vertices.length * 4);
buff.order(ByteOrder.nativeOrder());
verticesBuffer = buff.asFloatBuffer();
verticesBuffer.put(vertices);
verticesBuffer.position(0);
buff = ByteBuffer.allocateDirect(textureVertices.length * 4);
buff.order(ByteOrder.nativeOrder());
textureBuffer = buff.asFloatBuffer();
textureBuffer.put(textureVertices);
textureBuffer.position(0);
}</code>
創建著色器
著色器只不過是簡單的運行在GPU中的每個單獨的頂點的C程序,在本次教程中,我們使用兩種著色器:頂點著色器和片段著色器。
頂點著色器的代碼:
<code class="hljs" glsl="">attribute vec4 aPosition;
attribute vec2 aTexPosition;
varying vec2 vTexPosition;
void main() {
gl_Position = aPosition;
vTexPosition = aTexPosition;
};</code>
片段著色器的代碼
class="hljs" glsl="">precision mediump float;
uniform sampler2D uTexture;
varying vec2 vTexPosition;
void main() {
gl_FragColor = texture2D(uTexture, vTexPosition);
};</code>
如果你了解OpenGL,那麼這段代碼對你來說是熟悉的,如果你不能理解這段代碼,你可以參考OpenGL documentation。這里有一個簡明扼要的解釋:
頂點著色器負責繪制單個頂點。aPosition是一個變數被綁定到FloatBuffer上,包含著這些頂點的坐標。相似的,aTexPosition 是一個變數被綁定到FloatBuffer上,包含著紋理的坐標。gl_Position 是一個在OpenGL中創建的變數,代表每一個頂點的位置,vTexPosition是一個數組變數,它的值被傳遞到片段著色器中。
在本教程中,片段著色器負責square的著色。它使用texture2D方法從紋理中拾取顏色,並且使用一個在OpenGL中被創建的變數gl_FragColor將顏色分配到片段。
在該類中,著色器的代碼應該被轉化為String。
<code class="hljs" java="">private final String vertexShaderCode =
attribute vec4 aPosition; +
attribute vec2 aTexPosition; +
varying vec2 vTexPosition; +
void main() { +
gl_Position = aPosition; +
vTexPosition = aTexPosition; +
};
private final String fragmentShaderCode =
precision mediump float; +
uniform sampler2D uTexture; +
varying vec2 vTexPosition; +
void main() { +
gl_FragColor = texture2D(uTexture, vTexPosition); +
};</code>
創建程序
創建新的方法initializeProgram來創建一個編譯和鏈接著色器的OpenGL程序。
使用glCreateShader創建一個著色器對象,並且返回以int為表示形式的指針。為了創建頂點著色器,傳遞GL_VERTEX_SHADER給它。相似的,為了創建一個片段著色器,傳遞GL_FRAGMENT_SHADER給它。下面使用glShaderSource方法關聯相對應的著色器代碼到著色器上。使用glCompileShader編譯著色器代碼。
在編譯了著色器的代碼後,創建一段新的的程序glCreateProgram,與glCreateShader相似,它也返回一個以int為表示形式的指針。調用glAttachShader方法附著著色器到程序中,最後,調用glLinkProgram進行鏈接。
代碼:
<code class="hljs" cs="">private int vertexShader;
private int fragmentShader;
private int program;
private void initializeProgram(){
vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
GLES20.glShaderSource(vertexShader, vertexShaderCode);
GLES20.glCompileShader(vertexShader);
fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragmentShader, fragmentShaderCode);
GLES20.glCompileShader(fragmentShader);
program = GLES20.glCreateProgram();
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program);
}</code>
你可能會發現,OpenGL的方法(以gl開頭的)都是在GLES20類中,這是因為我們使用的是OpenGL ES2.0,如果我們使用更高的版本,就會用到這些類:GLES30,GLES31。
畫出形狀
現在定義draw方法來利用我們之前定義的點和著色器進行繪制。
下面是你需要做的:
1.使用glBindFramebuffer方法創建一個幀緩沖對象(FBO)
2.調用glUseProgram創建程序,就像之前所提
3.傳遞GL_BLEND給glDisable方法,在渲染過程中禁用顏色的混合。
4.調用glGetAttribLocation得到變數aPosition和aTexPosition的句柄
5.使用glVertexAttribPointer連接aPosition和aTexPosition的句柄到各自的verticesBuffer和textureBuffer
6.使用glBindTexture方法綁定紋理(作為draw方法的參數傳入)到片段著色器上
7.調用glClear方法清空GLSurfaceView的內容
8.最後,使用glDrawArrays方法畫出兩個三角形(也就是方形)
代碼:
<code avrasm="" class="hljs">public void draw(int texture){
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
GLES20.glUseProgram(program);
GLES20.glDisable(GLES20.GL_BLEND);
int positionHandle = GLES20.glGetAttribLocation(program, aPosition);
int textureHandle = GLES20.glGetUniformLocation(program, uTexture);
int texturePositionHandle = GLES20.glGetAttribLocation(program, aTexPosition);
GLES20.glVertexAttribPointer(texturePositionHandle, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
GLES20.glEnableVertexAttribArray(texturePositionHandle);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(textureHandle, 0);
GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, verticesBuffer);
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}</code>
在構造函數中添加初始化方法:
<code class="hljs" cs="">public Square(){
initializeBuffers();
initializeProgram();
}</code>
渲染OpenGL平面和紋理
現在我們的渲染器什麼也沒做,我們需要改變它來渲染我們在前面創造的平面。
首先,讓我們創建一個Bitmap,添加一張照片到res/drawable文件夾之下,我把它命名為forest.jpg,使用BitmapFactory將照片轉化為Bitmap。另外將照片的尺寸存儲下來。
改變EffectsRenderer的構造函數如下,
<code class="hljs" java="">private Bitmap photo;
private int photoWidth, photoHeight;
public EffectsRenderer(Context context){
super();
photo = BitmapFactory.decodeResource(context.getResources(), R.drawable.forest);
photoWidth = photo.getWidth();
photoHeight = photo.getHeight();
}</code>
創建一個新的方法generateSquare,將Bitmap轉化為紋理,並且出初始化Square對象,你也需要一個數組來保存對紋理的引用,使用glGenTextures來初始化這個數組,glBindTexture方法來在位置0激活紋理。
現在,調用glTexParameteri設置不同的級別,決定紋理被怎樣渲染。
設置GL_TEXTURE_MIN_FILTER(修正功能),GL_TEXTURE_MAG_FILTER(放大功能)給GL_LINEAR,確保圖片是平滑的在它被拉伸的時候。
設置GL_TEXTURE_WRAP_S和GL_TEXTURE_WRAP_T給GL_CLAMP_TO_EDGE,保證紋理不會重復。
最後調用texImage2D方法將Bitmap放置到紋理中,實現方法如下:
<code avrasm="" class="hljs">private int textures[] = new int[2];
private Square square;
private void generateSquare(){
GLES20.glGenTextures(2, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, photo, 0);
square = new Square();
}</code>
當GLSurfaceView的尺寸發生改變時,onSurfaceChanged方法被調用,這時我們需要調用glViewPort確認新的尺寸。調用glClearColor使其變為黑色,接著調用generateSquare重新初始化紋理和平面。
<code class="hljs" java="">@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0,0,width, height);
GLES20.glClearColor(0,0,0,1);
generateSquare();
}</code>
最後在onDrawFrame調用draw方法:
<code class="hljs" java="">@Override
public void onDrawFrame(GL10 gl) {
square.draw(textures[0]);
}</code>
3. android 簡單的貼圖方法,有個小問題!在線等!
簡單說就是: 第一種你用系統的控制項ImageView去展示圖片,第二種就是你自己去實現ImageView這個控制項,然後展示這個圖片。ImageView是繼承自View的,如果ImageView能滿足你的需求,可以直接用。如果你有特殊的需求,比如你要自己畫一個三角形,不用圖片。這樣這能自己去畫。
4. 在android中怎麼至上而下漸變
這個是輸出一層顏色漸變的效果,而你的是多層的,做法一樣,弄幾個小的的三角形同樣的畫法畫到上面。而顏色的值是不可能是線性的值,你只能自己定義每層三角形的顏色,這個是你要做的。 這個我直接用NDK自帶的HELLO-GL2給你弄的,就設置下三角形
5. Android OpenGLES3繪圖 - 幀緩沖
普通的OpenGL繪圖時是繪制到當前幀上面,由於GL環境跟當前屏幕進行了關聯,也就直接繪制到屏幕了。這樣有兩個問題:1. 如果有的幀計算得快,有的計算得慢,而屏幕刷新率是固定的,就會拖慢整體幀率;2. 在著色器裡面只能處理當前位置的點,沒辦法處理當前點跟其他點的關系。
如果將OpenGL計算後的幀緩存起來,不直接繪制。那麼就可以利用雙緩沖或多緩沖技術穩定幀率;在著色器裡面可以從緩存幀讀取所有點,就可以進行一些相對位置處理,比如將當前點跟周圍點顏色計算平均值,進行圖像模糊。這就是幀緩沖。
給一個普通的繪制添加幀緩沖也很方便,基本不影響原來的繪制。假設原來繪制的是三角形,那麼先配置一下幀緩沖,可以配置成2D紋理,然後進行原來的繪制,三角形就會繪制到緩沖幀的紋理上面,最後將這個2D紋理繪制到屏幕上就可以了。
實現方法:
原圖形是很多個旋轉的3D箱子
創建幀緩沖對象fbo,創建紋理對象tcbo和渲染緩沖對象rbo,將它們倆跟fbo綁定,檢查一下是否成功。
創建頂點數組緩沖對象vbo,繪制一個帶紋理的正方形,注意紋理需要用上一步創建的紋理對象tcbo
先綁定幀緩沖對象,開啟深度測試,用原圖形Shader繪制3D箱子圖案;然後解綁幀緩沖對象fbo,關閉深度測試(綁定當前屏幕),用幀緩沖Shader繪制fbo中的紋理。繪制結果跟原圖形完全一致。
有了幀緩沖後,可以在幀緩沖的片段著色器上做一些簡單的圖像處理:反相、灰度;核效果:模糊、銳化、邊緣檢測等。
6. Android (基礎自定義組件)viewpagertap滑動器
視頻地址: http://www.imooc.com/learn/615
2.1.1主要定義畫筆、三角形使用path來實現。接著定義三角形的大小(寬高)以及初始化位置。
2.1.2設置mInitTranslationX參數,表示三角形初始化的位置,相當於marginLeft,計算方式是:
mInitTranslationX = 一個tab的寬度 - 三角形寬度的/2
2.1.3設置mTranslationX參數,表示每一移動一個tab時,三角形需要平移的寬度,如圖:
2.1.4 mTabVisibleCount,自定義屬性,布局中要顯示幾個tab,如上圖4個tab
2.2.1構造中主要獲取自定義屬性值,默認為4;以及設置畫筆
2.3.1三角形的寬度 = 一個tab寬度的1/6;如果覺得寬度的大小不合適, 可以改變1/6這個常量的比例
2.3.2三角形的高度 = 高度/2如圖:
2.4.1重寫父類dispatchDraw方法,此方法在invalidate()時,會重新執行
2.4.2通過 canvas.translate()設置三角形所在位置;X軸(上去看2.1.3),Y軸為但前組件的高度(最底部)。以及調用drawPath()方法使用畫筆。
2.5.1如標題主要是通過viewpager的position和positionOffset來計算mTranslationX的值;再通過scrollTo方法來平移但前組件,最後通過invalidate()方法重繪布局
2.5.2剩下的就是一些演算法和邏輯判斷
2.6.1獲取viewpager,監聽viewpager的滑動事件,自定義setScroll方法(2.5的方法)將但前position和滑動偏移量傳進去
2.6.2在此次以及監聽的viewpager的滑動事件,如果外界也需要監聽當前viewpager的話,會起沖突;此時就需要設置回調,對外提供介面
2.6.3setTextHighLight()方法設置選中的tab為高亮顏色
2.7.1獲取list集合,將每一個item設置成一個textview,再通過setTextItemOnclickEvent()方法設置點擊事件
3.1app:visible_tab_count自定義屬性;如果不設置默認為自定義組件的COUNT_TAB_VISIBLE變數值
http://pan..com/s/1qYGUTAW
http://pan..com/s/1slpi5v3
7. OpenGl ES 2.0 Learn For Android(五)碰撞檢測
在現實生活里,碰撞是怎樣發生的呢?是兩個實體的邊緣相接觸。在OpenGL的視圖世界裡,肯定也是這個樣子。但是我們不可能把一個物體的所有點都描述出來,然後在另一個集合里看是否有點的存在。
那麼最簡單的方式,就是將一個實體看做一個球,它的假設它的外邊緣都在半徑里。那麼這個問題就簡化成了,這個半徑范圍內,是否會有其他物體存在。
那我們在OpenGL世界坐標系裡放置半徑R1一個物體。如果是世界坐標系裡放半徑R2另一物體,那麼,只要兩個物體的中心位置距離dis小於兩個物體半徑和(R1+R2),就可以認為它們相交。這個是很容易理解的。
《OpenGL ES應用開發實踐指南:Android卷》則用手指觸點檢測相交。其實這個問題並沒有發生變化。我們還是在世界坐標系裡看相交就好了。投射到屏幕的一個點,同樣可以轉換為世界坐標系裡的兩個點。這里涉及一些奇怪的技巧。比如,將一個不知道Z軸位置的點設置為-1/1。
這邊我會做一個更簡易的版本。我在世界坐標系裡放置一個邊長為1的正方體。如下圖所示。
在之前講到三角形的畫法的時候,有講到三角帶。這是openGL為了節省節點,設計的繪制方案。這里的話,頂點也按對應的方式進行排布。
為了方便,我並沒有繪制它的上下兩個面。
將上一篇的頂點下面方式賦值。顏色也對應改改。
在上一篇的時候,我只用了modelMatrix和projectionMatrix。因為上一篇使用的默認視角,也就是從Z軸往它的負方向看去。
其實這一篇方向還是不會發生變化,但是這里需要用到視角的概念,也就是 setLookAtM() 這個方法。
所以引入這三個矩陣
viewMatrix 用來保存相機矩陣。 viewProjectionMatrix 用來保存透視投影和相機矩陣的乘積。 invertedViewProjectionMatrix 用來保存 viewProjectionMatrix 的逆矩陣。
因為要拿到觸碰事件,給GlSurfaceView.setOnTouchListener
有意思的來了。我們知道,Android View的坐標系是左上角為原點,往右是x正方向,往下是y正方向。但是OpenGL ES歸一化坐標里,坐標原點在屏幕正中央,往右是x正方向,往上是y正方向。 以X軸為例,要做是的從[0,1]映射到[-1,1]。那麼x*2-1就可以達到想要的效果。這個如果後面有時間介紹構型函數,會見得很多。
我們拿到了觸點的歸一化坐標,我們要轉換成世界坐標,這樣才能做距離計算。
計算距離的工具類直接從示例中拿出來
這里光使用計算距離的方法,可以看書的9.2章。我覺得我肯定是沒作者講得好了。
使用上一篇用的投影參數,矩陣顯得有些大了,所以在使用前,先把他們都縮小到1/5大小。
這里的話我要偷些懶,把 handleTouchPress 直接用上工具類里的方法。
在將點擊的坐標轉換為世界坐標里線段的方法里,有用到 invertedViewProjectionMatrix
它是 viewProjectionMatrix 的逆矩陣
那我做的判斷是,如果點擊了正方體,則停止旋轉。效果如下
demo地址:
https://github.com/YueZhiFengMing/LearnOpenGl/tree/master/Fourth3D
8. android 中opengl畫正方體,其頂底坐標還有索引是怎麼計算和定義的
opengl es畫圖形都是通過三角形來畫的,當然還可以畫直線和點
畫圖形的時候有兩種方法:glDrawArrays( ) 和glDrawElements( )
比如畫一個由2個三角形組成的正方形,左上角坐標是l,t,右下角坐標是r,b
使用glDrawArrays繪制時,畫2個三角形,需要這樣傳:
(l,t),(r,t),(l,b)
(r,t),(r,b),(l,b)
也就是說傳的頂點數據就是按照順時針或者逆時針排好順序的,兩個三角形的6個頂點
而用glDrawElements畫的話可以這樣
float coord[4][2]={{l,t},{r,t},{r,b},{l,b}};
繪制時用索引指定頂點順序:
0,1,3
1,2,3
也就是說glDrawArrays傳輸或指定的數據是最終的真實數據,在繪制時效能更好
而glDrawElements指定的是真實數據的調用索引,在內存/顯存佔用上更節省
9. android中如何使用shape來顯示直角三角形
用一個rectangle的shape,再用一個rotate標簽包裹這個shape,設置rotate標簽的fromDegree為30,pivotX為0%,pivotY為100%。
意思就是對矩形做一個旋轉,讓它變成直角三角形。
10. android skia與opengl es 都可以畫2d圖嗎
一、基礎知識: OpenGL ES目前只支持三角形,但任何多邊形都可拆分成多個三角形,所以無所謂這個限制的存在。 1.OpenGL中的坐標點: 每一個坐標點由(X, Y, Z)組成。 定義一個三角形的頂點數組: [java] int one = 0x10000; //三角形三個頂點 private IntBuffer triggerBuffer = IntBuffer.wrap(new int[]{ 0,one,0, //上頂點 -one,-one,0, //左下點 one,-one,0,}); //右下點 int one = 0x10000; //三角形三個頂點 private IntBuffer triggerBuffer = IntBuffer.wrap(new int[]{ 0,one,0, //上頂點 -one,-one,0, //左下點 one,-one,0,}); //右下點定義一個正方形的頂點數組: [java] //正方形的4個頂點 private IntBuffer quaterBuffer = IntBuffer.wrap(new int[]{ one,one,0, -one,one,0, one,-one,0, -one,-one,0}); //正方形的4個頂點 private IntBuffer quaterBuffer = IntBuffer.wrap(new int[]{ one,one,0, -one,one,0, one,-one,0, -one,-one,0}); 2.OpenGL中的坐標系: 當調用gl.glLoadIdentity()函數之後,實際上是將當前點移動到了屏幕中心, X坐標軸從左至右,Y坐標軸從下至上,Z坐標軸從里至外。 OpenGL屏幕中心的坐標值是X軸和Y軸的0.0f點。 中心左邊的坐標值是負值,右邊是正值; 移向屏幕頂端是正值,移向屏幕底端是負值; 移入屏幕深處是負值,移出屏幕則是正值。 在繪制時,我們可以使用glTranslatef函數來移動畫筆的位置,從而使圖形顯示在我們 想要的位置。 [java] gl.glTranslatef(-1.5f, 0.0f, -6.0f); gl.glTranslatef(-1.5f, 0.0f, -6.0f);此函數,就是將畫筆沿X軸左移1.5f個單位,Y軸保持不變,Z軸向屏幕裡面移動6.0f個單位。 將視圖推入屏幕背後足夠的距離以便可以看見全部的場景,這里需要注意的是屏幕內移動的單位 必須小於我們前面通過glFrustumf方法設置的最遠距離,否則超出視角范圍,將顯示不出來。 3.OpenGL中的頂點數組: 在實際畫圖時,我們往往需要定位幾個點,然後讓OpenGL以此為基準來畫圖。在設置頂點位置前, 我們需要按照以下步驟來啟用我們的頂點數組: ①開啟頂點設置動能: [java] gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);②設置頂點數組: [java] view plainprint?gl.glVertexPointer(3, GL10.GL_FIXED, 0, triggerBuffer); gl.glVertexPointer(3, GL10.GL_FIXED, 0, triggerBuffer);glVertexPointer(int size, int type, int stride, Buffer pointer) size用於描述頂點的尺寸(本例使用XYZ,所以是3),type描述頂點的類型,固定的使用 GL_FIXED,stride描述步長,pointer指向頂點緩存,即我們創建的頂點數組。 ③繪制頂點: [java] gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3); //繪制三角形 gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); //繪制四邊形 gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3); //繪制三角形 gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); //繪制四邊形glDrawArrays(int mode, int first, int count) mode指明繪制的模式,first和count分別是開始的位置和要繪制的頂點計數。 4、實例: 畫一個三角形和正方形。 根據我們上一節的框架分析,目前,我們只需將精力集中在onDrawFrame方法裡面的繪圖操作部分了。 1. 界面編輯(reslayoutmain.xml): [java] android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> 2.代碼編輯 (srcwyfzclMyActivity.java): [java] package wyf.zcl; import android.app.Activity; import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView.Renderer; import android.os.Bundle; public class Activity01 extends Activity { Renderer render = new GLRender(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GLSurfaceView glView = new GLSurfaceView(this); glView.setRenderer(render); setContentView(glView); } } package wyf.zcl; import android.app.Activity; import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView.Renderer; import android.os.Bundle; public class Activity01 extends Activity { Renderer render = new GLRender(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GLSurfaceView glView = new GLSurfaceView(this); glView.setRenderer(render); setContentView(glView); } } (srcwyfzclGLRender.java): [java] package wyf.zcl; import java.nio.IntBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class GLRender implements Renderer { int one = 0x10000; //三角形三個頂點 private IntBuffer triggerBuffer = IntBuffer.wrap(new int[]{ 0,one,0, //上頂點 -one,-one,0, //左下點 one,-one,0,}); //右下點 //正方形的4個頂點 private IntBuffer quaterBuffer = IntBuffer.wrap(new int[]{ one,one,0, -one,one,0, one,-one,0, -one,-one,0}); @Override public void onDrawFrame(GL10 gl) { // 清除屏幕和深度緩存 gl.glClear(GL10.GL_COLOR_BUFFER_BIT GL10.GL_DEPTH_BUFFER_BIT); // 重置當前的模型觀察矩陣 gl.glLoadIdentity(); // 左移 1.5 單位,並移入屏幕 6.0 gl.glTranslatef(-1.5f, 0.0f, -6.0f); // 允許設置頂點 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // 設置三角形 gl.glVertexPointer(3, GL10.GL_FIXED, 0, triggerBuffer); //繪制三角形 gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3); // 重置當前的模型觀察矩陣 gl.glLoadIdentity(); // 左移 1.5 單位,並移入屏幕 6.0 gl.glTranslatef(1.5f, 0.0f, -6.0f); //設置和繪制正方形 gl.glVertexPointer(3, GL10.GL_FIXED, 0, quaterBuffer); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); // 取消頂點設置 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { float ratio = (float) width / height; //設置OpenGL場景的大小 gl.glViewport(0, 0, width, height); //設置投影矩陣 gl.glMatrixMode(GL10.GL_PROJECTION); //重置投影矩陣 gl.glLoadIdentity(); // 設置視口的大小 gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); // 選擇模型觀察矩陣 gl.glMatrixMode(GL10.GL_MODELVIEW); // 重置模型觀察矩陣 gl.glLoadIdentity(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // 啟用陰影平滑 gl.glShadeModel(GL10.GL_SMOOTH); // 黑色背景 gl.glClearColor(0, 0, 0, 0); // 設置深度緩存 gl.glClearDepthf(1.0f); // 啟用深度測試 gl.glEnable(GL10.GL_DEPTH_TEST); // 所作深度測試的類型 gl.glDepthFunc(GL10.GL_LEQUAL); // 告訴系統對透視進行修正 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); } } package wyf.zcl; import java.nio.IntBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; public class GLRender implements Renderer { int one = 0x10000; //三角形三個頂點 private IntBuffer triggerBuffer = IntBuffer.wrap(new int[]{ 0,one,0, //上頂點 -one,-one,0, //左下點 one,-one,0,}); //右下點 //正方形的4個頂點 private IntBuffer quaterBuffer = IntBuffer.wrap(new int[]{ one,one,0, -one,one,0, one,-one,0, -one,-one,0}); @Override public void onDrawFrame(GL10 gl) { // 清除屏幕和深度緩存 gl.glClear(GL10.GL_COLOR_BUFFER_BIT GL10.GL_DEPTH_BUFFER_BIT); // 重置當前的模型觀察矩陣 gl.glLoadIdentity(); // 左移 1.5 單位,並移入屏幕 6.0 gl.glTranslatef(-1.5f, 0.0f, -6.0f); // 允許設置頂點 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // 設置三角形 gl.glVertexPointer(3, GL10.GL_FIXED, 0, triggerBuffer); //繪制三角形 gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3); // 重置當前的模型觀察矩陣 gl.glLoadIdentity(); // 左移 1.5 單位,並移入屏幕 6.0 gl.glTranslatef(1.5f, 0.0f, -6.0f); //設置和繪制正方形 gl.glVertexPointer(3, GL10.GL_FIXED, 0, quaterBuffer); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); // 取消頂點設置 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { float ratio = (float) width / height; //設置OpenGL場景的大小 gl.glViewport(0, 0, width, height); //設置投影矩陣 gl.glMatrixMode(GL10.GL_PROJECTION); //重置投影矩陣 gl.glLoadIdentity(); // 設置視口的大小 gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); // 選擇模型觀察矩陣 gl.glMatrixMode(GL10.GL_MODELVIEW); // 重置模型觀察矩陣 gl.glLoadIdentity(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // 啟用陰影平滑 gl.glShadeModel(GL10.GL_SMOOTH); // 黑色背景 gl.glClearColor(0, 0, 0, 0); // 設置深度緩存 gl.glClearDepthf(1.0f); // 啟用深度測試 gl.glEnable(GL10.GL_DEPTH_TEST); // 所作深度測試的類型 gl.glDepthFunc(GL10.GL_LEQUAL); // 告訴系統對透視進行修正 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); } } 3.運行效果: