android3D場景繪制1——房間的繪制 – Android移動開發技術文章_手機開發 Android移動開發教學課程

 

相信大傢都會畫矩形瞭,下面我們來畫一個房間,大傢想想怎麼畫瞭,我以前想用索引法把每個面都畫出來,但是遇到瞭很多問題,畫不出我想要的結果,其實還有種方法,那就是通過旋轉,和位移變換,把矩形旋轉和位移到長方體的各個面,再加工一下,這樣就變成小房間瞭,下面我們來看看效果和代碼吧。

package yy.cal; 

 

 

import android.app.Activity; 

import android.os.Bundle; 

import android.widget.LinearLayout; 

 

public class GLSurfaceViewActivity extends Activity { 

    private MySurfaceView mSurfaceView;//聲明MySurfaceView對象 

    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(); 

    }   

 

 

 

 

package yy.cal; 

 

import javax.microedition.khronos.egl.EGLConfig; 

import javax.microedition.khronos.opengles.GL10; 

 

import android.content.Context; 

import android.opengl.GLSurfaceView; 

import android.opengl.GLU; 

import android.view.MotionEvent; 

 

public class MySurfaceView extends GLSurfaceView{ 

    private final float TOUCH_SCALE_FACTOR = 180.0f/320;//角度縮放比例 

    private SceneRenderer mRenderer;//場景渲染器  

 

    private float mPreviousX;//上次的觸控位置X坐標 

     

    public MySurfaceView(Context context) { 

        super(context); 

        mRenderer = new SceneRenderer();    //創建場景渲染器 

        setRenderer(mRenderer);             //設置渲染器      

        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//設置渲染模式為主動渲染    

    } 

     

    //觸摸事件回調方法 

    @Override  

    public boolean onTouchEvent(MotionEvent e) { 

        float x = e.getX(); 

        switch (e.getAction()) { 

        case MotionEvent.ACTION_MOVE: 

            float dx = x – mPreviousX;//計算觸控筆X位移 

            mRenderer.angle += dx * TOUCH_SCALE_FACTOR;//設置沿x軸旋轉角度 

             

            requestRender();//重繪畫面 

        }    

        mPreviousX = x;//記錄觸控筆位置 

        return true; 

    } 

 

    private class SceneRenderer implements GLSurfaceView.Renderer  

    {    

        Cube cube=new Cube();//立方體 

        float angle=45;//總旋轉角度 

         

        public void onDrawFrame(GL10 gl) { 

            //設置為打開背面剪裁 

            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();     

             

            GLU.gluLookAt//不太可能變形的視角——小視角 

            ( 

                    gl,  

                    0f,   //人眼位置的X 

                    10f,    //人眼位置的Y 

                    15.0f,   //人眼位置的Z 

                    0,  //人眼球看的點X 

                    0f,   //人眼球看的點Y 

                    0,   //人眼球看的點Z 

                    0,  

                    1,  

                    0 

            );   

             

            //旋轉總坐標系 

            gl.glRotatef(angle, 0, 1, 0); 

             

            //繪制右立方體 

            gl.glPushMatrix(); 

           // gl.glTranslatef(2, 0, 0); 

            cube.drawSelf(gl); 

            gl.glPopMatrix(); 

             

        } 

 

        public void onSurfaceChanged(GL10 gl, int width, int height) { 

            //設置視窗大小及位置  

            gl.glViewport(0, 0, width, height); 

            //設置當前矩陣為投影矩陣 

            gl.glMatrixMode(GL10.GL_PROJECTION); 

            //設置當前矩陣為單位矩陣 

            gl.glLoadIdentity(); 

            //計算透視投影的比例 

            float ratio = (float) height/width ; 

            //調用此方法計算產生透視投影矩陣 

            //gl.glFrustumf( -1, 1,-ratio, ratio, 1, 100);   //可能變形的視角——大視角   

            gl.glFrustumf( -1, 1,-ratio, ratio, 8f, 100);     //不太可能變形的視角——小視角 

        } 

 

        public void onSurfaceCreated(GL10 gl, EGLConfig config) { 

            //關閉抗抖動  

            gl.glDisable(GL10.GL_DITHER); 

            //設置特定Hint項目的模式,這裡為設置為使用快速模式 

            gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST); 

            //設置屏幕背景色黑色RGBA 

            gl.glClearColor(0,0,0,0);             

            //啟用深度測試 

            gl.glEnable(GL10.GL_DEPTH_TEST); 

        } 

    } 

 

 

 

 

 

package yy.cal; 

 

import java.nio.ByteBuffer; 

import java.nio.ByteOrder; 

import java.nio.FloatBuffer; 

import java.nio.IntBuffer; 

 

import javax.microedition.khronos.opengles.GL10; 

 

public class ColorRect { 

    private FloatBuffer   mVertexBuffer;//頂點坐標數據緩沖 

    private IntBuffer   mColorBuffer;//頂點著色數據緩沖 

    int vCount=0;//頂點數量 

     

    public ColorRect(float width,float height) 

    { 

        //頂點坐標數據的初始化================begin============================ 

        vCount=6; 

        final float UNIT_SIZE=4.0f; 

        float vertices[]=new float[] 

        { 

            0,0,0, 

            width*UNIT_SIZE,height*UNIT_SIZE,0, 

            -width*UNIT_SIZE,height*UNIT_SIZE,0, 

            -width*UNIT_SIZE,-height*UNIT_SIZE,0, 

            width*UNIT_SIZE,-height*UNIT_SIZE,0, 

            width*UNIT_SIZE,height*UNIT_SIZE,0 

        }; 

         

        //創建頂點坐標數據緩沖 

        //vertices.length*4是因為一個整數四個字節 

        ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4); 

        vbb.order(ByteOrder.nativeOrder());//設置字節順序 

        mVertexBuffer = vbb.asFloatBuffer();//轉換為Float型緩沖 

        mVertexBuffer.put(vertices);//向緩沖區中放入頂點坐標數據 

        mVertexBuffer.position(0);//設置緩沖區起始位置 

        //特別提示:由於不同平臺字節順序不同數據單元不是字節的一定要經過ByteBuffer 

        //轉換,關鍵是要通過ByteOrder設置nativeOrder(),否則有可能會出問題 

        //頂點坐標數據的初始化================end============================ 

         

        //頂點著色數據的初始化================begin============================ 

        final int one = 65535; 

        int colors[]=new int[]//頂點顏色值數組,每個頂點4個色彩值RGBA 

        { 

                one,one,one,0, 

                0,0,one,0, 

                0,0,one,0, 

                0,0,one,0, 

                0,0,one,0,           

                0,0,one,0, 

        }; 

 

         

        //創建頂點著色數據緩沖 

        //vertices.length*4是因為一個int型整數四個字節 

        ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4); 

        cbb.order(ByteOrder.nativeOrder());//設置字節順序 

        mColorBuffer = cbb.asIntBuffer();//轉換為int型緩沖 

        mColorBuffer.put(colors);//向緩沖區中放入頂點著色數據 

        mColorBuffer.position(0);//設置緩沖區起始位置 

        //特別提示:由於不同平臺字節順序不同數據單元不是字節的一定要經過ByteBuffer 

        //轉換,關鍵是要通過ByteOrder設置nativeOrder(),否則有可能會出問題 

        //頂點著色數據的初始化================end============================ 

         

         

    } 

 

    public void drawSelf(GL10 gl) 

    {         

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//啟用頂點坐標數組 

        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//啟用頂點顏色數組 

 

         

        //為畫筆指定頂點坐標數據 

        gl.glVertexPointer 

        ( 

                3,              //每個頂點的坐標數量為3  xyz  

                GL10.GL_FLOAT,  //頂點坐標值的類型為GL_FIXED 

                0,              //連續頂點坐標數據之間的間隔 

                mVertexBuffer   //頂點坐標數據 

        ); 

         

        //為畫筆指定頂點著色數據 

        gl.glColorPointer 

        ( 

                4,              //設置顏色的組成成分,必須為4—RGBA 

                GL10.GL_FIXED,  //頂點顏色值的類型為GL_FIXED 

                0,              //連續頂點著色數據之間的間隔 

                mColorBuffer    //頂點著色數據 

        ); 

         

         

        //繪制圖形 

        gl.glDrawArrays 

        ( 

                GL10.GL_TRIANGLE_FAN,       //以三角形方式填充 

                0,                      //開始點編號 

                vCount                  //頂點的數量 

        ); 

    } 

 

 

 

 

package yy.cal; 

 

import javax.microedition.khronos.opengles.GL10; 

import static yy.cal.Constant.*; 

 

 

public class Cube { 

    //用於繪制各個面的顏色矩形 

    ColorRect cr=new ColorRect(SCALE,SCALE); 

     

    public void drawSelf(GL10 gl) 

    { 

        //總繪制思想:通過把一個顏色矩形旋轉移位到立方體每個面的位置 

        //繪制立方體的每個面 

         

        gl.glPushMatrix(); 

         

 

         

        //繪制後小面 

        gl.glPushMatrix();       

        gl.glTranslatef(0, 0, -UNIT_SIZE*SCALE); 

        cr.drawSelf(gl);         

        gl.glPopMatrix(); 

         

 

         

        //繪制下大面 

        gl.glPushMatrix();           

        gl.glTranslatef(0,-UNIT_SIZE*SCALE,0); 

        gl.glRotatef(-90, 1, 0, 0); 

        cr.drawSelf(gl); 

        gl.glPopMatrix(); 

         

        //繪制右大面 

        gl.glPushMatrix();           

        gl.glTranslatef(UNIT_SIZE*SCALE,0,0);        

        gl.glRotatef(-90, 1, 0, 0); 

        gl.glRotatef(-90, 0, 1, 0); 

        cr.drawSelf(gl); 

        gl.glPopMatrix(); 

         

        //繪制左大面 

        gl.glPushMatrix();           

        gl.glTranslatef(-UNIT_SIZE*SCALE,0,0);       

        gl.glRotatef(90, 0, 1, 0); 

        cr.drawSelf(gl); 

        gl.glPopMatrix(); 

         

        gl.glPopMatrix(); 

    } 

     

 

 

 

 

 

package yy.cal; 

 

public class Constant { 

 

     public static final float UNIT_SIZE=4.0f;//單位尺寸 

     public static final float SCALE=0.5f;//尺寸縮放比 

}   

摘自 dlnuchunge的專欄

發佈留言