三维漫游的实现
一、本文主要是展示一個demo,實現的是畫一個三維的立方體,通過滑動屏幕來旋轉方向,上下左右來移動。直接上代碼:
MainActivity: package com.example.zp.a3dword; ? import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; import android.opengl.GLSurfaceView; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; ? public class MainActivity extends AppCompatActivity { ? private GLSurfaceView glSurfaceView; GLRenderer renderer; //屏幕的寬高 int width; int height; float speed = 0.5f; ? @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); glSurfaceView= (GLSurfaceView) findViewById(R.id.gl_surfaceView); // glSurfaceView =new GLSurfaceView(this); Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.ayx); Bitmap bitmap2 = BitmapFactory.decodeResource(this.getResources(), R.drawable.ayx2); Bitmap mBitmap[] = {bitmap,bitmap2}; renderer=new GLRenderer(mBitmap); glSurfaceView.setRenderer(renderer); // setContentView(glSurfaceView); WindowManager wm = this.getWindowManager(); Point p = new Point(0,0); wm.getDefaultDisplay().getSize(p); width = p.x; height =p.y; ? } ? int downX; //向一個方向的起始點坐標 int previewX; // 記住前一個點的x坐標 int currentX; //當前點的ex坐標 ? int downY; //向一個方向的起始點坐標 int previewY; // 記住前一個點的x坐標 int currentY; //當前點的ex坐標 ? @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = (int) event.getX(); previewX = downX; downY = (int) event.getY(); previewY= downY; break; case MotionEvent.ACTION_MOVE: currentX = (int) event.getX(); currentY = (int) event.getY(); //****************************X方向旋轉******************************************// //判斷運動的方向是否改變,大于0不改變 if((currentX - downX)*(currentX - previewX)>0) { int dis = currentX - downX; float angle = (float) dis / (float) width * (float) Math.PI; renderer.letfrightDirectionChange(angle); previewX = currentX; } else { downX = previewX; } //****************************Y方向旋轉******************************************// currentY = (int) event.getY(); //判斷運動的方向是否改變,大于0不改變 if((currentY - downY)*(currentY - previewY)>0) { int dis = currentY - downY; float angle = (float) dis / (float) width * (float) Math.PI; renderer.updownDirectionChange(angle); previewY = currentY; } else { downY = previewY; } ? break; case MotionEvent.ACTION_UP: break; } return true; } ? public void goBack(View view) { renderer.goAhead(-speed); } public void goAhead(View view) { renderer.goAhead(speed); } public void goLeft(View view) { renderer.goleft(speed); } public void goRight(View view) { renderer.goleft(-speed); } } Render的實現: package com.example.zp.a3dword; ? import android.graphics.Bitmap; import android.opengl.GLSurfaceView; import android.opengl.GLUtils; import java.nio.FloatBuffer; import java.nio.IntBuffer; ? import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; ? /** * Created by lenovo on 2016/9/7. */ public class GLRenderer implements GLSurfaceView.Renderer{ ? float xrot = 0; float yrot = 0; ? private float visonPointX=0f; private float visonPointY=0f; private float visonPointZ=-3f; ? int size=3; int one = 0x10000*size; ? int textureSize = 2; int texture[] = new int [textureSize]; private Bitmap mBitmap[]; ? ? //當正方體很小,為1個點位的時候發現在角落的時候兩邊出現黑條,這是因為屏幕顯示的,即我們看到的視覺是一個以(0,0,0)為中心的平面,旋轉函數是旋轉整個三維世界,而 //視覺平面的大小位置永遠不變,我自己定義為視覺坐標,視覺坐標是不變的,三維世界的坐標起初與視覺坐標是一致的,且視覺顯示的是-1層即z為-1的那層只有小與-1的物體可以看到 // 當隨著三維世界的旋轉就會與視覺坐標產生差異,視覺坐標不變,當隨著三維世界的旋轉,三維世界的坐標對應的點對應與視覺坐標-1層及大于-1層的物體就不會顯示 //正方體的6個面,4個點確定一個面 IntBuffer vertices = BufferUtil.intToBuffer(new int[]{ -one,-one,one, one,-one,one, ? -one,one,one, one,one,one, ? -one,-one,-one, -one,one,-one, ? one,-one,-one,one,one,-one, ? -one,one,-one, -one,one,one, ? one,one,-one, one,one,one, ? -one,-one,-one, one,-one,-one, ? -one,-one,one,one,-one,one, ? one,-one,-one, one,one,-one, ? one,-one,one, one,one,one, ? -one,-one,-one, -one,-one,one, ? -one,one,-one,-one,one,one ? }); ? //這里one 為幾就貼幾張,是指一個邊貼幾張,一個面就是one*one張了,one為1*5所以這里除以5,就會只貼一張 int one2 = one/size; IntBuffer texCoords2 = BufferUtil.intToBuffer(new int[]{ 0, one2, one2, one2, 0, 0, one2, 0, 0, 0, 0, one2, one2, 0, one2, one2, one2, one2, one2, 0, 0, one2, 0, 0, 0, one2, one2, one2, 0, 0, one2, 0, 0, 0, 0, one2, one2, 0, one2, one2, one2, 0, 0, 0, one2, one2, 0, one2, }); ? public GLRenderer(Bitmap mBitmap[]) { this.mBitmap = mBitmap; } ? @Override public void onDrawFrame(GL10 gl) { // 清除屏幕和深度緩存 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // 重置當前的模型觀察矩陣 // gl.glEnable(GL10.GL_LIGHTING); gl.glLoadIdentity(); gl.glTranslatef(visonPointX,visonPointY,visonPointZ); ? //設置3個方向的旋轉 gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f); gl.glRotatef(yrot, 0.0f,1.0f, 0.0f); // gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f); ? ? gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);//啟用紋理映射 ? gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertices); gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, texCoords2); gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[1]); ? for(int i = 0 ; i < 6 ; i ++) { gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP , i*4 , 4); gl.glFinish(); } gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); ? } ? @Override public void onSurfaceChanged(GL10 gl, int width, int height) { float ratio = (float) width / height; //設置OpenGL場景的大小 gl.glViewport(0, 0, width, height); //設置投影矩陣 gl.glMatrixMode(GL10.GL_PROJECTION); //重置投影矩陣 gl.glLoadIdentity(); // 設置視口的大小 gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); // 選擇模型觀察矩陣 gl.glMatrixMode(GL10.GL_MODELVIEW); // 重置模型觀察矩陣 gl.glLoadIdentity(); ? } ? @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // 黑色背景 gl.glClearColor(0, 0, 0, 0); // gl.glEnable(GL10.GL_CULL_FACE); // 啟用陰影平滑 gl.glShadeModel(GL10.GL_SMOOTH); // 啟用深度測試 gl.glEnable(GL10.GL_DEPTH_TEST); ? // 啟用混合模式 gl.glEnable(GL10.GL_BLEND); gl.glDisable(GL10.GL_DEPTH_TEST); // 關閉深度測試 //設置光線,,1.0f為全光線,a=50% gl.glColor4f(1.0f,1.0f,1.0f,0.5f); // 基于源象素alpha通道值的半透明混合函數 gl.glBlendFunc(GL10.GL_SRC_ALPHA,GL10.GL_ONE); ? //啟用紋理映射 gl.glClearDepthf(1.0f); //深度測試的類型 gl.glDepthFunc(GL10.GL_LEQUAL); //精細的透視修正 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); //允許2D貼圖,紋理 gl.glEnable(GL10.GL_TEXTURE_2D); getTextures(gl); ? ? ? // //設置光顏色 // FloatBuffer lightAmbient = BufferUtil.floatToBuffer(new float[]{ // 1f, 1f, 1f, 1f // } ); // FloatBuffer lightDiffuse = BufferUtil.floatToBuffer(new float[]{ // 1f,1f,1f,1f // } ); // //定義光源位置 // FloatBuffer lightPosition = BufferUtil.floatToBuffer(new float[]{ // -2f,0f,-4f,1f // } ); // //設置環境光 // gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightAmbient); // // //設置漫射光 // gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, lightDiffuse); // // //設置光源位置 // gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, lightPosition); // // //開啟一號光源 // gl.glEnable(GL10.GL_LIGHT1); ? } ? ? private void getTextures(GL10 gl) { IntBuffer intBuffer = IntBuffer.allocate(2);//申請2個紋理存儲空間 // 創建紋理 gl.glGenTextures(2 , intBuffer); //創建2個紋理,綁定intuffer texture[0] = intBuffer.get(); // 獲取第一個紋理的存儲指針,即紋理存儲位置,位置+1 texture[1] = intBuffer.get(); //獲取下一個紋理存儲的位置 ? // 設置要使用的紋理 gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[0]); //生成紋理 GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0 , mBitmap[0] , 0);//利用圖mBitmap[0]生成紋理,存儲在texture[0] // 線形濾波 gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); ? //生成第二個紋理 gl.glBindTexture(GL10.GL_TEXTURE_2D, texture[1]); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0 , mBitmap[1] , 0);//利用圖mBitmap[0]生成紋理,存儲在texture[1] gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); ? } ? //三維世界向右旋轉,我們的視覺就向左旋轉了 public void letfrightDirectionChange( float angle) { yrot = yrot + angle; } ? public void updownDirectionChange(float angle) { xrot = xrot + angle; } ? public void goAhead (float dis) { visonPointZ = visonPointZ + dis; } public void goleft (float dis) { visonPointX = visonPointX + dis; } ? } BufferUtil工具類前面展示過這里就省略了。?
轉載于:https://www.cnblogs.com/bokeofzp/p/5967481.html
總結
- 上一篇: codeblock不能调试
- 下一篇: Nodejs学习(三)-安装nodejs