2014年1月6日 星期一

3D遊戲開發祥解-第一個 OpenGL ES 範例繪出Z軸=0的立體三角形

3D遊戲開發祥解-第一個 OpenGL ES 範例繪出Z軸=0的立體三角形


Sample4_1-Layout(Xml)


 









<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:id="@+id/main_liner"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
</LinearLayout>


 



Sample4_1-Code
-MyActivity.java(主程式)


 









package wyf.swq;
import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
public class MyActivity extends Activity {
/** Called when the activity is first created. */
private MySurfaceView mSurfaceView;//宣告MySurfaceView物件
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSurfaceView=new MySurfaceView(this);//建立MySurfaceView物件
mSurfaceView.requestFocus();//獲取焦點
mSurfaceView.setFocusableInTouchMode(true);//設置為可觸控
LinearLayout ll=(LinearLayout)this.findViewById(R.id.main_liner);//獲得線性佈局的引用
ll.addView(mSurfaceView);
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
mSurfaceView.onPause();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mSurfaceView.onResume();
}
}



-MySurfaceView.java(畫布)









 

package wyf.swq;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;
public class MySurfaceView extends GLSurfaceView {
private final float TOUCH_SCALE_FACTOR=180.0f/320;//角度縮放比例,即螢幕寬320,從螢幕的一端滑到另一端,x軸上的差距對應相應的需要旋轉的角度
private SceneRenderer myRenderer;//場景顯示器
private float myPreviousY;//上次螢幕上的觸控位置的Y座標
private float myPreviousX;//上次螢幕上的觸控位置的X座標
public MySurfaceView(Context context) {
super(context);
// TODO Auto-generated constructor stub
myRenderer=new SceneRenderer();//建立場景顯示器
this.setRenderer(myRenderer);//設置顯示器
this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//設置顯示模式為主動顯示
}
@Override//觸控事件回呼方法
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
float y=event.getY();//獲得當前觸點的Y座標
float x=event.getX();//獲得當前觸點的X座標
switch(event.getAction()){
case MotionEvent.ACTION_MOVE:
float dy=y-myPreviousY;//滑動距離在y軸方向上的垂直距離
float dx=x-myPreviousX;//活動距離在x軸方向上的垂直距離
myRenderer.tr.yAngle+=dx*TOUCH_SCALE_FACTOR;//設置沿y軸旋轉角度
myRenderer.tr.zAngle+=dy*TOUCH_SCALE_FACTOR;//設置沿z軸旋轉角度
requestRender();//顯示畫面
}
myPreviousY=y;
myPreviousX=x;
return true;
}
private class SceneRenderer implements GLSurfaceView.Renderer{//內部類別,實作Renderer介面,顯示器
Triangle tr=new Triangle();
public SceneRenderer(){
}
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
gl.glEnable(GL10.GL_CULL_FACE);//設置為打開背面剪裁
gl.glShadeModel(GL10.GL_SMOOTH);//設置著色模型為平滑著色
gl.glFrontFace(GL10.GL_CCW);//設置自訂捲繞順序為逆時針為正面
gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);//清除顏色緩��和深度緩��
gl.glMatrixMode(GL10.GL_MODELVIEW);//設置當前矩陣為模式矩陣
gl.glLoadIdentity();//設置當前矩陣為單位矩陣
gl.glTranslatef(0, 0, -2.0f);//
tr.drawSelf(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();
float ratio=(float)width/height;
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
gl.glDisable(GL10.GL_DITHER);//關閉抗震動
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST);//設置特定Hint專案的模式,這裡為設置使用快速模式
gl.glClearColor(0, 0, 0, 0);//設置螢幕背景色為黑色
gl.glEnable(GL10.GL_DEPTH_TEST);//啟用深度測試
}}}

 



-Triangle.java(實際OpenGL ES碼)


 









package wyf.swq;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Triangle {
private IntBuffer myVertexBuffer;//頂點座標資料緩衝
private IntBuffer myColorBuffer;//頂點著色資料緩衝
private ByteBuffer myIndexBuffer;//頂點建立的索引資料緩衝
int vCount=0;//頂點數量
int iCount=0;//索引數量
float yAngle=0;//繞y軸旋轉的角度
float zAngle=0;//繞z軸旋轉的角度
public Triangle(){
vCount=3;//一個三角形,3個頂點
final int UNIT_SIZE=10000;//縮放比例
int []vertices=new int[]
{
-8*UNIT_SIZE,6*UNIT_SIZE,0,
-8*UNIT_SIZE,-6*UNIT_SIZE,0,
8*UNIT_SIZE,-6*UNIT_SIZE,0
};
//建立頂點座標資料緩存,由於不同平臺位元組順序不同,資料單元不是位元組的(上面的事整型的緩存),一定要經過ByteBuffer轉換,關鍵是通過ByteOrder設置nativeOrder()
ByteBuffer vbb=ByteBuffer.allocateDirect(vertices.length*4);//一個整數四個位元組,根據最新分配的區塊來建立一個有向的位元組緩衝
vbb.order(ByteOrder.nativeOrder());//設置這個位元組緩衝的位元組順序為本地平臺的位元組順序
myVertexBuffer=vbb.asIntBuffer();//轉換為int型緩衝
myVertexBuffer.put(vertices);//向緩衝區中放入頂點座標資料
myVertexBuffer.position(0);//設置緩衝區的起始位置
final int one=65535;//支持65535色色彩通道
int []colors=new int[]//頂點顏色值陣列,每個頂點4個色彩值RGBA
{
one,one,one,0,
one,one,one,0,
one,one,one,0
};
ByteBuffer cbb=ByteBuffer.allocateDirect(colors.length*4);
cbb.order(ByteOrder.nativeOrder());
myColorBuffer=cbb.asIntBuffer();
myColorBuffer.put(colors);
myColorBuffer.position(0);
//為三角形建構索引資料初始化
iCount=3;
byte []indices=new byte[]
{
0,1,2
};
//建立三角形構造索引資料緩衝
myIndexBuffer=ByteBuffer.allocateDirect(indices.length);
myIndexBuffer.put(indices);
myIndexBuffer.position(0);
}
public void drawSelf(GL10 gl)//GL10是實作介面GL的一公共介面,包含了一系列常數和抽象方法
{
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//啟用頂點座標陣列
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//啟用頂點顏色陣列

gl.glRotatef(yAngle,0,1,0);//根據yAngle的角度值,繞y軸旋轉yAngle
gl.glRotatef(zAngle,0,0,1);

gl.glVertexPointer//為畫筆指定頂點座標資料
(
3, //每個頂點的座標數量為3
GL10.GL_FIXED, //頂點座標值的類型為GL_FIXED,整型
0, //連續頂點座標資料之間的間隔
myVertexBuffer //頂點座標數量
);
gl.glColorPointer//為畫筆指定頂點 顏色資料
(
4,
GL10.GL_FIXED,
0,
myColorBuffer
);
gl.glDrawElements//繪製圖形
(
GL10.GL_TRIANGLES, //填充模式,這裡是以三角形方式填充
iCount, //頂點數量
GL10.GL_UNSIGNED_BYTE, //索引值的類型
myIndexBuffer //索引值資料
);
}}


 


 


沒有留言:

張貼留言