編輯:關於Android編程
最近因為興趣所向,開始學習OpenGL繪圖。本文以“畫球體”為點,小結一下最近所學。
然後,如果想要實現比較復雜的效果(比如3D),Canvas就很難勝任了。了解了一下,目前大部分Android游戲都是用OpenGL來實現。
OpenGL是何方神聖?實際上,最終圖像(不管是2D還是3D)都是顯示在顯示屏上,所以最終操作肯定是對一個2D的顯示內存進行操作的。而OpenGL就是提供了很多方法,幫助我們定義空間立體模型,然後通過我們輸入的各種參數,計算出映射矩陣,最終在顯示屏幕上體現出效果。
OpenGL ES (OpenGL for Embedded Systems)是專門OpenGL的API子集,專門用於手機等嵌入式平台。簡單理解就是,專門開發給“低端”的環境。刪減了很多不必要的方法,留下了最基本的。





seogKHgwLCB5MCwgejApILzGy+OjuihSzqrH8rDrvrYpCngwID0gUiAqIGNvcyhhKSAqIHNpbihiKTsKeTAgPSBSICogc2luKGEpOwp6MCA9IFIgKiBjb3MoYSkgKiBjb3MoYik7Cjxicj4KCjxoMj4+INS0wus8L2gyPgrS1M/Csr+31rLOv7y78tXfysezrdC009qjumh0dHA6Ly9ibG9nLmNzZG4ubmV0L3d1em9uZ3BvL2FydGljbGUvZGV0YWlscy83MjMwMjg1Cjxicj4KCsq508NPcGVuR0wgRVO75s28tcTSu7Djsr3W6MrHo7oKMaOsu/HIoUVHTERpc3BsYXm21M/zCjKjrLP1yry7r9PrRUdMRGlzcGxhedauvOS1xMGsvdMKM6Osu/HIoUVHTENvbmZpZ7bUz/MKNKOstLS9qEVHTENvbnRleHS21M/zCjWjrLS0vahFR0xTdXJmYWNlyrXA/Qo2o6zBrL3TRUdMQ29udGV4dNPrRUdMU3VyZmFjZQo3o6zKudPDR0zWuMHuu63NvAo4o6y2z7+qys23xUVHTENvbnRleHS21M/zCjmjrMm+s/1FR0xTdXJmYWNlCjEwo6zJvrP9RUdMQ29udGV4dAoxMaOs1tXWudPrRUdMRGlzcGxhedauvOS1xMGsvdMKPGJyPgoKQW5kcm9pZCBHTFN1cmZhY2VWaWV3IMDgo6y21E9wZW5HTCBBcGkgvfjQ0MHL0ruy47fi17Cho7Dvw6bO0sPHudzA7URpc3BsYXksQ29udGV4dCxTdXJmYWNloaPO0sPH1rvSqsq1z9ZhbmRyb2lkLm9wZW5nbC5HTFN1cmZhY2VWaWV3LlJlbmRlcmVyvdO/2ry0v8mhowo8YnI+Cgo8cHJlIGNsYXNzPQ=="brush:java;">import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLU;
import android.opengl.GLSurfaceView.Renderer;
public class OpenGLRenderer4 implements Renderer {
// 環境光
private final float[] mat_ambient = { 0.2f, 0.3f, 0.4f, 1.0f };
private FloatBuffer mat_ambient_buf;
// 平行入射光
private final float[] mat_diffuse = { 0.4f, 0.6f, 0.8f, 1.0f };
private FloatBuffer mat_diffuse_buf;
// 高亮區域
private final float[] mat_specular = { 0.2f * 0.4f, 0.2f * 0.6f, 0.2f * 0.8f, 1.0f };
private FloatBuffer mat_specular_buf;
private Sphere mSphere = new Sphere();
public volatile float mLightX = 10f;
public volatile float mLightY = 10f;
public volatile float mLightZ = 10f;
@Override
public void onDrawFrame(GL10 gl) {
// 清楚屏幕和深度緩存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置當前的模型觀察矩陣
gl.glLoadIdentity();
gl.glEnable(GL10.GL_LIGHTING);
gl.glEnable(GL10.GL_LIGHT0);
// 材質
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, mat_ambient_buf);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, mat_diffuse_buf);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, mat_specular_buf);
// 鏡面指數 0~128 越小越粗糙
gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 96.0f);
//光源位置
float[] light_position = {mLightX, mLightY, mLightZ, 0.0f};
ByteBuffer mpbb = ByteBuffer.allocateDirect(light_position.length*4);
mpbb.order(ByteOrder.nativeOrder());
FloatBuffer mat_posiBuf = mpbb.asFloatBuffer();
mat_posiBuf.put(light_position);
mat_posiBuf.position(0);
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, mat_posiBuf);
gl.glTranslatef(0.0f, 0.0f, -3.0f);
mSphere.draw(gl);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 設置輸出屏幕大小
gl.glViewport(0, 0, width, height);
// 設置投影矩陣
gl.glMatrixMode(GL10.GL_PROJECTION);
// 重置投影矩陣
gl.glLoadIdentity();
// 設置視口大小
// gl.glFrustumf(0, width, 0, height, 0.1f, 100.0f);
GLU.gluPerspective(gl, 90.0f, (float) width / height, 0.1f, 50.0f);
// 選擇模型觀察矩陣
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重置模型觀察矩陣
gl.glLoadIdentity();
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
// 對透視進行修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
// 背景:黑色
gl.glClearColor(0, 0.0f, 0.0f, 0.0f);
// 啟動陰影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 復位深度緩存
gl.glClearDepthf(1.0f);
// 啟動深度測試
gl.glEnable(GL10.GL_DEPTH_TEST);
// 所做深度測試的類型
gl.glDepthFunc(GL10.GL_LEQUAL);
initBuffers();
}
private void initBuffers() {
ByteBuffer bufTemp = ByteBuffer.allocateDirect(mat_ambient.length * 4);
bufTemp.order(ByteOrder.nativeOrder());
mat_ambient_buf = bufTemp.asFloatBuffer();
mat_ambient_buf.put(mat_ambient);
mat_ambient_buf.position(0);
bufTemp = ByteBuffer.allocateDirect(mat_diffuse.length * 4);
bufTemp.order(ByteOrder.nativeOrder());
mat_diffuse_buf = bufTemp.asFloatBuffer();
mat_diffuse_buf.put(mat_diffuse);
mat_diffuse_buf.position(0);
bufTemp = ByteBuffer.allocateDirect(mat_specular.length * 4);
bufTemp.order(ByteOrder.nativeOrder());
mat_specular_buf = bufTemp.asFloatBuffer();
mat_specular_buf.put(mat_specular);
mat_specular_buf.position(0);
}
}import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
// 計算球面頂點
public class Sphere {
public void draw(GL10 gl) {
float angleA, angleB;
float cos, sin;
float r1, r2;
float h1, h2;
float step = 30.0f;
float[][] v = new float[32][3];
ByteBuffer vbb;
FloatBuffer vBuf;
vbb = ByteBuffer.allocateDirect(v.length * v[0].length * 4);
vbb.order(ByteOrder.nativeOrder());
vBuf = vbb.asFloatBuffer();
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
for (angleA = -90.0f; angleA < 90.0f; angleA += step) {
int n = 0;
r1 = (float)Math.cos(angleA * Math.PI / 180.0);
r2 = (float)Math.cos((angleA + step) * Math.PI / 180.0);
h1 = (float)Math.sin(angleA * Math.PI / 180.0);
h2 = (float)Math.sin((angleA + step) * Math.PI / 180.0);
// 固定緯度, 360 度旋轉遍歷一條緯線
for (angleB = 0.0f; angleB <= 360.0f; angleB += step) {
cos = (float)Math.cos(angleB * Math.PI / 180.0);
sin = -(float)Math.sin(angleB * Math.PI / 180.0);
v[n][0] = (r2 * cos);
v[n][1] = (h2);
v[n][2] = (r2 * sin);
v[n + 1][0] = (r1 * cos);
v[n + 1][1] = (h1);
v[n + 1][2] = (r1 * sin);
vBuf.put(v[n]);
vBuf.put(v[n + 1]);
n += 2;
if(n>31){
vBuf.position(0);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vBuf);
gl.glNormalPointer(GL10.GL_FLOAT, 0, vBuf);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, n);
n = 0;
angleB -= step;
}
}
vBuf.position(0);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vBuf);
gl.glNormalPointer(GL10.GL_FLOAT, 0, vBuf);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, n);
}
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}
}
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;
public class OpenGLView extends GLSurfaceView {
private OpenGLRenderer4 mRenderer;
private float mDownX = 0.0f;
private float mDownY = 0.0f;
public OpenGLView(Context context) {
super(context);
mRenderer = new OpenGLRenderer4();
this.setRenderer(mRenderer);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
return true;
case MotionEvent.ACTION_UP:
return true;
case MotionEvent.ACTION_MOVE:
float mX = event.getX();
float mY = event.getY();
mRenderer.mLightX += (mX-mDownX)/10;
mRenderer.mLightY -= (mY-mDownY)/10;
mDownX = mX;
mDownY = mY;
return true;
default:
return super.onTouchEvent(event);
}
}
}import android.os.Bundle;
import android.app.Activity;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
private OpenGLView mOpenGLView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 去標題欄
requestWindowFeature(Window.FEATURE_NO_TITLE);
//設置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
mOpenGLView = new OpenGLView(this);
setContentView(mOpenGLView);
}
}

Android錄制聲音文件(音頻),並播放
readme:1、這個demo中沒有對多次點擊同一個聲音文件做詳細處理,偶爾會有崩潰,用的時候需要注意。2、按住錄音按鈕錄音過程中,只對豎直方向處理了一下,水平方向沒寫;
Andorid 日歷控件庫,可左右滑動,顯示公歷,農歷,節假日等功能
封面圖: demo效果圖 源碼目錄結構 Features
Android面試知識(4)
30、簡要解釋一下Activity、 Intent 、Intent Filter、Service、BroadcastReceiver。一個activity呈現了一個用戶可
細說JVM系列:JVM內存空間分區
java虛擬機基本結構:JVM是一個內存中的虛擬機,那它的存儲就是內存了,我們寫的所有類、常量、變量、方法都在內存中,因此明白java虛擬機的內存分配非常重要,本部分主要