感谢支持
我们一直在努力

Android OpenGL ES开发学习教程

1)首先你要定义自己的Polygon类,当然你一可以直接在Renderer的子类中直接绘制,为了更加符合面向对象,还是自定义一个Polygon类更好,这样代码更加清晰,Polygon类中主要有Polygon的顶点坐标,和绘制Polygon对象的draw方法,例如下面的代码:

public class Polygon{
 
 /** The buffer holding the Polygon‘s vertices


保存Polygon对象顶点坐标的FloatBuffer


 */
 private FloatBuffer vertexBuffer;
 
 /** The initial vertex definition


保存Polygon对象顶点坐标的的float数组


*/
 private float vertices[] = {
        0.0f, 1.0f, 0.0f,  //Top
        -1.0f, -1.0f, 0.0f, //Bottom Left
        1.0f, -1.0f, 0.0f  //Bottom Right
            };
 
 /**
  * The Triangle constructor.
  *
  * Initiate the buffers.
  */
 public Triangle() {
  //this is the common method to initiate the FloatBuffer


 //下面是一种常用的初始化FloatBuffer的方法,本人还见到过一种方法,如下:


 //vertexBuffer = FloatBuffer.wrap(vertices)


 //但是如果用这种方法在运行的时候会报错,指出你的FloatBuffer没有序列化,


//不明白原因,如有明白的高手帮解释一下,不胜感激
  ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
  byteBuf.order(ByteOrder.nativeOrder());
  vertexBuffer = byteBuf.asFloatBuffer();
  vertexBuffer.put(vertices);
  vertexBuffer.position(0);
 }


 /**
  * The object own drawing function.
  * Called from the renderer to redraw this instance
  * with possible changes in values.
  *
  * @param gl – The GL context
  */
 public void draw(GL10 gl) {


//这就是Polygon被绘制的方法,下面都是一些在draw方法中经常用到的简单的设置,


//在此不一一解释了
  //Set the face rotation
  gl.glFrontFace(GL10.GL_CW);
  
  //Point to our vertex buffer
  gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
  
  //Enable vertex buffer
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  
  //Draw the vertices as triangle strip
  gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
  
  //Disable the client state before leaving
  gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
 }
}


2)下面就是Renderer子类,它就是一个OpenGL渲染器,就是真正绘制3D图形的地方,主要是重写三个方法(三个方法将在下面一一标出),设置一些属性,来完成我们想要达到的效果,代码如下:


public class Myrenderer implements Renderer {
 
  public Myrenderer () {
  triangle = new Triangle();
  square = new Square();
 }


 /**
  * The Surface is created/init()


这个方法是当surface创建时调用的方法,主要是设置一些属性
  */
 public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
  gl.glShadeModel(GL10.GL_SMOOTH);    //Enable Smooth Shading
  gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);  //Black Background
  gl.glClearDepthf(1.0f);      //Depth Buffer Setup
  gl.glEnable(GL10.GL_DEPTH_TEST);    //Enables Depth Testing
  gl.glDepthFunc(GL10.GL_LEQUAL);    //The Type Of Depth Testing To Do
  
  //Really Nice Perspective Calculations
  gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
 }


 /**
  * Here we do our drawing
  */
 public void onDrawFrame(GL10 gl) {


//这个方法就是真正绘制3D图形的方法,系统会根据机器的性能在固定的时间间隔自动调用这个方法


//这里通过设置gl的属性,和我们定义的Polygon类的顶点坐标来绘制我们想要达到的效果


  //Clear Screen And Depth Buffer
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 
  gl.glLoadIdentity();     //Reset The Current Modelview Matrix
  
  gl.glTranslatef(0.0f, -1.2f, -6.0f); //Move down 1.2 Unit And Into The Screen 6.0
  square.draw(gl);      //Draw the square
  
  gl.glTranslatef(0.0f, 2.5f, 0.0f);  //Move up 2.5 Units
  triangle.draw(gl);      //Draw the triangle  
 }


 /**
  * If the surface changes, reset the view
  */
 public void onSurfaceChanged(GL10 gl, int width, int height) {


 


//这个方法是当surface改变时调用的方法,也是设置一些gl的属性,


//大体的设置没有太大变化,所以这基本上是一个通用的写法
  if(height == 0) {       //Prevent A Divide By Zero By
   height = 1;       //Making Height Equal One
  }


  gl.glViewport(0, 0, width, height);  //Reset The Current Viewport
  gl.glMatrixMode(GL10.GL_PROJECTION);  //Select The Projection Matrix
  gl.glLoadIdentity();      //Reset The Projection Matrix


  //Calculate The Aspect Ratio Of The Window
  GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);


  gl.glMatrixMode(GL10.GL_MODELVIEW);  //Select The Modelview Matrix
  gl.glLoadIdentity();      //Reset The Modelview Matrix
 }
}


 


 


3)最后就是把我们的GLSurfaceView通过activity的setContentView()方法加载到屏幕上,代码如下:


public class Run extends Activity {


 /** The OpenGL View */
 private GLSurfaceView glSurface;


 /**
  * Initiate the OpenGL View and set our own
  * Renderer   */
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);


  //Create an Instance with this Activity
  glSurface = new GLSurfaceView(this);
  //Set our own Renderer
  glSurface.setRenderer(new Lesson02());
  //Set the GLSurface as View to this Activity
  setContentView(glSurface);
 }


 /**
  * Remember to resume the glSurface
  */
 @Override
 protected void onResume() {
  super.onResume();
  glSurface.onResume();
 }


 /**
  * Also pause the glSurface
  */
 @Override
 protected void onPause() {
  super.onPause();
  glSurface.onPause();
 }



希望给刚刚入门的同学一些帮助,也希望和高手们交流一下经验。

第一课里是一个简单的正方形的绘制,现在我们要为这个正方形添加颜色。

唯一的不同(和上一课比较,以后同意)就是在Polygon类的draw方法中添加了如下内容(红色字体):


public void draw(GL10 gl) {  
  //Set the face rotation
  gl.glFrontFace(GL10.GL_CW);
  
  //Point to our vertex buffer
  gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
  
  //Enable vertex buffer
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  
  //Set The Color To Blue
  gl.glColor4f(0.5f, 0.5f, 1.0f, 1.0f); 
  
  //Draw the vertices as triangle strip
  gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
  
  //Disable the client state before leaving
  gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
 }


 


 


 


当然也可以通过下面的方法为Polygon添加颜色,和使用顶点数组一样,我们可以建立一个颜色的数组,具体实现如下:


/** The buffer holding the colors */
 private FloatBuffer colorBuffer;


 


/** The initial color definition */
 private float colors[] = {
           1.0f, 0.0f, 0.0f, 1.0f, //Set The Color To Red, last value 100% luminance
           0.0f, 1.0f, 0.0f, 1.0f, //Set The Color To Green, last value 100% luminance
           0.0f, 0.0f, 1.0f, 1.0f,   //Set The Color To Blue, last value 100% luminance


           0.5f, 0.5f, 0.5f, 1.0f,   //Set The Color To combination, last value 100% luminance

                };


 


  //在我们的Polygon类构造方法中为colorBuffer初始化


public Polygon() {
    byteBuf = ByteBuffer.allocateDirect(colors.length * 4);
  byteBuf.order(ByteOrder.nativeOrder());
  colorBuffer = byteBuf.asFloatBuffer();
  colorBuffer.put(colors);
  colorBuffer.position(0);
 }


 


//在draw方法中添加对color的权限(红色部分为新加内容)


public void draw(GL10 gl) {  
  //Set the face rotation
  gl.glFrontFace(GL10.GL_CW);
  
  //Point to our buffers
  gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
  gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
  
  //Enable the vertex and color state
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
  
  //Draw the vertices as triangles
  gl.glDrawArrays(GL10.GL_TRIANGLES, 0, vertices.length / 3);
  
  //Disable the client state before leaving
  gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
  gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
 } 


这样我们就绘制了一个带有颜色的Polygon。

这一课和前面的唯一不同在于MyRenderer类中的onDrawFrame(GL10 gl)方法,在这个方法里我们添加了对Polygon翻转的操作,


代码如下(红色部分为新添加的部分):


//定义一个控制翻转角度的变量


private float rquad;


public void onDrawFrame(GL10 gl) {
  //Clear Screen And Depth Buffer
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 
  gl.glLoadIdentity();     //Reset The Current Modelview Matrix
  
  //Drawing
  gl.glTranslatef(0.0f, -1.2f, -6.0f); //Move down 1.0 Unit And Into The Screen 6.0
  gl.glRotatef(rquad, 1.0f, 0.0f, 0.0f); //Rotate The PolygonOn The X axis ( NEW )  沿x轴翻转
  square.draw(gl);      //Draw the Polygon


  
  rquad -= 0.15f;       //Decrease The Rotation Variable For The Polygon( NEW )  改变翻转角度
 }

前几课我们绘制的是平面的图形,下面我们要绘制一个立体的图形——六棱柱,这里我们使用了顶点索引,这是一个新的概念,它是一个指明了顶点绘制顺序的ByteBuffer,还有就是这里我们使用的是二维的顶点数组,其中第二维中所有的顶点是同一个平面上的点,所以我们是一个面一个面的绘制,MyPolygon 类改动的代码较多,其他类基本不变,下面一一描述:


public class MyPolygon {


//保存每一个平面的顶点索引的ByteBuffer数组
 private ByteBuffer[] indexBuffer;


//保存每一个平面的顶点坐标的FloatBuffer数组
 private FloatBuffer[] faceVertexBuffer;


//保存每一个平面的顶点坐标的二维数组


 private float[][] faceVertices = {
   new float[] {
     -0.5f, -0.816f, 1.0f,// bottom left 0
     0.5f, -0.816f, 1.0f,// bottom right 1
     -1.0f, 0.0f, 1.0f,// middle left 2
     1.0f, 0.0f, 1.0f,// middle right 3
     -0.5f, 0.816f, 1.0f, // top left 4
     0.5f, 0.816f, 1.0f // top right 5
   },// front face
   new float[] {
     -0.5f, -0.816f, -1.0f,// bottom left 6
     0.5f, -0.816f, -1.0f,// bottom right 7
     -1.0f, 0.0f, -1.0f,// middle left 8
     1.0f, 0.0f, -1.0f,// middle right 9
     -0.5f, 0.816f, -1.0f, // top left 10
     0.5f, 0.816f, -1.0f // top right 11
   },// back face
   new float[] {
     -0.5f, -0.816f, -1.0f,// bottom left 6
     0.5f, -0.816f, -1.0f,// bottom right 7
     -0.5f, -0.816f, 1.0f,// bottom left 0
     0.5f, -0.816f, 1.0f // bottom right 1
   },// bottom face
   new float[] {
     -1.0f, 0.0f, -1.0f,// middle left 8
     -0.5f, -0.816f, -1.0f,// bottom left 6
     -1.0f, 0.0f, 1.0f,// middle left 2
     -0.5f, -0.816f, 1.0f // bottom left 0
   },// bottom left face
   new float[] {
     0.5f, -0.816f, -1.0f,// bottom right 7
     1.0f, 0.0f, -1.0f,// middle right 9
     0.5f, -0.816f, 1.0f,// bottom right 1
     1.0f, 0.0f, 1.0f // middle right 3
   },// bottom right face
   new float[] {
     0.5f, 0.816f, -1.0f, // top right 11
     1.0f, 0.0f, -1.0f,// middle right 9
     0.5f, 0.816f, 1.0f,// top right 5
     1.0f, 0.0f, 1.0f // middle right 3
   },// top right face
   new float[] {
     -0.5f, 0.816f, -1.0f, // top left 10
     0.5f, 0.816f, -1.0f, // top right 11
     -0.5f, 0.816f, 1.0f,// top left 4
     0.5f, 0.816f, 1.0f // top right 5
   },// top face
   new float[] {
     -0.5f, 0.816f, -1.0f, // top left 10
     -1.0f, 0.0f, -1.0f,// middle left 8
     -0.5f, 0.816f, 1.0f, // top left 4
     -1.0f, 0.0f, 1.0f // middle left 2
   } // top left face
 };


 


//定义每一个平面颜色的数组


 private float[] colors = { 1.0f, 0.0f, 0.0f, 1.0f, // 0
   0.0f, 1.0f, 0.0f, 1.0f,// 1
   0.0f, 0.0f, 1.0f, 1.0f, // 2
   1.0f, 1.0f, 1.0f, 1.0f, // 3
   1.0f, 1.0f, 0.0f, 1.0f,// 4
   1.0f, 0.0f, 1.0f, 1.0f,// 5
   0.0f, 1.0f, 1.0f, 1.0f,// 6
   0.5f, 0.5f, 0.5f, 1.0f, // 7
 };


 


//保存每一个平面的顶点索引的二维数组


 private byte[][] indies = {
   new byte[] {
     0, 1, 2,
     1, 3, 2,
     2, 3, 4,
     3, 5, 4
     },// front face
   new byte[] {
     0, 1, 2,
     1, 3, 2,
     2, 3, 4,
     3, 5, 4
     },// back face
   new byte[] {
     0, 1, 2,
     1, 3, 2
     },// bottom face
   new byte[] {
     0, 1, 2,
     1, 3, 2
     },// bottom left face
   new byte[] {
     0, 1, 2,
     1, 3, 2
     },// bottom right face
   new byte[] {
     0, 1, 2,
     1, 3, 2
     },// top right face
   new byte[] {
     0, 1, 2,
     1, 3, 2
     },// top face
   new byte[] {
     0, 1, 2,
     1, 3, 2
     } // top left face
 };


 public MyPolygon() {


 


//利用循环初始化顶点坐标faceVertexBuffer数组和顶点索引indexBuffer数组
  ByteBuffer bb;
  faceVertexBuffer = new FloatBuffer[8];
  for (int i = 0; i < faceVertices.length; i++) {
   bb = ByteBuffer.allocateDirect(faceVertices[i].length * 4);
   bb.order(ByteOrder.nativeOrder());
   faceVertexBuffer[i] = bb.asFloatBuffer();
   faceVertexBuffer[i].put(faceVertices[i]);
   faceVertexBuffer[i].position(0);


  }


  indexBuffer = new ByteBuffer[8];
  for (int i = 0; i < indies.length; i++) {
   indexBuffer[i] = ByteBuffer.allocateDirect(indies[i].length);
   indexBuffer[i].put(indies[i]);
   indexBuffer[i].position(0);


  }


 }


 public void onDraw(GL10 gl) {


//利用循环绘制六棱柱的每一个面,并给不同的面设置不同的颜色
  gl.glFrontFace(GL10.GL_CW);


  for (int i = 0; i < 8; i++) {
   gl.glVertexPointer(3, GL10.GL_FLOAT, 0, faceVertexBuffer[i]);
   gl.glColor4f(colors[4 * i + 0], colors[4 * i + 1],
     colors[4 * i + 2], colors[4 * i + 3]);
   gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);



   gl.glDrawElements(GL10.GL_TRIANGLES, indies[i].length,
     GL10.GL_UNSIGNED_BYTE, indexBuffer[i]);//另一种绘制的方法glDrawElements
   gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
  }


 }


}  

这里我们将加入纹理来代替颜色设置不同表面的内容,和上一课不同的地方是在Polygon类中加入了一些纹理的设置,下面将一一描述,代码如下:


public class MyPolygon {
  //保存纹理的FloatBuffer


 private FloatBuffer[] textureBuffer;


//用来加载纹理的数组
 private int [] textures = new int[8];


//保存纹理顶点坐标的数组 


private float[][] texture = {
   new float[]{
    0.0f,0.0f,
    1.0f,0.0f,
    0.0f,0.5f,
    1.0f,0.5f,
    0.0f,1.0f,
    1.0f,1.0f,
    
   },
   new float[]{
     0.0f,0.0f,
     1.0f,0.0f,
     0.0f,0.5f,
     1.0f,0.5f,
     0.0f,1.0f,
     1.0f,1.0f,
     
   },
   new float[]{
     0.0f,0.0f,
     1.0f,0.0f,
     0.0f,1.0f,
     1.0f,1.0f,
     
   },
   new float[]{
     0.0f,0.0f,
     1.0f,0.0f,
     0.0f,1.0f,
     1.0f,1.0f,
     
   },
   new float[]{
     0.0f,0.0f,
     1.0f,0.0f,
     0.0f,1.0f,
     1.0f,1.0f,
     
   },
   new float[]{
     0.0f,0.0f,
     1.0f,0.0f,
     0.0f,1.0f,
     1.0f,1.0f,
     
   },
   new float[]{
     0.0f,0.0f,
     1.0f,0.0f,
     0.0f,1.0f,
     1.0f,1.0f,
     
   },
   new float[]{
     0.0f,0.0f,
     1.0f,0.0f,
     0.0f,1.0f,
     1.0f,1.0f,
     
   }
 };



 public MyPolygon() {
  ByteBuffer bb;
//初始化保存纹理的FloatBuffer


 textureBuffer = new FloatBuffer[8];
  for (int i = 0; i < 8; i++) {
   bb = ByteBuffer.allocateDirect(texture[i].length * 4);
   bb.order(ByteOrder.nativeOrder());
   textureBuffer[i] = bb.asFloatBuffer();
   textureBuffer[i].put(texture[i]);
   textureBuffer[i].position(0);
  }


 }


 public void onDraw(GL10 gl) {
  gl.glFrontFace(GL10.GL_CW);


  for (int i = 0; i < 8; i++) {
   // Generate one texture pointer…
   // …and bind it to our array


//生成一个纹理引用,并把它和当前的数组绑定
   gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[i]);
   //Point to our buffers
  //设置纹理坐标


   gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer[i]);
   //Enable the texture state  
   //加入纹理坐标的权限


   gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
      //Disable the client state before leaving
  //取消纹理坐标的权限


   gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
  }


 }
 


 


//加载和绑定纹理的方法
 public void loadTexture(GL10 gl, Context context) {
  //define the resourcesId
  int[] resourcesIds = { R.drawable.gou, R.drawable.hou,
    R.drawable.laohu, R.drawable.laoshu, R.drawable.tuzi,
    R.drawable.xiaolong, R.drawable.xiaoniu, R.drawable.zhu };
  gl.glGenTextures(8, textures, 0);
  // Get the texture from the Android resource directory
  for (int i = 0; i < 8; i++) {
   Bitmap bitmap = loadBitmap(context, resourcesIds[i]);
   // Generate one texture pointer…
   // …and bind it to our array
   gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[i]);


// Create Nearest Filtered Texture
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
    GL10.GL_NEAREST);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
    GL10.GL_LINEAR);
   // Use the Android GLUtils to specify a two-dimensional texture
   // image from our bitmap
   GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
   // Clean up
   bitmap.recycle();
  }
     }


 


//加载bitmap


public Bitmap loadBitmap(Context context, int resourceid) {


  InputStream is = context.getResources().openRawResource(resourceid);
  try {
   // BitmapFactory is an Android graphics utility for images
   return BitmapFactory.decodeStream(is);


  } finally {
   // Always clear and close
   try {
    is.close();
    is = null;
   } catch (IOException e) {
   }
  }
 可以到网上找一些256×256的图片代替文中的图片资源。

赞(0) 打赏
转载请注明出处:服务器评测 » Android OpenGL ES开发学习教程
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏