系列文章目錄
Android 3D效果的實作
文章目錄
- 系列文章目錄
- 前言
- 一、先看看聊天(需求)
- 二、實作效果
- 三.實作
- 1.通過getSystemService獲得SensorManager實體物件
- 2.通過SensorManager實體物件獲得想要的傳感器物件:引數決定獲取哪個傳感器
- 3.在獲得焦點時注冊傳感器并讓本類實作SensorEventListener介面
- 4.必須重寫的兩個方法:onAccuracyChanged,onSensorChanged
- 5.在失去焦點時注銷傳感器(為Activity提供呼叫)
- 6.draw方法中的方發詳解,本案例(opengl坐標系中采用的是3維坐標)
- 四.需求中的青黃色引數
- 五.原始碼
- TdRenderer.java
- ThreeDimensionsRotation,java(Activity記得注冊)
前言
前幾天有粉絲要求計蒙寫一個3d效果的簡單教程,其實這個在Android官方demo中是有的,可能對于新手而言看不太明白,于是根據本人自己的理解來寫一個教程,并改成粉絲要求的樣子,
文章最后將會貼出原始碼(照顧新手附加注釋),歡迎留言,
一、先看看聊天(需求)

二、實作效果

三.實作
前五步傳感器內容,
1.通過getSystemService獲得SensorManager實體物件
mSensorManager = (SensorManager)context.getSystemService(SENSOR_SERVICE);
2.通過SensorManager實體物件獲得想要的傳感器物件:引數決定獲取哪個傳感器
mRotationVectorSensor = mSensorManager.getDefaultSensor(
Sensor.TYPE_ROTATION_VECTOR);
3.在獲得焦點時注冊傳感器并讓本類實作SensorEventListener介面
mSensorManager.registerListener(this, mRotationVectorSensor, 10000);
- 第一個引數:SensorEventListener介面的實體物件
- 第二個引數:需要注冊的傳感器實體
- 第三個引數:傳感器獲取傳感器事件event值頻率:
SensorManager.SENSOR_DELAY_FASTEST = 0:對應0微秒的更新間隔,最快,1微秒 = 1 % 1000000秒
SensorManager.SENSOR_DELAY_GAME = 1:對應20000微秒的更新間隔,游戲中常用
SensorManager.SENSOR_DELAY_UI = 2:對應60000微秒的更新間隔
SensorManager.SENSOR_DELAY_NORMAL = 3:對應200000微秒的更新間隔
鍵入自定義的int值x時:對應x微秒的更新間隔
4.必須重寫的兩個方法:onAccuracyChanged,onSensorChanged
- onSensorChanged: 傳感器事件值改變時的回呼介面:執行此方法的頻率與注冊傳感器時的頻率有關.
- onAccuracyChanged:傳感器精度發生改變的回呼介面
5.在失去焦點時注銷傳感器(為Activity提供呼叫)
public void stop() {
mSensorManager.unregisterListener(this);
}
6.draw方法中的方發詳解,本案例(opengl坐標系中采用的是3維坐標)
- glEnable:啟用服務器端GL功能,
- glFrontFace:定義多邊形的正面和背面,多邊形正面的方向,GL_CW和GL_CCW被允許,初始值為GL_CCW,
- glShadeModel:選擇恒定或光滑著色模式,GL圖元可以采用恒定或者光滑著色模式,默認值為光滑著色模式,當圖元進行光柵化的時候,將引起插入頂點顏色計算,不同顏色將被均勻分布到各個像素片段,允許的值有GL_FLAT 和GL_SMOOTH,初始值為GL_SMOOTH,
- glVertexPointer:定義一個頂點坐標矩陣,(后續原始碼中會貼上各個引數以及需要注意的地方),
- glColorPointer:定義一個顏色矩陣,size指明每個顏色的元素數量,必須為4,type指明每個顏色元素的資料型別,stride指明從一個顏色到下一個允許的頂點的位元組增幅,并且屬性值被擠入簡單矩陣或存盤在單獨的矩陣中(簡單矩陣存盤可能在一些版本中更有效率),
- glDrawElements:由矩陣資料渲染圖元
更多建議參考Android官方檔案,
四.需求中的青黃色引數
final float colors[] = {
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1,
};
五.原始碼
TdRenderer.java
public class TdRenderer implements GLSurfaceView.Renderer, SensorEventListener {
//傳感器
private SensorManager mSensorManager;
private Sensor mRotationVectorSensor;
private Cube mCube;
private final float[] mRotationMatrix = new float[16];
public TdRenderer(Context context) {
//第一步:通過getSystemService獲得SensorManager實體物件
mSensorManager = (SensorManager)context.getSystemService(SENSOR_SERVICE);
//第二步:通過SensorManager實體物件獲得想要的傳感器物件:引數決定獲取哪個傳感器
mRotationVectorSensor = mSensorManager.getDefaultSensor(
Sensor.TYPE_ROTATION_VECTOR);
mCube = new Cube();
mRotationMatrix[ 0] = 1;
mRotationMatrix[ 4] = 1;
mRotationMatrix[ 8] = 1;
mRotationMatrix[12] = 1;
}
// 第三步:在獲得焦點時注冊傳感器并讓本類實作SensorEventListener介面
public void start() {
/*
*第一個引數:SensorEventListener介面的實體物件
*第二個引數:需要注冊的傳感器實體
*第三個引數:傳感器獲取傳感器事件event值頻率:
* SensorManager.SENSOR_DELAY_FASTEST = 0:對應0微秒的更新間隔,最快,1微秒 = 1 % 1000000秒
* SensorManager.SENSOR_DELAY_GAME = 1:對應20000微秒的更新間隔,游戲中常用
* SensorManager.SENSOR_DELAY_UI = 2:對應60000微秒的更新間隔
* SensorManager.SENSOR_DELAY_NORMAL = 3:對應200000微秒的更新間隔
* 鍵入自定義的int值x時:對應x微秒的更新間隔
*
*/
mSensorManager.registerListener(this, mRotationVectorSensor, 10000);
}
//第四步:必須重寫的兩個方法:onAccuracyChanged,onSensorChanged
//第五步:在失去焦點時注銷傳感器(為Activity提供呼叫)
public void stop() {
mSensorManager.unregisterListener(this);
}
//傳感器事件值改變時的回呼介面:執行此方法的頻率與注冊傳感器時的頻率有關
public void onSensorChanged(SensorEvent event) {
// 大部分傳感器會回傳三個軸方向x,y,x的event值
//float x = event.values[0];
//float y = event.values[1];
//float z = event.values[2];
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
SensorManager.getRotationMatrixFromVector(
mRotationMatrix , event.values);
}
}
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -3.0f);
gl.glMultMatrixf(mRotationMatrix, 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);
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) {
gl.glDisable(GL10.GL_DITHER);
//指定顏色緩沖區的清理值
gl.glClearColor(1,1,1,1);
}
public class Cube {
//opengl坐標系中采用的是3維坐標:
private FloatBuffer mVertexBuffer;
private FloatBuffer mColorBuffer;
private ByteBuffer mIndexBuffer;
public Cube() {
final float vertices[] = {
-1, -1, -1, 1, -1, -1,
1, 1, -1, -1, 1, -1,
-1, -1, 1, 1, -1, 1,
1, 1, 1, -1, 1, 1,
};
final float colors[] = {
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 0, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1,
};
final 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
};
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
vbb.order(ByteOrder.nativeOrder());
mVertexBuffer = vbb.asFloatBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
cbb.order(ByteOrder.nativeOrder());
mColorBuffer = cbb.asFloatBuffer();
mColorBuffer.put(colors);
mColorBuffer.position(0);
mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
mIndexBuffer.put(indices);
mIndexBuffer.position(0);
}
public void draw(GL10 gl) {
//啟用服務器端GL功能,
gl.glEnable(GL10.GL_CULL_FACE);
//定義多邊形的正面和背面,
//引數:
//mode——多邊形正面的方向,GL_CW和GL_CCW被允許,初始值為GL_CCW,
gl.glFrontFace(GL10.GL_CW);
//選擇恒定或光滑著色模式,
//GL圖元可以采用恒定或者光滑著色模式,默認值為光滑著色模式,當圖元進行光柵化的時候,將引起插入頂點顏色計算,不同顏色將被均勻分布到各個像素片段,
//引數:
//mode——指明一個符號常量來代表要使用的著色技術,允許的值有GL_FLAT 和GL_SMOOTH,初始值為GL_SMOOTH,
gl.glShadeModel(GL10.GL_SMOOTH);
//定義一個頂點坐標矩陣,
//引數:
//
//size——每個頂點的坐標維數,必須是2, 3或者4,初始值是4,
//
//type——指明每個頂點坐標的資料型別,允許的符號常量有GL_BYTE, GL_SHORT, GL_FIXED和GL_FLOAT,初始值為GL_FLOAT,
//
//stride——指明連續頂點間的位偏移,如果為0,頂點被認為是緊密壓入矩陣,初始值為0,
//
//pointer——指明頂點坐標的緩沖區,如果為null,則沒有設定緩沖區,
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
//定義一個顏色矩陣,
//size指明每個顏色的元素數量,必須為4,type指明每個顏色元素的資料型別,stride指明從一個顏色到下一個允許的頂點的位元組增幅,并且屬性值被擠入簡單矩陣或存盤在單獨的矩陣中(簡單矩陣存盤可能在一些版本中更有效率),
gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);
//由矩陣資料渲染圖元
//可以事先指明獨立的頂點、法線、顏色和紋理坐標矩陣并且可以通過呼叫glDrawElements方法來使用它們創建序列圖元,
gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);
}
}
//傳感器精度發生改變的回呼介面
public void onAccuracyChanged(Sensor sensor, int accuracy) {
//在傳感器精度發生改變時做些操作,accuracy為當前傳感器精度
}
}
ThreeDimensionsRotation,java(Activity記得注冊)
public class ThreeDimensionsRotation extends Activity {
private GLSurfaceView mGLSurfaceView;
private TdRenderer tdRenderer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tdRenderer=new TdRenderer(this);
// 創建預覽視圖,并將其設定為Activity的內容
mGLSurfaceView = new GLSurfaceView(this);
mGLSurfaceView.setRenderer(tdRenderer);
setContentView(mGLSurfaceView);
}
@Override
protected void onResume() {
super.onResume();
tdRenderer.start();
mGLSurfaceView.onResume();
}
@Override
protected void onPause() {
super.onPause();
tdRenderer.stop();
mGLSurfaceView.onPause();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/295451.html
標籤:其他
上一篇:Airtest給愛豆點贊
