3D遊戲開發祥解-OpenGL 兩種投影(glFrustumf/glOrthof)結果比較
3D遊戲開發祥解-OpenGL 兩種投影(glFrustumf/glOrthof)結果比較
Sample4_5-Layout(Xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_liner"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ToggleButton
android:textOff="正交投影"
android:textOn="透視投影"
android:checked="false"
android:id="@+id/ToggleButton01"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</ToggleButton>
</LinearLayout>
|
Sample4_5-Code
-MyActivity.java(程式進入點)
package wyf.swq;
import wyf.swq.MySurfaceView; //引入相關套件
import android.app.Activity; //引入相關套件
import android.os.Bundle; //引入相關套件
import android.widget.CompoundButton; //引入相關套件
import android.widget.LinearLayout; //引入相關套件
import android.widget.ToggleButton; //引入相關套件
import android.widget.CompoundButton.OnCheckedChangeListener; //引入相關套件
public class MyActivity extends Activity {
private MySurfaceView mSurfaceView; //宣告MySurfaceView變數
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main); //設置佈局
mSurfaceView = new MySurfaceView(this); //建立MySurfaceView物件
mSurfaceView.requestFocus();//獲取焦點
mSurfaceView.setFocusableInTouchMode(true);//設置為可觸控
LinearLayout ll=(LinearLayout)findViewById(R.id.main_liner); //獲得佈局引用
ll.addView(mSurfaceView);//在佈局中加入MySurfaceView物件
//控制是否打開背面剪裁的ToggleButton
ToggleButton tb=(ToggleButton)this.findViewById(R.id.ToggleButton01);//獲得按鈕引用
tb.setOnCheckedChangeListener(new MyListener()); //為按鈕設置監聽器
}
class MyListener implements OnCheckedChangeListener{
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
mSurfaceView.isPerspective=!mSurfaceView.isPerspective;//在正交投影與透視投影之間切換
mSurfaceView.requestRender();//重新繪製
}
}
@Override
protected void onResume() { //
super.onResume(); //
mSurfaceView.onResume();//
}
@Override
protected void onPause() { //
super.onPause(); //
mSurfaceView.onPause(); //
}
}
|
-MySurfaceView.java
package wyf.swq;
import android.opengl.GLSurfaceView; //引入相關套件
import android.view.MotionEvent; //引入相關套件
import javax.microedition.khronos.egl.EGLConfig; //引入相關套件
import javax.microedition.khronos.opengles.GL10; //引入相關套件
import android.content.Context; //引入相關套件
class MySurfaceView extends GLSurfaceView {
private final float TOUCH_SCALE_FACTOR = 180.0f/320; //角度縮放比例
private SceneRenderer mRenderer; //場景顯示器
public boolean isPerspective=false; //投影標誌位元
private float mPreviousY; //上次的觸控位置Y座標
public float xAngle=0; //整體繞x軸旋轉的角度
public MySurfaceView(Context context) {
super(context);
mRenderer = new SceneRenderer(); //建立場景顯示器
setRenderer(mRenderer); //設置顯示器
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//主動顯示
}
//觸控事件回呼方法
@Override
public boolean onTouchEvent(MotionEvent e) {
float y = e.getY();
switch (e.getAction()) { //獲取動作
case MotionEvent.ACTION_MOVE: //判斷��否��滑動
float dy = y - mPreviousY; //計算觸控筆Y位移
xAngle+= dy * TOUCH_SCALE_FACTOR; //設置沿x軸旋轉角度
requestRender(); //重繪畫面
}
mPreviousY = y; //作為上一次觸點的Y座標
return true;
}
private class SceneRenderer implements GLSurfaceView.Renderer {
Hexagon[] ha=new Hexagon[]{ //六邊形陣列
new Hexagon(0),
new Hexagon(-2),
new Hexagon(-4),
new Hexagon(-6),
new Hexagon(-8),
new Hexagon(-10),
new Hexagon(-12),
};
public SceneRenderer(){} //顯示器建構子
@Override
public void onDrawFrame(GL10 gl) {
gl.glMatrixMode(GL10.GL_PROJECTION); //設置當前矩陣為投影矩陣
gl.glLoadIdentity(); //設置當前矩陣為單位矩陣
float ratio = (float) 320/480; //計算透視投影的比例
if(isPerspective){
gl.glFrustumf(-ratio, ratio, -1, 1, 1f, 10);//呼叫此方法計算產生透視投影矩陣
}
else{
gl.glOrthof(-ratio, ratio, -1, 1, 1, 10);//呼叫此方法計算產生正交投影矩陣
}
gl.glEnable(GL10.GL_CULL_FACE); //設置為打開背面剪裁
gl.glShadeModel(GL10.GL_SMOOTH); //設置著色模型為平滑著色
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);//清除緩��
gl.glMatrixMode(GL10.GL_MODELVIEW); //設置當前矩陣為模式矩陣
gl.glLoadIdentity(); //設置當前矩陣為單位矩陣
gl.glTranslatef(0, 0f, -1.4f); //沿z軸向遠處推
gl.glRotatef(xAngle, 1, 0, 0); //繞x軸旋轉制定角度
for(Hexagon th:ha){
th.drawSelf(gl); //迴圈繪製六邊形陣列中的每個六邊形
}
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height); //設置視窗大小及位置
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
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); //啟用深度測試
}}}
|
-Hexagon.java
package wyf.swq;
import java.nio.ByteBuffer; //引入相關套件
import java.nio.ByteOrder; //引入相關套件
import java.nio.IntBuffer; //引入相關套件
import javax.microedition.khronos.opengles.GL10;
public class Hexagon {
private IntBuffer mVertexBuffer; //頂點座標資料緩衝
private IntBuffer mColorBuffer; //頂點著色資料緩衝
private ByteBuffer mIndexBuffer; //頂點建構索引資料緩衝
int vCount=0; //圖形頂點數量
int iCount=0; //索引頂點數量
public Hexagon(int zOffset){
//頂點座標資料的初始化
vCount=7;
final int UNIT_SIZE=10000;
int vertices[]=new int[]{
0*UNIT_SIZE,0*UNIT_SIZE,zOffset*UNIT_SIZE,
2*UNIT_SIZE,3*UNIT_SIZE,zOffset*UNIT_SIZE,
4*UNIT_SIZE,0*UNIT_SIZE,zOffset*UNIT_SIZE,
2*UNIT_SIZE,-3*UNIT_SIZE,zOffset*UNIT_SIZE,
-2*UNIT_SIZE,-3*UNIT_SIZE,zOffset*UNIT_SIZE,
-4*UNIT_SIZE,0*UNIT_SIZE,zOffset*UNIT_SIZE,
-2*UNIT_SIZE,3*UNIT_SIZE,zOffset*UNIT_SIZE
};
//建立頂點座標資料緩衝
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
vbb.order(ByteOrder.nativeOrder());//設置位元組順序
mVertexBuffer = vbb.asIntBuffer();//轉換為int型緩衝
mVertexBuffer.put(vertices);//向緩衝區中放入頂點座標資料
mVertexBuffer.position(0);//設置緩衝區起始位置
//頂點著色數據的初始化
final int one = 65535;
int colors[]=new int[]//頂點顏色值陣列,每個頂點4個色彩值RGBA
{
0,0,one,0,
0,one,0,0,
0,one,one,0,
one,0,0,0,
one,0,one,0,
one,one,0,0,
one,one,one,0
};
//建立頂點著色資料緩衝
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
cbb.order(ByteOrder.nativeOrder());//設置位元組順序
mColorBuffer = cbb.asIntBuffer();//轉換為int型緩衝
mColorBuffer.put(colors);//向緩衝區中放入頂點著色數據
mColorBuffer.position(0);//設置緩衝區起始位置
//三角形建構索引資料初始化
iCount=18;
byte indices[]=new byte[]{
0,2,1,
0,3,2,
0,4,3,
0,5,4,
0,6,5,
0,1,6
};
//建立三角形構造索引資料緩衝
mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
mIndexBuffer.put(indices);//向緩衝區中放入三角形建構索引資料
mIndexBuffer.position(0);//設置緩衝區起始位置
}
public void drawSelf(GL10 gl){
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//啟用頂點座標陣列
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//啟用頂點顏色陣列
gl.glVertexPointer(//為畫筆指定頂點座標資料
3, //每個頂點的座標數量為3 xyz
GL10.GL_FIXED, //頂點座標值的類型為 GL_FIXED
0, //連續頂點座標資料之間的間隔
mVertexBuffer //頂點座標資料
);
gl.glColorPointer(//為畫筆指定頂點著色數據
4, //設置顏色的組成成分,必須為4—RGBA
GL10.GL_FIXED, //頂點顏色值的類型為 GL_FIXED
0, //連續頂點著色資料之間的間隔
mColorBuffer //頂點著色數據
);
gl.glDrawElements(//索引法繪製圖形
GL10.GL_TRIANGLES, //以三角形方式填充
iCount, //一共icount/3個三角形,iCount個頂點
GL10.GL_UNSIGNED_BYTE, //索引值的尺寸
mIndexBuffer //索引值資料
);
}}
|