openGL ES 画球

openGL ES很强大,使用它可以很简单我画出我们想要的3D图形,今天从画球体入手。

这个示例中包含灯光效果,如果不想看灯光效果可以去掉 initLight()/ initMaterialWhite()这两个方法

第一个类:Ball

[java] view plain copy
  1. public class Ball {  
  2.     private IntBuffer vertexBuffer;  //顶点坐标数据缓冲  
  3.     private IntBuffer nomalBuffer;  //顶点法向量数据缓冲  
  4.     private ByteBuffer indexBuffer; //顶点构建索引数据缓冲  
  5.     public float angleX;  //沿x轴旋转角度  
  6.     int vCount=0;  
  7.     int iCount=0;  
  8.     public Ball(int scale){  
  9.         //顶点坐标初始化数据  
  10.         final int UNIT_SIZE=10000;  
  11.         ArrayList<Integer> alVertex=new ArrayList<Integer>();  
  12.         final int angleSpan=18;          //将小球进行单位切分的角度  
  13.         for (int vAngle = -90; vAngle <= 90; vAngle=vAngle+angleSpan) {  //垂直方向angleSpan度一份  
  14.             for (int hAngle = 0; hAngle <360; hAngle=hAngle+angleSpan ) { //水平方向angleSpan度一份  
  15.                 //纵向横向各到一个角度后计算对应的此点在球面上的坐标  
  16.                 double xozLength=scale*UNIT_SIZE*Math.cos(Math.toRadians(vAngle));  
  17.                 int x=(int) (xozLength*Math.cos(Math.toRadians(hAngle)));  
  18.                 int y=(int) (xozLength*Math.sin(Math.toRadians(hAngle))) ;  
  19.                 int z=(int) (scale*UNIT_SIZE*Math.sin(Math.toRadians(vAngle)));  
  20.                 alVertex.add(x);   
  21.                 alVertex.add(y);  
  22.                 alVertex.add(z);  
  23.             }  
  24.         }  
  25.         vCount=alVertex.size()/3;  //顶点数量为坐标值数量的三分之一,因为一个顶点有三个坐标  
  26.         //将alVertix中的坐标值转存到一个int数组中  
  27.         int vertices []=new int[alVertex.size()];  
  28.         for (int i = 0; i < alVertex.size(); i++) {  
  29.             vertices[i]=alVertex.get(i);  
  30.         }  
  31.         //创建顶点坐标数据缓冲  
  32.         ByteBuffer vbb=ByteBuffer.allocateDirect(vertices.length*4);  
  33.         vbb.order(ByteOrder.nativeOrder()); //设置字节顺序  
  34.         vertexBuffer=vbb.asIntBuffer();  //转换成int型缓冲  
  35.         vertexBuffer.put(vertices);   //向缓冲区放入顶点坐标数据  
  36.         vertexBuffer.position(0);  //设置缓冲区起始位置  
  37.           
  38.         //创建顶点坐标数据缓冲  
  39.         ByteBuffer nbb=ByteBuffer.allocateDirect(vertices.length*4); //一个整型是4个字节  
  40.         nbb.order(ByteOrder.nativeOrder());  //设置字节顺序   由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer  
  41.         nomalBuffer=nbb.asIntBuffer(); //转换成int型缓冲  
  42.         nomalBuffer.put(vertices);      //想缓冲区放入顶点坐标数据  
  43.         nomalBuffer.position(0);         //设置缓冲区起始位置  
  44.           
  45.         ArrayList<Integer> alIndex=new ArrayList<Integer>();  
  46.         int row=(180/angleSpan)+1//球面切分的行数  
  47.         int col=360/angleSpan;  //球面切分的列数  
  48.         for (int i = 0; i < row; i++) {  //对每一行循环  
  49.             if(i>0 && i<row-1){  
  50.                 //中间行  
  51.                 for (int j = -1; j < col; j++) {   
  52.                     //中间行的两个相邻点与下一行的对应点构成三角形  
  53.                     int k=i*col+j;  
  54.                     alIndex.add(k+col);  
  55.                     alIndex.add(k+1);  
  56.                     alIndex.add(k);  
  57.                 }  
  58.                 for (int j = 0; j < col+1; j++) {  
  59.                     //中间行的两个相邻点与上一行的对应点构成三角形          
  60.                     int k=i*col+j;  
  61.                     alIndex.add(k-col);  
  62.                     alIndex.add(k-1);  
  63.                     alIndex.add(k);  
  64.                 }  
  65.             }  
  66.         }  
  67.         iCount=alIndex.size();  
  68.         byte indices []=new byte[iCount];  
  69.         for (int i = 0; i < iCount; i++) {  
  70.             indices[i]=alIndex.get(i).byteValue();  
  71.         }  
  72.         //三角形构造数据索引缓冲  
  73.         indexBuffer=ByteBuffer.allocateDirect(iCount);  //由于indices是byte型的,索引不用乘以4  
  74.         indexBuffer.put(indices);  
  75.         indexBuffer.position(0);  
  76.     }  
  77.       
  78.     public void drawSelf(GL10 gl){  
  79.         gl.glRotatef(angleX, 100);  //沿x轴旋转  
  80.         gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);  //启用顶点坐标数组  
  81.         gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);  //启用顶点向量数组  
  82.           
  83.         //为画笔指定顶点坐标数据  
  84.         gl.glVertexPointer(  
  85.                 3 , //顶点坐标数量,三个坐标一个顶点  
  86.                 GL10.GL_FIXED ,  //顶点坐标数据类型  
  87.                 0//连续顶点之间的数据间隔  
  88.                 vertexBuffer //顶点坐标数据    
  89.                 );  
  90.         //为画笔指定顶点向量数据  
  91.         gl.glNormalPointer(GL10.GL_FIXED, 0, nomalBuffer);  
  92.         //绘制图形  
  93.         gl.glDrawElements(  
  94.                 GL10.GL_TRIANGLES,  //以三角形的方式填充  
  95.                 iCount, GL10.GL_UNSIGNED_BYTE, indexBuffer);   
  96.           
  97.     }  
  98.       
  99. }  
第二个类:MySurfaceView
[java] view plain copy
  1. public class MySurfaceView  extends GLSurfaceView{  
  2.   
  3.     //private final float TOUCH_SCALE_FACTOR=180.0f/360;  //角度缩放比例  
  4.     private final float TOUCH_SCALE_FACTOR=0.5f;  
  5.     private SceneRenderer myRenderer;   //场景渲染器  
  6.     public boolean openLightFlag=false;  //开灯标记,false为关灯,true为开灯  
  7.     private float previousX,previousY;  //上次触控的横纵坐标  
  8.       
  9.       
  10.     public MySurfaceView(Context context) {  
  11.         super(context);  
  12.         myRenderer=new SceneRenderer();  //创建场景渲染器  
  13.         this.setRenderer(myRenderer);  //设置渲染器  
  14.         this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); //渲染模式为主动渲染  
  15.     }  
  16.       
  17.     @Override  
  18.     public boolean onTouchEvent(MotionEvent event) {  
  19.         float x=event.getX();  
  20.         //float y=event.getY();  
  21.         switch (event.getAction()) {  
  22.         case MotionEvent.ACTION_MOVE:  
  23.             //float dy=y-previousY;  //计算触控笔移动Y位移  
  24.             float dx=x-previousX;   //计算触控笔移动X位移  
  25.             myRenderer.ball.angleX +=dx*TOUCH_SCALE_FACTOR;  //设置沿x轴旋转角度  
  26.             requestRender();                               //渲染画面  
  27.             break;  
  28.         }  
  29.         previousX=x;                                   //前一次触控位置x坐标  
  30.         return true;                                      //事件成功返回true  
  31.     }  
  32.       
  33.     private class SceneRenderer implements GLSurfaceView.Renderer{  
  34.         Ball ball=new Ball(4);  //创建圆  
  35.         public SceneRenderer(){}   
  36.           
  37.         public void onDrawFrame(GL10 gl) {  
  38.             gl.glEnable(GL10.GL_CULL_FACE) ; //打开背面剪裁  
  39.             gl.glShadeModel(GL10.GL_SMOOTH);  //开始平滑着色  
  40.             if(openLightFlag){  
  41.                 gl.glEnable(GL10.GL_LIGHTING);  
  42.                 initLight(gl, GL10.GL_LIGHT0);  
  43.                 initMaterialWhite(gl);  
  44.                 //设置light0光源位置  
  45.                 float [] positionParamsGreen={2,1,0,1};  
  46.                 gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, positionParamsGreen,0);  
  47.             }else{  
  48.                 gl.glDisable(GL10.GL_LIGHTING);  
  49.             }  
  50.             gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);  //清除缓存  
  51.             gl.glMatrixMode(GL10.GL_MODELVIEW); //设置当前矩形为模式矩阵  
  52.             gl.glLoadIdentity();   //设置矩阵为单位矩阵  
  53.             gl.glTranslatef(00, -1.8f);  //把坐标系往z轴负方向平移2.0f个单位  
  54.             ball.drawSelf(gl);  
  55.             gl.glLoadIdentity();  
  56.         }  
  57.   
  58.         public void onSurfaceChanged(GL10 gl, int width, int height) {  
  59.             gl.glViewport(00, width, height);   //设置视口大小和位置  
  60.             gl.glMatrixMode(GL10.GL_PROJECTION);   //设置矩阵为投影矩阵  
  61.             gl.glLoadIdentity();                   //设置矩阵为单位矩阵  
  62.             float ratio=(float)width/height;        //比例大小  
  63.             gl.glFrustumf(-ratio, ratio, -11110);  //设置投影模式  
  64.         }  
  65.   
  66.         public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
  67.             gl.glDisable(GL10.GL_DITHER);     //关闭抗抖动  
  68.             gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);  
  69.             //设置模式  
  70.             gl.glClearColor(0000);  //设置屏幕颜色为黑色  
  71.             gl.glEnable(GL10.GL_DEPTH_TEST);  //启用深度检测  
  72.               
  73.         }  
  74.   
  75.         /** 
  76.          * 初始化灯 
  77.          * @param gl 
  78.          * @param LIGTH  0-7代表八盏灯 
  79.          */  
  80.         private void initLight(GL10 gl,final int LIGHT){  
  81.             gl.glEnable(LIGHT); //打开LIGTH+1号灯  
  82.             //设置环境光  
  83.             float [] ambientParams  ={0.1f,0.1f,0.1f,1.0f};   //光参数RGBA  
  84.             gl.glLightfv(LIGHT, GL10.GL_AMBIENT, ambientParams,0);  
  85.             //设置散射光  
  86.             float [] diffuseParams={0.5f,0.5f,0.5f,1.0f};  //光参数RGBA  
  87.             gl.glLightfv(LIGHT, GL10.GL_DIFFUSE, diffuseParams, 0);   
  88.             //设置放射光  
  89.             float [] specularParams={1.0f,1.0f,1.0f,1.0f};  
  90.             gl.glLightfv(LIGHT, GL10.GL_SPECULAR, specularParams,0);  
  91.         }  
  92.           
  93.         private void initMaterialWhite(GL10 gl){   
  94.             //材质为白色时,什么颜色的光照在上面就将体现出什么颜色  
  95.             //设置环境光,为白色材质  
  96.             float [] ambientMaterial={0.4f,0.4f,0.4f,1.0f};  
  97.             gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, ambientMaterial,0);  
  98.             //设置散射光白色  
  99.             float [] diffuseMaterial={0.8f,0.8f,0.8f,1.0f};  
  100.             gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, diffuseMaterial, 0);  
  101.             //高光材质为白色          //建立镜面光float,镜面光一般设置较高  
  102.             float [] specularMaterial={1.0f,1.0f,1.0f,1.0f};  
  103.             gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, specularMaterial, 0);  
  104.             //高光反色区,数越大,高亮区域越小、越暗          //高光反射区域数越大,高亮区域越小  
  105.             float [] shininessMaterial={1.5f};  
  106.             gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, shininessMaterial,0);  
  107.         }  
  108.           
  109.     }  
  110.   
  111. }  

第三个类:MainActivity
[java] view plain copy
  1. public class MainActivity extends Activity {  
  2.       
  3.     private MySurfaceView mySurfaceView;  
  4.     @Override  
  5.     public void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.main);  
  8.         mySurfaceView=new MySurfaceView(this); //创建MysurfaceView对象  
  9.         mySurfaceView.requestFocus();           //获取焦点  
  10.         mySurfaceView.setFocusableInTouchMode(true);  //设置为可触控  
  11.         LinearLayout ll=(LinearLayout) this.findViewById(R.id.main_liner); //获得线性布局的引用  
  12.         ll.addView(mySurfaceView);  
  13.           
  14.         ToggleButton tb1=(ToggleButton) findViewById(R.id.toggleButton1);  
  15.         tb1.setOnCheckedChangeListener(new ButtonListener());  
  16.     }  
  17.       
  18.     class ButtonListener implements OnCheckedChangeListener{  
  19.   
  20.         public void onCheckedChanged(CompoundButton buttonView,  
  21.                 boolean isChecked) {  
  22.             switch (buttonView.getId()) {  
  23.             case R.id.toggleButton1:  
  24.                 mySurfaceView.openLightFlag=!mySurfaceView.openLightFlag;  
  25.                 break;  
  26.             }  
  27.               
  28.         }  
  29.           
  30.     }  
  31.       
  32.     @Override  
  33.     protected void onPause() {  
  34.         super.onPause();  
  35.         mySurfaceView.onPause();  //调用MySurfaceView的onPause()方法  
  36.     }  
  37.     @Override  
  38.     protected void onRestart() {  
  39.         super.onRestart();  
  40.         mySurfaceView.onResume();   
  41.     }  
  42.       
  43.       
  44. }  

第四个:main.xml
[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:id="@+id/main_liner"  
  6.     android:orientation="vertical" >  
  7.       
  8.     <ToggleButton   
  9.         android:textOff="关闭灯光效果"  
  10.         android:textOn="打开灯光效果"  
  11.         android:checked="true"  
  12.         android:id="@+id/toggleButton1"  
  13.         android:layout_width="fill_parent"  
  14.         android:layout_height="wrap_content"  
  15.         />  
  16.   
  17. </LinearLayout> 
博客地址:http://blog.csdn.net/wuzongpo/article/details/7230285

你可能感兴趣的:(openGL ES 画球)