經測試其重要範例執行畫面如下:
本社群由Nantou.py使用者社群以及國立虎尾科技大學電機資訊學院負責維護,它是一群熱愛智慧生活科技以及Python的專業教師所組成,大家一同快樂地研究有關數位生活中人工智慧、大數據、物聯網、雲端服務、APPS、福祉科技、感知網路服務、車載網路服務、及網際網路等資通訊技術,並運用這些資通訊以及Python技術來提升我們的日常生活品質,建立更好的生活環境。
2011年6月27日 星期一
2011年5月9日 星期一
[ Android OpenGL ES 教學(六)] 觸控控制
基礎閱讀:[ Android OpenGL ES 教學(五)] 貼皮技術 發表在 http://cheng-min-i-taiwan.blogspot.com/2011/05/android-opengl-es_09.html
在Google Android SDK所附的範例ApiDemo內的com.example.android.apis.graphics套件中的TouchRotateActivity.java的程式,TouchRotateActivity繼承了Activity類別,在TouchRotateActivity類別中建立了TouchSurfaceView物件,並利用setFocusableInTouchMode()函式來啟用觸控功能,TouchRotateActivity類別中的onCreate()事件處理程式的列表如下:
在TouchSurfaceView類別中,可以發現兩個onTrackballEvent()和onTouchEvent()事件函件,經由這兩個事件來改變立方體的觀察角度,這兩個事件程式列表如下:
1. 建立新專案

2. 把在Google Android SDK所附的範例ApiDemo內的com.example.android.apis.graphics套件中的TouchRotateActivity.java的程式複製到新專案所產生的程式中,完整程式如下:
3. 點擊下圖紅圈建立新的Cube類別。

4. 按下下圖finish鍵來建立新的Cube類別。

5. 把在Google Android SDK所附的範例ApiDemo內的com.example.android.apis.graphics套件中的Cube.java的程式複製到新專案所產生的程式中,完整程式如下:
6. 執行結果,記得利用觸控功能來觀察立方體。
在Google Android SDK所附的範例ApiDemo內的com.example.android.apis.graphics套件中的TouchRotateActivity.java的程式,TouchRotateActivity繼承了Activity類別,在TouchRotateActivity類別中建立了TouchSurfaceView物件,並利用setFocusableInTouchMode()函式來啟用觸控功能,TouchRotateActivity類別中的onCreate()事件處理程式的列表如下:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create our Preview view and set it as the content of our
// Activity
mGLSurfaceView = new TouchSurfaceView(this);
setContentView(mGLSurfaceView);
mGLSurfaceView.requestFocus();
mGLSurfaceView.setFocusableInTouchMode(true);
}
在TouchSurfaceView類別中,可以發現兩個onTrackballEvent()和onTouchEvent()事件函件,經由這兩個事件來改變立方體的觀察角度,這兩個事件程式列表如下:
@Override public boolean onTrackballEvent(MotionEvent e) {
mRenderer.mAngleX += e.getX() * TRACKBALL_SCALE_FACTOR;
mRenderer.mAngleY += e.getY() * TRACKBALL_SCALE_FACTOR;
requestRender();
return true;
}
@Override public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;
float dy = y - mPreviousY;
mRenderer.mAngleX += dx * TOUCH_SCALE_FACTOR;
mRenderer.mAngleY += dy * TOUCH_SCALE_FACTOR;
requestRender();
}
mPreviousX = x;
mPreviousY = y;
return true;
}
1. 建立新專案
2. 把在Google Android SDK所附的範例ApiDemo內的com.example.android.apis.graphics套件中的TouchRotateActivity.java的程式複製到新專案所產生的程式中,完整程式如下:
package com.example.opengl;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;
public class TouchRotateActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create our Preview view and set it as the content of our
// Activity
mGLSurfaceView = new TouchSurfaceView(this);
setContentView(mGLSurfaceView);
mGLSurfaceView.requestFocus();
mGLSurfaceView.setFocusableInTouchMode(true);
}
@Override
protected void onResume() {
// Ideally a game should implement onResume() and onPause()
// to take appropriate action when the activity looses focus
super.onResume();
mGLSurfaceView.onResume();
}
@Override
protected void onPause() {
// Ideally a game should implement onResume() and onPause()
// to take appropriate action when the activity looses focus
super.onPause();
mGLSurfaceView.onPause();
}
private GLSurfaceView mGLSurfaceView;
}
/**
* Implement a simple rotation control.
*
*/
class TouchSurfaceView extends GLSurfaceView {
public TouchSurfaceView(Context context) {
super(context);
mRenderer = new CubeRenderer();
setRenderer(mRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
@Override public boolean onTrackballEvent(MotionEvent e) {
mRenderer.mAngleX += e.getX() * TRACKBALL_SCALE_FACTOR;
mRenderer.mAngleY += e.getY() * TRACKBALL_SCALE_FACTOR;
requestRender();
return true;
}
@Override public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;
float dy = y - mPreviousY;
mRenderer.mAngleX += dx * TOUCH_SCALE_FACTOR;
mRenderer.mAngleY += dy * TOUCH_SCALE_FACTOR;
requestRender();
}
mPreviousX = x;
mPreviousY = y;
return true;
}
/**
* Render a cube.
*/
private class CubeRenderer implements GLSurfaceView.Renderer {
public CubeRenderer() {
mCube = new Cube();
}
public void onDrawFrame(GL10 gl) {
/*
* Usually, the first thing one might want to do is to clear
* the screen. The most efficient way of doing this is to use
* glClear().
*/
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
/*
* Now we're ready to draw some 3D objects
*/
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -3.0f);
gl.glRotatef(mAngleX, 0, 1, 0);
gl.glRotatef(mAngleY, 1, 0, 0);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
mCube.draw(gl);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
/*
* Set our projection matrix. This doesn't have to be done
* each time we draw, but usually a new projection needs to
* be set when the viewport is resized.
*/
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
/*
* By default, OpenGL enables features that improve quality
* but reduce performance. One might want to tweak that
* especially on software renderer.
*/
gl.glDisable(GL10.GL_DITHER);
/*
* Some one-time OpenGL initialization can be made here
* probably based on features of this particular context
*/
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
GL10.GL_FASTEST);
gl.glClearColor(1,1,1,1);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glEnable(GL10.GL_DEPTH_TEST);
}
private Cube mCube;
public float mAngleX;
public float mAngleY;
}
private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
private final float TRACKBALL_SCALE_FACTOR = 36.0f;
private CubeRenderer mRenderer;
private float mPreviousX;
private float mPreviousY;
}
3. 點擊下圖紅圈建立新的Cube類別。
4. 按下下圖finish鍵來建立新的Cube類別。
5. 把在Google Android SDK所附的範例ApiDemo內的com.example.android.apis.graphics套件中的Cube.java的程式複製到新專案所產生的程式中,完整程式如下:
package com.example.opengl;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Cube {
public Cube()
{
int one = 0x10000;
int vertices[] = {
-one, -one, -one,
one, -one, -one,
one, one, -one,
-one, one, -one,
-one, -one, one,
one, -one, one,
one, one, one,
-one, one, one,
};
int colors[] = {
0, 0, 0, one,
one, 0, 0, one,
one, one, 0, one,
0, one, 0, one,
0, 0, one, one,
one, 0, one, one,
one, one, one, one,
0, one, one, one,
};
byte indices[] = {
0, 4, 5, 0, 5, 1,
1, 5, 6, 1, 6, 2,
2, 6, 7, 2, 7, 3,
3, 7, 4, 3, 4, 0,
4, 7, 6, 4, 6, 5,
3, 0, 1, 3, 1, 2
};
// Buffers to be passed to gl*Pointer() functions
// must be direct, i.e., they must be placed on the
// native heap where the garbage collector cannot
// move them.
//
// Buffers with multi-byte datatypes (e.g., short, int, float)
// must have their byte order set to native order
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
vbb.order(ByteOrder.nativeOrder());
mVertexBuffer = vbb.asIntBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
cbb.order(ByteOrder.nativeOrder());
mColorBuffer = cbb.asIntBuffer();
mColorBuffer.put(colors);
mColorBuffer.position(0);
mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
mIndexBuffer.put(indices);
mIndexBuffer.position(0);
}
public void draw(GL10 gl)
{
gl.glFrontFace(gl.GL_CW);
gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer);
gl.glColorPointer(4, gl.GL_FIXED, 0, mColorBuffer);
gl.glDrawElements(gl.GL_TRIANGLES, 36, gl.GL_UNSIGNED_BYTE, mIndexBuffer);
}
private IntBuffer mVertexBuffer;
private IntBuffer mColorBuffer;
private ByteBuffer mIndexBuffer;
}
6. 執行結果,記得利用觸控功能來觀察立方體。
[ Android OpenGL ES 教學(五)] 貼皮技術
基礎閱讀:[ Android OpenGL ES 教學(四)] 添加顏色轉換相關方法 發表在 http://cheng-min-i-taiwan.blogspot.com/2011/05/android-opengl-es.html
延伸閱讀:[ Android OpenGL ES 教學(六)] 觸控控制 發表在
http://cheng-min-i-taiwan.blogspot.com/2011/05/android-opengl-es_498.html
參考文章:OpenGL ES Tutorial for Android – Part VI – Textures 發表在http://blog.jayway.com/2010/12/30/opengl-es-tutorial-for-android-%E2%80%93-part-vi-textures/
貼皮後的結果

貼皮後的結果(含顏色對映處理)

貼皮除了要載入一張位元圖外,在貼皮質地使用的坐標要特別注意

社員可以試著改變質地坐標中的數值,可以達到放大或縮小位元圖的目的。
延伸閱讀:[ Android OpenGL ES 教學(六)] 觸控控制 發表在
http://cheng-min-i-taiwan.blogspot.com/2011/05/android-opengl-es_498.html
參考文章:OpenGL ES Tutorial for Android – Part VI – Textures 發表在http://blog.jayway.com/2010/12/30/opengl-es-tutorial-for-android-%E2%80%93-part-vi-textures/
貼皮後的結果
貼皮後的結果(含顏色對映處理)
貼皮除了要載入一張位元圖外,在貼皮質地使用的坐標要特別注意
社員可以試著改變質地坐標中的數值,可以達到放大或縮小位元圖的目的。
OpenGLActivity.java 程式列表
package nkut.cce.smartliving.opengl;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class OpenGLActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GLSurfaceView view = new GLSurfaceView(this);
OpenGLRenderer render = new OpenGLRenderer();
// 載入位元圖
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.icon);
render.setBitmap(bitmap);
view.setRenderer(render);
setContentView(view);
}
}
OpenGLRender.java程式列表
package nkut.cce.smartliving.opengl;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.graphics.Bitmap;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
public class OpenGLRenderer implements Renderer {
private Square square;
private float angle = 0;
public OpenGLRenderer() {
// 初始化
square = new Square();
}
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
// 清除螢幕和深度緩衝區
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 以單位矩陣取代目前的矩陣
gl.glLoadIdentity();
// Z軸轉置 10 單位
gl.glTranslatef(0, 0, -10);
// 第一個方形
// 存儲目前陣列
gl.glPushMatrix();
// 反時鐘旋轉
gl.glRotatef(angle, 0, 0, 1);
// 畫出第一個方形
square.draw(gl);
// 復原成最後的矩陣
gl.glPopMatrix();
// 第二個方形
// 存儲目前陣列
gl.glPushMatrix();
// 在移動前先旋轉, 讓第二個方形圍繞著第一個方形旋轉
gl.glRotatef(-angle, 0, 0, 1);
// 移動第二個方形
gl.glTranslatef(2, 0, 0);
// 調整其大小為第一個方形的一半
gl.glScalef(.5f, .5f, .5f);
// 畫出第二個方形
square.draw(gl);
// 第三個方形
// 存儲目前陣列
gl.glPushMatrix();
// 讓第三個方形圍繞著第二個方形旋轉
gl.glRotatef(-angle, 0, 0, 1);
// 移動第三個方形
gl.glTranslatef(2, 0, 0);
// 調整其大小為第二個方形的一半
gl.glScalef(.5f, .5f, .5f);
// 以自己為中心旋轉
gl.glRotatef(angle * 10, 0, 0, 1);
// 畫出第三個方形.
square.draw(gl);
// 復原成第三個方形前的矩陣
gl.glPopMatrix();
// 復原成第二個方形前的矩陣.
gl.glPopMatrix();
// 增加角度
angle++;
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
// 設定新視域視窗的大小
gl.glViewport(0, 0, width, height);
// 選擇投射的陣列模式
gl.glMatrixMode(GL10.GL_PROJECTION);
// 重設投射陣
gl.glLoadIdentity();
// 計算視窗的寬高比率
GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,
100.0f);
// 選擇MODELVIEW陣列
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重設MODELVIEW陣列
gl.glLoadIdentity();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
// 設定背景顏色為黑色, 格式是RGBA
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
// 設定流暢的陰影模式
gl.glShadeModel(GL10.GL_SMOOTH);
// 深度緩區的設定
gl.glClearDepthf(1.0f);
// 啟動深度的測試
gl.glEnable(GL10.GL_DEPTH_TEST);
// GL_LEQUAL深度函式測試
gl.glDepthFunc(GL10.GL_LEQUAL);
// 設定很好的角度計算模式
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
public void setBitmap(Bitmap bitmap) {
// TODO Auto-generated method stub
square.setBitmap(bitmap);
}
}
square.java程式列表
package nkut.cce.smartliving.opengl;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.graphics.Bitmap;
import android.opengl.GLUtils;
public class Square {
// 點的陣列
private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, 左上角
-1.0f, -1.0f, 0.0f, // 1, 左下角
1.0f, -1.0f, 0.0f, // 2, 右下角
1.0f, 1.0f, 0.0f, // 3, 右上角
};
// 將顏色資訊對應到點陣列上
float[] colors = { 1f, 0f, 0f, 1f, // 左上角 0 red
0f, 1f, 0f, 1f, // 左下角 1 green
0f, 0f, 1f, 1f, // 右下角 2 blue
1f, 0f, 1f, 1f, // 右上角 3 magenta
};
// 質地坐標
float texture[] = { 0.0f, 0.0f, //
0.0f, 1.0f, //
1.0f, 1.0f, //
1.0f, 0.0f, //
};
// 連接點的次序
private short[] indices = { 0, 1, 2, 0, 2, 3 };
// 點的緩衝區
private FloatBuffer vertexBuffer;
// 索引值緩衝區
private ShortBuffer indexBuffer;
// 顏色緩衝區
private FloatBuffer colorBuffer;
// 質地緩衝區
private FloatBuffer textureBuffer;
Bitmap bitmap;
public Square() {
// 浮點數是4位元組因此需要把點陣列長度乘以4
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
// 短整數是2位元組因此需要把點陣列長度乘以2
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
// 浮點數是4位元組,顏色(RGBA)
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
ByteBuffer byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
textureBuffer = byteBuf.asFloatBuffer();
textureBuffer.put(texture);
textureBuffer.position(0);
}
/**
* 畫圖函式
*
* @param gl
*/
public void draw(GL10 gl) {
// 逆時鐘
gl.glFrontFace(GL10.GL_CCW);
// 啟動CULL_FACE
gl.glEnable(GL10.GL_CULL_FACE);
// 刪除多邊形的背景
gl.glCullFace(GL10.GL_BACK);
// 啟動點的緩衝區
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// 指定位置和資料格式
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
// 在渲染期間啟用顏色緩衝區
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// 指定顏色緩衝區。
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
// 建立質地陣列
int[] textures = new int[1];
// 告訴OpenGL產生第幾個質地
gl.glGenTextures(1, textures, 0);
// 指定要用那一質地
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// 載入質地位元圖
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
// 啟動質地功能
gl.glEnable(GL10.GL_TEXTURE_2D);
// 使用UV坐標
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// 指定質地緩衝區
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer); // 以三點劃出三角形
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
GL10.GL_UNSIGNED_SHORT, indexBuffer);
// 除能點的緩衝區
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
// 除能CULL_FACE
gl.glDisable(GL10.GL_CULL_FACE);
// 除能UV坐標
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// 除能質地的使用
gl.glDisable(GL10.GL_TEXTURE_2D); }
public void setBitmap(Bitmap bitmap) {
// TODO Auto-generated method stub
this.bitmap = bitmap;
}}
2011年5月8日 星期日
[ Android OpenGL ES 教學(四)] 添加顏色
基礎閱讀:[ Android OpenGL ES 教學(三)] 轉換相關方法 發表在http://cheng-min-i-taiwan.blogspot.com/2011/04/android-opengl-es_3388.html
延伸閱讀:[ Android OpenGL ES 教學(五)] 貼皮技術 發表在 http://cheng-min-i-taiwan.blogspot.com/2011/05/android-opengl-es_09.html
參考文章:OpenGL ES Tutorial for Android – Part IV – Adding colors 發表在http://blog.jayway.com/2010/01/14/opengl-es-tutorial-for-android-%E2%80%93-part-iv-adding-colors/
今天試著從參考文章中學習如何在三個旋轉的四方形上添加顏色

首先您必須宣告一個顏色的陣列來對映到四邊形的四個角,每一個角的顏色都包括紅,藍,綠,及透明度的資訊, 其宣告如下:
// 將顏色資訊對應到點陣列上
float[] colors = { 1f, 0f, 0f, 1f, // 左上角 0 red
0f, 1f, 0f, 1f, // 左下角 1 green
0f, 0f, 1f, 1f, // 右下角 2 blue
1f, 0f, 1f, 1f, // 右上角 3 magenta
};
另外也必須宣告一個儲存顏色的浮點緩衝區
// 顏色緩衝區
private FloatBuffer colorBuffer;
把顏色的資訊放到衝區中
// 浮點數是4位元組,顏色(RGBA) * 4 位元組
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
最後在畫出四方形前將顏色緩衝區打開並指定顏色緩衝區。
// 在渲染期間啟用顏色緩衝區
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// 指定顏色緩衝區。
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
以下是Square.java完整的列表, 粗體字表示新增部份
延伸閱讀:[ Android OpenGL ES 教學(五)] 貼皮技術 發表在 http://cheng-min-i-taiwan.blogspot.com/2011/05/android-opengl-es_09.html
參考文章:OpenGL ES Tutorial for Android – Part IV – Adding colors 發表在http://blog.jayway.com/2010/01/14/opengl-es-tutorial-for-android-%E2%80%93-part-iv-adding-colors/
今天試著從參考文章中學習如何在三個旋轉的四方形上添加顏色
首先您必須宣告一個顏色的陣列來對映到四邊形的四個角,每一個角的顏色都包括紅,藍,綠,及透明度的資訊, 其宣告如下:
// 將顏色資訊對應到點陣列上
float[] colors = { 1f, 0f, 0f, 1f, // 左上角 0 red
0f, 1f, 0f, 1f, // 左下角 1 green
0f, 0f, 1f, 1f, // 右下角 2 blue
1f, 0f, 1f, 1f, // 右上角 3 magenta
};
另外也必須宣告一個儲存顏色的浮點緩衝區
// 顏色緩衝區
private FloatBuffer colorBuffer;
把顏色的資訊放到衝區中
// 浮點數是4位元組,顏色(RGBA) * 4 位元組
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
最後在畫出四方形前將顏色緩衝區打開並指定顏色緩衝區。
// 在渲染期間啟用顏色緩衝區
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// 指定顏色緩衝區。
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
以下是Square.java完整的列表, 粗體字表示新增部份
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Square {
// 點的陣列
private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, 左上角
-1.0f, -1.0f, 0.0f, // 1, 左下角
1.0f, -1.0f, 0.0f, // 2, 右下角
1.0f, 1.0f, 0.0f, // 3, 右上角
};
// 將顏色資訊對應到點陣列上
float[] colors = { 1f, 0f, 0f, 1f, // 左上角 0 red
0f, 1f, 0f, 1f, // 左下角 1 green
0f, 0f, 1f, 1f, // 右下角 2 blue
1f, 0f, 1f, 1f, // 右上角 3 magenta
};
// 連接點的次序
private short[] indices = { 0, 1, 2, 0, 2, 3 };
// 點的緩衝區
private FloatBuffer vertexBuffer;
// 索引值緩衝區
private ShortBuffer indexBuffer;
// 顏色緩衝區
private FloatBuffer colorBuffer;
public Square() {
// 浮點數是4位元組因此需要把點陣列長度乘以4
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
// 短整數是2位元組因此需要把點陣列長度乘以2
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
// 浮點數是4位元組,顏色(RGBA) * 4 位元組
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
}
/**
* 畫圖函式
*
* @param gl
*/
public void draw(GL10 gl) {
// 逆時鐘
gl.glFrontFace(GL10.GL_CCW);
// 啟動CULL_FACE
gl.glEnable(GL10.GL_CULL_FACE);
// 刪除多邊形的背景
gl.glCullFace(GL10.GL_BACK);
// 啟動點的緩衝區
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// 指定位置和資料格式
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
// 在渲染期間啟用顏色緩衝區
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
// 指定顏色緩衝區。
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
// 以三點劃出三角形
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
GL10.GL_UNSIGNED_SHORT, indexBuffer);
// 除能點的緩衝區
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
// 除能CULL_FACE
gl.glDisable(GL10.GL_CULL_FACE);
}
}
2011年4月17日 星期日
[ Android OpenGL ES 教學(三)] 轉換相關方法
基礎閱讀:[ Android OpenGL ES 教學(二)] 建立多邊形 發表在http://cheng-min-i-taiwan.blogspot.com/2011/04/android-opengl-es_17.html
延伸閱讀:[ Android OpenGL ES 教學(四)] 添加顏色 發表在 http://cheng-min-i-taiwan.blogspot.com/2011/05/android-opengl-es.html
參考文章:OpenGL ES Tutorial for Android – Part III – Transformations 發表在 http://blog.jayway.com/2010/01/01/opengl-es-tutorial-for-android-–-part-iii-–-transformations/

(以下圖形摘自參考文章)
坐標系統

轉換或移動
可以利用下列函式
public abstract void glTranslatef (float x, float y, float z)

旋轉
可以利用下列函式
public abstract void glRotatef(float angle, float x, float y, float z)

縮小或放大
可以利用下列函式
public abstract void glScalef (float x, float y, float z)

其他常用函式
1. 以單位矩陣取代目前的矩陣
public abstract void glLoadIdentity()
2. 儲存目前陣列
public abstract void glPushMatrix()
3. 恢復以前儲存陣列
public abstract void glPopMatrix()
以列是OpenGLRenderer.java程式列表(新增的程式用藍色字表示)
延伸閱讀:[ Android OpenGL ES 教學(四)] 添加顏色 發表在 http://cheng-min-i-taiwan.blogspot.com/2011/05/android-opengl-es.html
參考文章:OpenGL ES Tutorial for Android – Part III – Transformations 發表在 http://blog.jayway.com/2010/01/01/opengl-es-tutorial-for-android-–-part-iii-–-transformations/
(以下圖形摘自參考文章)
坐標系統
轉換或移動
可以利用下列函式
public abstract void glTranslatef (float x, float y, float z)
旋轉
可以利用下列函式
public abstract void glRotatef(float angle, float x, float y, float z)
縮小或放大
可以利用下列函式
public abstract void glScalef (float x, float y, float z)
其他常用函式
1. 以單位矩陣取代目前的矩陣
public abstract void glLoadIdentity()
2. 儲存目前陣列
public abstract void glPushMatrix()
3. 恢復以前儲存陣列
public abstract void glPopMatrix()
以列是OpenGLRenderer.java程式列表(新增的程式用藍色字表示)
package nkut.cce.smartliving.opengl;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
public class OpenGLRenderer implements Renderer {
private Square square;
private float angle = 0;
public OpenGLRenderer() {
// 初始化
square = new Square();
}
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
// 清除螢幕和深度緩衝區
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 以單位矩陣取代目前的矩陣
gl.glLoadIdentity();
// Z軸轉置 10 單位
gl.glTranslatef(0, 0, -10);
// 第一個方形
// 存儲目前陣列
gl.glPushMatrix();
// 反時鐘旋轉
gl.glRotatef(angle, 0, 0, 1);
// 畫出第一個方形
square.draw(gl);
// 復原成最後的矩陣
gl.glPopMatrix();
// 第二個方形
// 存儲目前陣列
gl.glPushMatrix();
// 在移動前先旋轉, 讓第二個方形圍繞著第一個方形旋轉
gl.glRotatef(-angle, 0, 0, 1);
// 移動第二個方形
gl.glTranslatef(2, 0, 0);
// 調整其大小為第一個方形的一半
gl.glScalef(.5f, .5f, .5f);
// 畫出第二個方形
square.draw(gl);
// 第三個方形
// 存儲目前陣列
gl.glPushMatrix();
// 讓第三個方形圍繞著第二個方形旋轉
gl.glRotatef(-angle, 0, 0, 1);
// 移動第三個方形
gl.glTranslatef(2, 0, 0);
// 調整其大小為第二個方形的一半
gl.glScalef(.5f, .5f, .5f);
// 以自己為中心旋轉
gl.glRotatef(angle * 10, 0, 0, 1);
// 畫出第三個方形.
square.draw(gl);
// 復原成第三個方形前的矩陣
gl.glPopMatrix();
// 復原成第二個方形前的矩陣.
gl.glPopMatrix();
// 增加角度
angle++;
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
// 設定新視域視窗的大小
gl.glViewport(0, 0, width, height);
// 選擇投射的陣列模式
gl.glMatrixMode(GL10.GL_PROJECTION);
// 重設投射陣
gl.glLoadIdentity();
// 計算視窗的寬高比率
GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,
100.0f);
// 選擇MODELVIEW陣列
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重設MODELVIEW陣列
gl.glLoadIdentity();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
// 設定背景顏色為黑色, 格式是RGBA
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
// 設定流暢的陰影模式
gl.glShadeModel(GL10.GL_SMOOTH);
// 深度緩區的設定
gl.glClearDepthf(1.0f);
// 啟動深度的測試
gl.glEnable(GL10.GL_DEPTH_TEST);
// GL_LEQUAL深度函式測試
gl.glDepthFunc(GL10.GL_LEQUAL);
// 設定很好的角度計算模式
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
}
[ Android OpenGL ES 教學(二)] 建立多邊形
基礎閱讀:http://cheng-min-i-taiwan.blogspot.com/2011/04/android-opengl-es.html
延伸閱讀:[ Android OpenGL ES 教學(三)] 轉換相關方法 發表在 http://cheng-min-i-taiwan.blogspot.com/2011/04/android-opengl-es_3388.html
參考文章:OpenGL ES Tutorial for Android – Part II – Building a polygon 發表在http://blog.jayway.com/2009/12/04/opengl-es-tutorial-for-android-%E2%80%93-part-ii-building-a-polygon/
在OpenGL中建立多邊形是利用點連接而成,如下圖(摘自參考文章)

上述的圖形可以轉換成點的陣列如下所示:
接下來我們來實作看看, 其步驟如下:
1. 建立Square類別

2. 以下是Square.java程式列表(新增的程式用藍色字表示)
3. 以下是OpenGLRenderer.java程式列表(新增的程式用藍色字表示)
4. 執行結果
延伸閱讀:[ Android OpenGL ES 教學(三)] 轉換相關方法 發表在 http://cheng-min-i-taiwan.blogspot.com/2011/04/android-opengl-es_3388.html
參考文章:OpenGL ES Tutorial for Android – Part II – Building a polygon 發表在http://blog.jayway.com/2009/12/04/opengl-es-tutorial-for-android-%E2%80%93-part-ii-building-a-polygon/
在OpenGL中建立多邊形是利用點連接而成,如下圖(摘自參考文章)
上述的圖形可以轉換成點的陣列如下所示:
// 點的陣列
private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, 左上角
-1.0f, -1.0f, 0.0f, // 1, 左下角
1.0f, -1.0f, 0.0f, // 2, 右下角
1.0f, 1.0f, 0.0f, // 3, 右上角
}
接下來我們來實作看看, 其步驟如下:
1. 建立Square類別
2. 以下是Square.java程式列表(新增的程式用藍色字表示)
package nkut.cce.smartliving.opengl; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import javax.microedition.khronos.opengles.GL10; public class Square { // 點的陣列 private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, 左上角 -1.0f, -1.0f, 0.0f, // 1, 左下角 1.0f, -1.0f, 0.0f, // 2, 右下角 1.0f, 1.0f, 0.0f, // 3, 右上角 }; // 連接點的次序 private short[] indices = { 0, 1, 2, 0, 2, 3 }; // 點的緩衝區 private FloatBuffer vertexBuffer; // 索引值緩衝區 private ShortBuffer indexBuffer; public Square() { // 浮點數是4位元組因此需要把點陣列長度乘以4 ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); vbb.order(ByteOrder.nativeOrder()); vertexBuffer = vbb.asFloatBuffer(); vertexBuffer.put(vertices); vertexBuffer.position(0); // 短整數是2位元組因此需要把點陣列長度乘以2 ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2); ibb.order(ByteOrder.nativeOrder()); indexBuffer = ibb.asShortBuffer(); indexBuffer.put(indices); indexBuffer.position(0); } /** * 畫圖函式 * * @param gl */ public void draw(GL10 gl) { // 逆時鐘 gl.glFrontFace(GL10.GL_CCW); // 啟動CULL_FACE gl.glEnable(GL10.GL_CULL_FACE); // 刪除多邀形的背景 gl.glCullFace(GL10.GL_BACK); // 啟動點的緩衝區 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // 指定位置和資料格式 gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); // 以三點劃出三角形 gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer); // 除能點的緩衝區 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // 除能CULL_FACE gl.glDisable(GL10.GL_CULL_FACE); } }
3. 以下是OpenGLRenderer.java程式列表(新增的程式用藍色字表示)
package nkut.cce.smartliving.opengl; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; import android.opengl.GLU; public class OpenGLRenderer implements Renderer { private Square square; public OpenGLRenderer() { // 初始化 square = new Square(); } @Override public void onDrawFrame(GL10 gl) { // TODO Auto-generated method stub // 清除螢幕和深度緩衝區 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // 以單位矩陣取代目前的矩陣 gl.glLoadIdentity(); // Z軸轉置 4 單位 gl.glTranslatef(0, 0, -4); // 畫出方形 square.draw(gl); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { // TODO Auto-generated method stub // 設定新視域視窗的大小 gl.glViewport(0, 0, width, height); // 選擇投射的陣列模式 gl.glMatrixMode(GL10.GL_PROJECTION); // 重設投射陣 gl.glLoadIdentity(); // 計算視窗的寬高比率 GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f, 100.0f); // 選擇MODELVIEW陣列 gl.glMatrixMode(GL10.GL_MODELVIEW); // 重設MODELVIEW陣列 gl.glLoadIdentity(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // TODO Auto-generated method stub // 設定背景顏色為黑色, 格式是RGBA gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // 設定流暢的陰影模式 gl.glShadeModel(GL10.GL_SMOOTH); // 深度緩區的設定 gl.glClearDepthf(1.0f); // 啟動深度的測試 gl.glEnable(GL10.GL_DEPTH_TEST); // GL_LEQUAL深度函式測試 gl.glDepthFunc(GL10.GL_LEQUAL); // 設定很好的角度計算模式 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); } }
4. 執行結果
[ Android OpenGL ES 教學(一)] 設定視域
延伸閱讀:[ Android OpenGL ES 教學(二)] 建立多邊形 發表在http://cheng-min-i-taiwan.blogspot.com/2011/04/android-opengl-es_17.html
參考文章:OpenGL ES Tutorial for Android – Part I – Setting up the view發表在http://blog.jayway.com/2009/12/03/opengl-es-tutorial-for-android-part-i/
GLSurfaceView類別可以幫助我們撰寫OpenGL ES應用程式。
一個基本OpenGL ES應用程式其步驟如下:
1. 建立專案檔

2. 查看自動產生的程式

3. 擴增GLSurfaceView類別物件的程式

(新增的程式用藍色字表示)
4. 建立新的渲染類別

5. 查看新的渲染類別程式

6. 擴增渲染類別程式,來控制視域的模式
7. 執行結果
參考文章:OpenGL ES Tutorial for Android – Part I – Setting up the view發表在http://blog.jayway.com/2009/12/03/opengl-es-tutorial-for-android-part-i/
GLSurfaceView類別可以幫助我們撰寫OpenGL ES應用程式。
- 提供一些事件處理函式碼來連接到OpenGL ES中視域系統(View System)。
- 提供一些事件處理函式碼以使OpenGL ES的工作與活動的生命週期。
- 很容易選擇合適的幀緩衝區的像素格式。
- 建立和管理一個單獨的渲染執行緒,實現了流暢的動畫。
- 提供易於使用的除錯工具用於追踪的OpenGL ES API測試和檢查錯誤。
一個基本OpenGL ES應用程式其步驟如下:
1. 建立專案檔
2. 查看自動產生的程式
3. 擴增GLSurfaceView類別物件的程式
(新增的程式用藍色字表示)
package nkut.cce.smartliving.opengl;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class OpenGLActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GLSurfaceView view = new GLSurfaceView(this);
view.setRenderer(new OpenGLRenderer()); setContentView(view);
}
}
4. 建立新的渲染類別
5. 查看新的渲染類別程式
6. 擴增渲染類別程式,來控制視域的模式
package nkut.cce.smartliving.opengl;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
public class OpenGLRenderer implements Renderer {
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
// 清除螢幕和深度緩衝區
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); }
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
// 設定新視域視窗的大小
gl.glViewport(0, 0, width, height);
// 選擇投射的陣列模式
gl.glMatrixMode(GL10.GL_PROJECTION);
// 重設投射陣
gl.glLoadIdentity();
// 計算視窗的寬高比率
GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,
100.0f);
// 選擇MODELVIEW陣列
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重設MODELVIEW陣列
gl.glLoadIdentity(); }
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
// 設定背景顏色為黑色, 格式是RGBA
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
// 設定流暢的陰影模式
gl.glShadeModel(GL10.GL_SMOOTH);
// 深度緩區的設定
gl.glClearDepthf(1.0f);
// 啟動深度的測試
gl.glEnable(GL10.GL_DEPTH_TEST);
// GL_LEQUAL深度函式測試
gl.glDepthFunc(GL10.GL_LEQUAL);
// 設定很好的角度計算模式
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); }
}
7. 執行結果
訂閱:
文章 (Atom)