編輯:關於Android編程
一、基礎知識:
GL_TRIANGLE_STRIP比GL_TRIANLGES 快100% ~ 200%。
建議:盡可能地使用GL_TRIANGLE_STRIP替代GL_TRIANGLES。
二、使用方法:
1.首先以框架入手,我們一般在Android上畫一個3D的圖形,需要在MainActivity的OnCreate函數中加入如下代碼,用來進入我們的3D場景界面:
[java]
glView = new GLSurfaceView(this); // 創建一個GLSurfaceView
glView.setRenderer(new MyGLRenderer(this)); // 使用定制的渲染器
setContentView(glView);
glView = new GLSurfaceView(this); // 創建一個GLSurfaceView
glView.setRenderer(new MyGLRenderer(this)); // 使用定制的渲染器
setContentView(glView); 其中,glView為GLSurfaceView glView的引用對象,在MainActivity中的成員變量中聲明:
[java]
private GLSurfaceView glView; // 使用GLSurfaceView
private GLSurfaceView glView; // 使用GLSurfaceView
2.接下來實現3D場景中的絢爛器(GLSurfaceView.Renderer):
[java]
public class MyGLRenderer implements GLSurfaceView.Renderer {
// 實現代碼
}
public class MyGLRenderer implements GLSurfaceView.Renderer {
// 實現代碼
}
①構造函數的編寫:
[java]
/ Constructor with global application context
public MyGLRenderer(Context context) {
this.context = context;
// 設置所用圖形的數據數組緩沖區
cube = new TextureCube();
}
// Constructor with global application context
public MyGLRenderer(Context context) {
this.context = context;
// 設置所用圖形的數據數組緩沖區
cube = new TextureCube();
}
其中,TextureCube 為我們自己的紋理類,需要自己實現,後面會有實現。context和cube分別為成員變量:
[java]
private Context context; // 應用的上下文句柄
private TextureCube cube;
private Context context; // 應用的上下文句柄
private TextureCube cube;
②重載函數onSurfaceCreated,創建絢爛器時需要初始化的部分皆在此:
[java]
// Call back when the surface is first created or re-created
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
// 啟用陰影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 設置背景顏色
gl.glClearColor(0.2f, 0.4f, 0.52f, 1.0f);
// 設置深度緩存
gl.glClearDepthf(1.0f);
// 啟用深度測試
gl.glEnable(GL10.GL_DEPTH_TEST);
// 所作深度測試的類型
gl.glDepthFunc(GL10.GL_LEQUAL);
// 告訴系統對透視進行修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
// 禁止抖動以取得更好的性能
gl.glDisable(GL10.GL_DITHER);
// 設置紋理
cube.loadTexture(gl, context); // 加載紋理
gl.glEnable(GL10.GL_TEXTURE_2D); // 紋理使能
}
// Call back when the surface is first created or re-created
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
// 啟用陰影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 設置背景顏色
gl.glClearColor(0.2f, 0.4f, 0.52f, 1.0f);
// 設置深度緩存
gl.glClearDepthf(1.0f);
// 啟用深度測試
gl.glEnable(GL10.GL_DEPTH_TEST);
// 所作深度測試的類型
gl.glDepthFunc(GL10.GL_LEQUAL);
// 告訴系統對透視進行修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
// 禁止抖動以取得更好的性能
gl.glDisable(GL10.GL_DITHER);
// 設置紋理
cube.loadTexture(gl, context); // 加載紋理
gl.glEnable(GL10.GL_TEXTURE_2D); // 紋理使能
}
以上一些功能的打開和聲明,都可以在我博客之前的一些文章中找到,不在詳述。
最重要的一句就是 cube.loadTexture(gl, context); 加載紋理。
③重載函數onSurfaceChanged,當屏幕旋轉(橫屏變為豎屏)時,調用。當然,在初始化的時候也是要調用的:
[java]
// Call back after onSurfaceCreated() or whenever the window's size changes
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
if(height == 0) // 防止被零除
{
height = 1;
}
// 重置當前的視圖區域
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);
// 選擇模型觀察矩陣
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重置模型觀察矩陣
gl.glLoadIdentity();
}
// Call back after onSurfaceCreated() or whenever the window's size changes
@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
if(height == 0) // 防止被零除
{
height = 1;
}
// 重置當前的視圖區域
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);
// 選擇模型觀察矩陣
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重置模型觀察矩陣
gl.glLoadIdentity();
}
④重載函數onDrawFrame,此為一個回調函數,用來更新場景中的各個對象:
[java]
// Call back to draw the current frame.
@Override
public void onDrawFrame(GL10 gl)
{
// 清除屏幕和深度緩存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置當前的模型觀察矩陣
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -5.0f); // 向屏幕裡移動5個單位
gl.glScalef(0.8f, 0.8f, 0.8f); // 縮小80%
// 繞X軸旋轉立方體
gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);
// 繞Y軸旋轉立方體
gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);
// 繞Z軸旋轉立方體
gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);
// 正方體
cube.draw(gl);
// 每次刷新之後更新旋轉角度
xrot += 0.3f;
yrot += 0.2f;
zrot += 0.4f;
}
// Call back to draw the current frame.
@Override
public void onDrawFrame(GL10 gl)
{
// 清除屏幕和深度緩存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置當前的模型觀察矩陣
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -5.0f); // 向屏幕裡移動5個單位
gl.glScalef(0.8f, 0.8f, 0.8f); // 縮小80%
// 繞X軸旋轉立方體
gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);
// 繞Y軸旋轉立方體
gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);
// 繞Z軸旋轉立方體
gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);
// 正方體
cube.draw(gl);
// 每次刷新之後更新旋轉角度
xrot += 0.3f;
yrot += 0.2f;
zrot += 0.4f;
}
3.接下來實現3D場景中絢爛器的紋理類(TextureCube):
[java]
// 生成一個帶紋理的立方體
// 這裡指定義一個面的頂點,立方體的其他面通過平移和旋轉這個面來渲染
public class TextureCube {
// 實現代碼
}
// 生成一個帶紋理的立方體
// 這裡指定義一個面的頂點,立方體的其他面通過平移和旋轉這個面來渲染
public class TextureCube {
// 實現代碼
}
①構造函數的編寫:
[java]
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[] texCoords = { // 定義上面的面的紋理坐標
0.0f, 1.0f, // A. 左-下
1.0f, 1.0f, // B. 右-下
0.0f, 0.0f, // C. 左-上
1.0f, 0.0f // D. 右-上
};
int[] textureIDs = new int[1]; // 紋理-ID數組
// 構造函數,設置緩沖區
public TextureCube()
{
// 設置頂點數組,頂點數據為浮點數據類型。一個浮點類型的數據長度為四個字節
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder()); // 使用原生字節順序
vertexBuffer = vbb.asFloatBuffer(); // 將字節類型緩沖區轉換成浮點類型
vertexBuffer.put(vertices); // 將數據復制進緩沖區
vertexBuffer.position(0); // 定位到初始位置
// 設置紋理坐標數組緩沖區,數據類型為浮點數據
ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4);
tbb.order(ByteOrder.nativeOrder());
texBuffer = tbb.asFloatBuffer();
texBuffer.put(texCoords);
texBuffer.position(0);
}
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[] texCoords = { // 定義上面的面的紋理坐標
0.0f, 1.0f, // A. 左-下
1.0f, 1.0f, // B. 右-下
0.0f, 0.0f, // C. 左-上
1.0f, 0.0f // D. 右-上
};
int[] textureIDs = new int[1]; // 紋理-ID數組
// 構造函數,設置緩沖區
public TextureCube()
{
// 設置頂點數組,頂點數據為浮點數據類型。一個浮點類型的數據長度為四個字節
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder()); // 使用原生字節順序
vertexBuffer = vbb.asFloatBuffer(); // 將字節類型緩沖區轉換成浮點類型
vertexBuffer.put(vertices); // 將數據復制進緩沖區
vertexBuffer.position(0); // 定位到初始位置
// 設置紋理坐標數組緩沖區,數據類型為浮點數據
ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4);
tbb.order(ByteOrder.nativeOrder());
texBuffer = tbb.asFloatBuffer();
texBuffer.put(texCoords);
texBuffer.position(0);
}
②加載圖像函數的實現(loadTexture):
[java]
// 加載一個圖像到GL紋理
public void loadTexture(GL10 gl, Context context) {
gl.glGenTextures(1, textureIDs, 0); // 生成紋理ID數組
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[0]); // 綁定到紋理ID
// 設置紋理過濾方式
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
// 構造一個輸入流來加載紋理文件"res/drawable/nehe.bmp"
InputStream ins = context.getResources().openRawResource(R.drawable.nehe);
Bitmap bmp;
try {
// 讀取並將輸入流解碼成位圖
bmp = BitmapFactory.decodeStream(ins);
} finally {
try {
ins.close();
}catch(IOException e) {}
}
// 根據加載的位圖為當前綁定的紋理ID建立紋理
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
}
// 加載一個圖像到GL紋理
public void loadTexture(GL10 gl, Context context) {
gl.glGenTextures(1, textureIDs, 0); // 生成紋理ID數組
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[0]); // 綁定到紋理ID
// 設置紋理過濾方式
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
// 構造一個輸入流來加載紋理文件"res/drawable/nehe.bmp"
InputStream ins = context.getResources().openRawResource(R.drawable.nehe);
Bitmap bmp;
try {
// 讀取並將輸入流解碼成位圖
bmp = BitmapFactory.decodeStream(ins);
} finally {
try {
ins.close();
}catch(IOException e) {}
}
// 根據加載的位圖為當前綁定的紋理ID建立紋理
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
}
③繪圖函數的實現(draw):
[java]
// 繪圖
public void draw(GL10 gl){
gl.glFrontFace(GL10.GL_CCW); // 正前面為逆時針方向
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_TEXTURE_COORD_ARRAY); // 使能紋理坐標數組
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer); // 定義紋理坐標數組緩沖區
// 前
gl.glPushMatrix();
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 左
gl.glPushMatrix();
gl.glRotatef(270.0f, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 後
gl.glPushMatrix();
gl.glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 右
gl.glPushMatrix();
gl.glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 頂
gl.glPushMatrix();
gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 底
gl.glPushMatrix();
gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 恢復原來的狀態
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_CULL_FACE);
}
// 繪圖
public void draw(GL10 gl){
gl.glFrontFace(GL10.GL_CCW); // 正前面為逆時針方向
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_TEXTURE_COORD_ARRAY); // 使能紋理坐標數組
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer); // 定義紋理坐標數組緩沖區
// 前
gl.glPushMatrix();
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 左
gl.glPushMatrix();
gl.glRotatef(270.0f, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 後
gl.glPushMatrix();
gl.glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 右
gl.glPushMatrix();
gl.glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 頂
gl.glPushMatrix();
gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 底
gl.glPushMatrix();
gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
gl.glTranslatef(0.0f, 0.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glPopMatrix();
// 恢復原來的狀態
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_CULL_FACE);
}
備注說明:
在紋理映射的時候,特別要注意頂點數組和圖像紋理數組的數值和順序,如果順序不對的話,很可能出現畫出來的是個三角形,或者圖像是很怪的那種。
一、前言 正在搞IOS的微信支付和支付寶支付,焦頭爛額之時,天上掉下來一個Android分包工具的需求,覺得還蠻有意思,其實之前一直想搞一個類似的東西,正好趁著這次機會實
先看下iOS的芝麻信用分截圖這是我做的效果,還是有點差距的支付寶9.9版本芝麻信用分的實現首先初始化各種畫筆,默認的size,padding,小圓點.(因為實在找不到原版
1、itools模擬器模擬器內置文件管理器,可以方便地作開發時進行文件管理。 itools模擬器文件管理器 2、可輕松設置模擬器分辨率,支持平板分辨率設
我們先用AndroidStudio新建一個項目,選擇空白模板,然後像其中拖入兩個Button,將他們的id分別命名為btDate(顯示日期),btTime(顯示時間),他