Android應用:3D圓柱體

總共三個類

 

[java] 

package wyf.lgz;  

  

import java.nio.ByteBuffer;  

import java.nio.ByteOrder;  

import java.nio.FloatBuffer;  

import java.util.ArrayList;  

  

import javax.microedition.khronos.opengles.GL10;  

  

public class DrawCylinder  

{  

    private FloatBuffer myVertexBuffer;//頂點坐標緩沖   

    private FloatBuffer myNormalBuffer;//法向量緩沖  

    private FloatBuffer myTexture;//紋理緩沖  

      

    int textureId;  

      

    int vCount;//頂點數量  

      

    float length;//圓柱長度  

    float circle_radius;//圓截環半徑  

    float degreespan;  //圓截環每一份的度數大小  

      

    public float mAngleX;  

    public float mAngleY;  

    public float mAngleZ;  

      

    public DrawCylinder(float length,float circle_radius,float degreespan,int textureId)  

    {  

        this.circle_radius=circle_radius;  

        this.length=length;  

        this.degreespan=degreespan;  

        this.textureId=textureId;  

          

        float collength=(float)length;//圓柱每塊所占的長度  

        int spannum=(int)(360.0f/degreespan);  

          

        ArrayList<Float> val=new ArrayList<Float>();//頂點存放列表  

        ArrayList<Float> ial=new ArrayList<Float>();//法向量存放列表  

          

        for(float circle_degree=180.0f;circle_degree>0.0f;circle_degree-=degreespan)//循環行  

        {  

                float x1 =(float)(-length/2);  

                float y1=(float) (circle_radius*Math.sin(Math.toRadians(circle_degree)));  

                float z1=(float) (circle_radius*Math.cos(Math.toRadians(circle_degree)));  

                  

                float a1=0;  

                float b1=y1;  

                float c1=z1;  

                float l1=getVectorLength(a1, b1, c1);//模長  

                a1=a1/l1;//法向量規格化  

                b1=b1/l1;  

                c1=c1/l1;  

                  

                float x2 =(float)(-length/2);  

                float y2=(float) (circle_radius*Math.sin(Math.toRadians(circle_degree-degreespan)));  

                float z2=(float) (circle_radius*Math.cos(Math.toRadians(circle_degree-degreespan)));  

                  

                float a2=0;  

                float b2=y2;  

                float c2=z2;  

                float l2=getVectorLength(a2, b2, c2);//模長  

                a2=a2/l2;//法向量規格化  

                b2=b2/l2;  

                c2=c2/l2;  

                  

                float x3 =(float)(length/2);  

                float y3=(float) (circle_radius*Math.sin(Math.toRadians(circle_degree-degreespan)));  

                float z3=(float) (circle_radius*Math.cos(Math.toRadians(circle_degree-degreespan)));  

                  

                float a3=0;  

                float b3=y3;  

                float c3=z3;  

                float l3=getVectorLength(a3, b3, c3);//模長  

                a3=a3/l3;//法向量規格化  

                b3=b3/l3;  

                c3=c3/l3;  

                  

                float x4 =(float)(length/2);  

                float y4=(float) (circle_radius*Math.sin(Math.toRadians(circle_degree)));  

                float z4=(float) (circle_radius*Math.cos(Math.toRadians(circle_degree)));  

                  

                float a4=0;  

                float b4=y4;  

                float c4=z4;  

                float l4=getVectorLength(a4, b4, c4);//模長  

                a4=a4/l4;//法向量規格化  

                b4=b4/l4;  

                c4=c4/l4;  

                  

                val.add(x1);val.add(y1);val.add(z1);//兩個三角形,共6個頂點的坐標  

                val.add(x2);val.add(y2);val.add(z2);  

                val.add(x4);val.add(y4);val.add(z4);  

                  

                val.add(x2);val.add(y2);val.add(z2);  

                val.add(x3);val.add(y3);val.add(z3);  

                val.add(x4);val.add(y4);val.add(z4);  

                  

                ial.add(a1);ial.add(b1);ial.add(c1);//頂點對應的法向量  

                ial.add(a2);ial.add(b2);ial.add(c2);  

                ial.add(a4);ial.add(b4);ial.add(c4);  

                  

                ial.add(a2);ial.add(b2);ial.add(c2);  

                ial.add(a3);ial.add(b3);ial.add(c3);  

                ial.add(a4);ial.add(b4);ial.add(c4);  

        }  

           

        vCount=val.size()/3;//確定頂點數量  

          

        //頂點  

        float[] vertexs=new float[vCount*3];  

        for(int i=0;i<vCount*3;i++)  

        {  

            vertexs[i]=val.get(i);  

        }  

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

        vbb.order(ByteOrder.nativeOrder());  

        myVertexBuffer=vbb.asFloatBuffer();  

        myVertexBuffer.put(vertexs);  

        myVertexBuffer.position(0);  

          

        //法向量  

        float[] normals=new float[vCount*3];  

        for(int i=0;i<vCount*3;i++)  

        {  

            normals[i]=ial.get(i);  

        }  

        ByteBuffer ibb=ByteBuffer.allocateDirect(normals.length*4);  

        ibb.order(ByteOrder.nativeOrder());  

        myNormalBuffer=ibb.asFloatBuffer();  

        myNormalBuffer.put(normals);  

        myNormalBuffer.position(0);  

          

        //紋理  

        float[] textures=generateTexCoor(spannum);  

        ByteBuffer tbb=ByteBuffer.allocateDirect(textures.length*4);  

        tbb.order(ByteOrder.nativeOrder());  

        myTexture=tbb.asFloatBuffer();  

        myTexture.put(textures);  

        myTexture.position(0);  

    }  

      

    public void drawSelf(GL10 gl)  

    {  

        gl.glRotatef(mAngleX, 1, 0, 0);//旋轉  

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

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

          

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//打開頂點緩沖  

        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, myVertexBuffer);//指定頂點緩沖  

          

        gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);//打開法向量緩沖  

        gl.glNormalPointer(GL10.GL_FLOAT, 0, myNormalBuffer);//指定法向量緩沖  

          

        gl.glEnable(GL10.GL_TEXTURE_2D);  

        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  

        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, myTexture);  

        gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId);  

          

        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, vCount);//繪制圖像  

          

        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);//關閉緩沖  

        gl.glEnable(GL10.GL_TEXTURE_2D);  

        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);  

        gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);  

    }  

      

    //法向量規格化,求模長度  

    public float getVectorLength(float x,float y,float z)  

    {  

        float pingfang=x*x+y*y+z*z;  

        float length=(float) Math.sqrt(pingfang);  

        return length;  

    }  

      

    //自動切分紋理產生紋理數組的方法  

    public float[] generateTexCoor(int bh)  

    {  

        float[] result=new float[bh*6*2];   

        float REPEAT=2;  

        float sizeh=1.0f/bh;//行數  

        int c=0;  

        for(int i=0;i<bh;i++)  

        {  

                //每行列一個矩形,由兩個三角形構成,共六個點,12個紋理坐標  

                float t=i*sizeh;  

                  

                result[c++]=0;  

                result[c++]=t;  

              

                result[c++]=0;  

                result[c++]=t+sizeh;   

                  

                result[c++]=REPEAT;  

                result[c++]=t;  

                              

                result[c++]=0;  

                result[c++]=t+sizeh;  

                  

                result[c++]=REPEAT;  

                result[c++]=t+sizeh;     

                  

                result[c++]=REPEAT;  

                result[c++]=t;  

        }  

        return result;  

    }  

}  

 

[java] 

package wyf.lgz;  

  

import android.app.Activity;  

import android.content.pm.ActivityInfo;  

import android.os.Bundle;  

import android.view.Window;  

import android.view.WindowManager;  

  

public class Activity_GL_Cylinder extends Activity {  

    private MyGLSurfaceView mGLSurfaceView;  

    /** Called when the activity is first created. */  

    @Override  

    public void onCreate(Bundle savedInstanceState) {  

        super.onCreate(savedInstanceState);  

          

        requestWindowFeature(Window.FEATURE_NO_TITLE);  

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);  

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);  

          

        mGLSurfaceView = new MyGLSurfaceView(this);  

        setContentView(mGLSurfaceView);  

        mGLSurfaceView.setFocusableInTouchMode(true);//設置為可觸控  

        mGLSurfaceView.requestFocus();//獲取焦點  

    }  

      

    @Override  

    protected void onResume() {  

        super.onResume();  

        mGLSurfaceView.onResume();  

    }  

  

    @Override  

    protected void onPause() {  

        super.onPause();  

        mGLSurfaceView.onPause();  

    }     

}  

 

[java]  

package wyf.lgz;  

  

import java.io.IOException;  

import java.io.InputStream;  

  

import android.opengl.GLSurfaceView;  

import android.opengl.GLUtils;  

  

import javax.microedition.khronos.egl.EGLConfig;  

import javax.microedition.khronos.opengles.GL10;  

import javax.microedition.khronos.opengles.GL11;  

  

import android.content.Context;  

import android.graphics.Bitmap;  

import android.graphics.BitmapFactory;  

import android.view.MotionEvent;  

  

public class MyGLSurfaceView extends GLSurfaceView {  

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

    private SceneRenderer mRenderer;//場景渲染器  

    private float mPreviousY;//上次的觸控位置Y坐標  

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

    private int lightAngle=90;//燈的當前角度  

      

    public MyGLSurfaceView(Context context) {  

        super(context);  

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

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

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

    }     

     

    //觸摸事件回調方法   

    @Override   

    public boolean onTouchEvent(MotionEvent e) {  

        float y = e.getY();  

        float x = e.getX();  

        switch (e.getAction()) {  

        case MotionEvent.ACTION_MOVE:  

            float dy = y – mPreviousY;//計算觸控筆Y位移  

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

            mRenderer.cylinder.mAngleX += dy * TOUCH_SCALE_FACTOR;//設置沿x軸旋轉角度  

            mRenderer.cylinder.mAngleZ += dx * TOUCH_SCALE_FACTOR;//設置沿z軸旋轉角度  

            requestRender();//重繪畫面  

        }  

        mPreviousY = y;//記錄觸控筆位置  

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

        return true;  

    }  

  

    private class SceneRenderer implements GLSurfaceView.Renderer   

    {     

        int textureId;//紋理名稱ID  

        DrawCylinder cylinder;//創建圓柱體  

          

        public SceneRenderer()  

        {  

  

        }  

          

        public void onDrawFrame(GL10 gl) {                    

            //清除顏色緩存  

            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);  

            //設置當前矩陣為模式矩陣  

            gl.glMatrixMode(GL10.GL_MODELVIEW);  

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

            gl.glLoadIdentity();       

                    

            gl.glPushMatrix();//保護變換矩陣現場  

              

            float lx=0; //設定光源的位置  

            float ly=(float)(7*Math.cos(Math.toRadians(lightAngle)));  

            float lz=(float)(7*Math.sin(Math.toRadians(lightAngle)));  

            float[] positionParamsRed={lx,ly,lz,0};  

            gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, positionParamsRed,0);      

              

            initMaterial(gl);//初始化紋理  

            gl.glTranslatef(0, 0, -10f);//平移  

            initLight(gl);//開燈  

            cylinder.drawSelf(gl);//繪制  

            closeLight(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) width / height;  

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

            gl.glFrustumf(-ratio, ratio, -1, 1, 1, 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.glShadeModel(GL10.GL_SMOOTH);  

            //啟用深度測試  

            gl.glEnable(GL10.GL_DEPTH_TEST);  

               

            textureId=initTexture(gl,R.drawable.stone);//紋理ID  

            cylinder=new DrawCylinder(10f,2f,18f,textureId);//創建圓柱體  

              

//            //開啟一個線程自動旋轉光源  

//            new Thread()  

//            {  

//                public void run()  

//                {  

//                    while(true)  

//                    {  

//                      lightAngle+=5;//轉動燈  

//                      mRenderer.cylinder.mAngleY+=2*TOUCH_SCALE_FACTOR;//球沿Y軸轉動  

//                    requestRender();//重繪畫面  

//                    try  

//                    {  

//                        Thread.sleep(50);//休息10ms再重繪  

//                    }  

//                    catch(Exception e)  

//                    {  

//                        e.printStackTrace();  

//                    }                     

//                    }  

//                }  

//            }.start();  

        }  

    }  

      

    //初始化白色燈  

    private void initLight(GL10 gl)  

    {      

        gl.glEnable(GL10.GL_LIGHTING);//允許光照      

        gl.glEnable(GL10.GL_LIGHT1);//打開1號燈    

          

        //環境光設置  

        float[] ambientParams={0.2f,0.2f,0.2f,1.0f};//光參數 RGBA  

        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, ambientParams,0);              

          

        //散射光設置  

        float[] diffuseParams={1f,1f,1f,1.0f};//光參數 RGBA  

        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, diffuseParams,0);   

          

        //反射光設置  

        float[] specularParams={1f,1f,1f,1.0f};//光參數 RGBA  

        gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_SPECULAR, specularParams,0);   

    }  

      

    //關閉燈  

    private void closeLight(GL10 gl)  

    {  

        gl.glDisable(GL10.GL_LIGHT1);  

        gl.glDisable(GL10.GL_LIGHTING);  

    }  

      

    //初始化材質  

    private void initMaterial(GL10 gl)  

    {  

        //環境光  

        float ambientMaterial[] = {248f/255f, 242f/255f, 144f/255f, 1.0f};  

        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, ambientMaterial,0);  

        //散射光  

        float diffuseMaterial[] = {248f/255f, 242f/255f, 144f/255f, 1.0f};  

        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, diffuseMaterial,0);  

        //高光材質  

        float specularMaterial[] = {248f/255f, 242f/255f, 144f/255f, 1.0f};  

        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, specularMaterial,0);  

        gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 100.0f);  

    }  

      

    //初始化紋理  

    public int initTexture(GL10 gl,int drawableId)//textureId  

    {  

        //生成紋理ID  

        int[] textures = new int[1];  

        gl.glGenTextures(1, textures, 0);      

        int currTextureId=textures[0];      

        gl.glBindTexture(GL10.GL_TEXTURE_2D, currTextureId);  

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR_MIPMAP_NEAREST);  

        gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR_MIPMAP_LINEAR);  

        ((GL11)gl).glTexParameterf(GL10.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL10.GL_TRUE);  

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,GL10.GL_REPEAT);  

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,GL10.GL_REPEAT);  

          

          

          

        InputStream is = this.getResources().openRawResource(drawableId);  

        Bitmap bitmapTmp;   

        try   

        {  

            bitmapTmp = BitmapFactory.decodeStream(is);  

        }   

        finally   

        {  

            try   

            {  

                is.close();  

            }   

            catch(IOException e)   

            {  

                e.printStackTrace();  

            }  

        }  

        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapTmp, 0);  

        bitmapTmp.recycle();   

          

        return currTextureId;  

    }  

}  

 

發佈留言