Android OpenGL ES :材质渲染

转载自:http://blog.csdn.net/mapdigit/article/details/7527746

前面讨论了如何给3D图形染色,更一般的情况是使用位图来给Mesh上色(渲染材质)。主要步骤如下:

创建Bitmap对象

使用材质渲染,首先需要构造用来渲染的Bitmap对象,Bitmap对象可以从资源文件中读取或是从网络下载或是使用代码构造。为简单起见,本例从资源中读取:

[java]  view plain copy print ?
  1. Bitmap bitmap = BitmapFactory.decodeResource(contect.getResources(),  
  2.  R.drawable.icon);  


要注意的是,有些设备对使用的Bitmap的大小有要求,要求Bitmap的宽度和长度为2的几次幂(1,2,4,8,16,32,64.。。。),如果使用不和要求的Bitmap来渲染,可能只会显示白色。

创建材质(Generating a texture)

下一步使用OpenGL库创建一个材质(Texture),首先是获取一个Texture Id。

[java]  view plain copy print ?
  1. // Create an int array with the number of textures we want,  
  2. // in this case 1.  
  3. int[] textures = new int[1];  
  4. // Tell OpenGL to generate textures.  
  5. gl.glGenTextures(1, textures, 0);  


textures中存放了创建的Texture ID,使用同样的Texture Id ,也可以来删除一个Texture:

[java]  view plain copy print ?
  1. // Delete a texture.  
  2. gl.glDeleteTextures(1, textures, 0)  


有了Texture Id之后,就可以通知OpenGL库使用这个Texture:

[java]  view plain copy print ?
  1. gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);  

设置Texture参数glTexParameter

下一步需要给Texture填充设置参数,用来渲染的Texture可能比要渲染的区域大或者小,这是需要设置Texture需要放大或是缩小时OpenGL的模式:

[java]  view plain copy print ?
  1. // Scale up if the texture if smaller.  
  2. gl.glTexParameterf(GL10.GL_TEXTURE_2D,  
  3.  GL10.GL_TEXTURE_MAG_FILTER,  
  4.  GL10.GL_LINEAR);  
  5.    
  6. // scale linearly when image smalled than texture  
  7. gl.glTexParameterf(GL10.GL_TEXTURE_2D,  
  8.  GL10.GL_TEXTURE_MIN_FILTER,  
  9.  GL10.GL_LINEAR);  

常用的两种模式为GL10.GL_LINEAR和GL10.GL_NEAREST。

需要比较清晰的图像使用GL10.GL_NEAREST:

而使用GL10.GL_LINEAR则会得到一个较模糊的图像:

UV Mapping

下一步要告知OpenGL库如何将Bitmap的像素映射到Mesh上。这可以分为两步来完成:

定义UV坐标

UV Mapping指将Bitmap的像素映射到Mesh上的顶点。UV坐标定义为左上角(0,0),右下角(1,1)(因为使用的2D Texture),下图坐标显示了UV坐标,右边为我们需要染色的平面的顶点顺序:

为了能正确的匹配,需要把UV坐标中的(0,1)映射到顶点0,(1,1)映射到顶点2等等。


[java]  view plain copy print ?
  1. float textureCoordinates[] = {0.0f, 1.0f,  
  2.  1.0f, 1.0f,  
  3.  0.0f, 0.0f,  
  4.  1.0f, 0.0f };  


 

如果使用如下坐标定义:

[java]  view plain copy print ?
  1. float textureCoordinates[] = {0.0f, 0.5f,  
  2.  0.5f, 0.5f,  
  3.  0.0f, 0.0f,  
  4.  0.5f, 0.0f };  

Texture匹配到Plane的左上角部分。

[java]  view plain copy print ?
  1. float textureCoordinates[] = {0.0f, 2.0f,  
  2.  2.0f, 2.0f,  
  3.  0.0f, 0.0f,  
  4.  2.0f, 0.0f };  

将使用一些不存在的Texture去渲染平面(UV坐标为0,0-1,1 而 (0,0)-(2,2)定义超过UV定义的大小),这时需要告诉OpenGL库如何去渲染这些不存在的Texture部分。

有两种设置

  • GL_REPEAT 重复Texture。
  • GL_CLAMP_TO_EDGE 只靠边线绘制一次。

下面有四种不同组合:

本例使用如下配置:

[java]  view plain copy print ?
  1. gl.glTexParameterf(GL10.GL_TEXTURE_2D,  
  2.  GL10.GL_TEXTURE_WRAP_S,  
  3.  GL10.GL_REPEAT);  
  4. gl.glTexParameterf(GL10.GL_TEXTURE_2D,  
  5.  GL10.GL_TEXTURE_WRAP_T,  
  6.  GL10.GL_REPEAT);  

然后是将Bitmap资源和Texture绑定起来:


[java]  view plain copy print ?
  1. GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);  
[java]  view plain copy print ?
  1. <p><strong>使用Texture</strong></p><p>为了能够使用上面定义的Texture,需要创建一Buffer来存储UV坐标:</p><pre class="java" name="code">FloatBuffer byteBuf = ByteBuffer.allocateDirect(texture.length * 4);  
  2. byteBuf.order(ByteOrder.nativeOrder());  
  3. textureBuffer = byteBuf.asFloatBuffer();  
  4. textureBuffer.put(textureCoordinates);  
  5. textureBuffer.position(0);</pre>  
  6. <p><br>  
  7.  </p>  
  8. <p> </p>  
  9. <pre></pre>  
  10. <p><br>  
  11. <strong>渲染</strong></p>  
  12. <pre class="java" name="code">// Telling OpenGL to enable textures.  
  13. gl.glEnable(GL10.GL_TEXTURE_2D);  
  14. // Tell OpenGL where our texture is located.  
  15. gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);  
  16. // Tell OpenGL to enable the use of UV coordinates.  
  17. gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  
  18. // Telling OpenGL where our UV coordinates are.  
  19. gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);  
  20.    
  21. // ... here goes the rendering of the mesh ...  
  22.    
  23. // Disable the use of UV coordinates.  
  24. gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  
  25. // Disable the use of textures.  
  26. gl.glDisable(GL10.GL_TEXTURE_2D);</pre>  
  27. <p>本例代码是在一个平面上(SimplePlane)下使用Texture来渲染,首先是修改Mesh基类,使它能够支持定义UV 坐标:</p>  
  28. <br>  
  29. <pre class="java" name="code">// Our UV texture buffer.  
  30. private FloatBuffer mTextureBuffer;  
  31.    
  32. /** 
  33.  * Set the texture coordinates. 
  34.  * 
  35.  * @param textureCoords 
  36.  */  
  37. protected void setTextureCoordinates(float[] textureCoords) {  
  38.  // float is 4 bytes, therefore we multiply the number if  
  39.  // vertices with 4.  
  40.  ByteBuffer byteBuf = ByteBuffer.allocateDirect(  
  41.  textureCoords.length * 4);  
  42.  byteBuf.order(ByteOrder.nativeOrder());  
  43.  mTextureBuffer = byteBuf.asFloatBuffer();  
  44.  mTextureBuffer.put(textureCoords);  
  45.  mTextureBuffer.position(0);  
  46. }</pre>  
  47. <p><br>  
  48.  并添加设置Bitmap和创建Texture的方法:</p>  
  49. <pre class="java" name="code">// Our texture id.  
  50. private int mTextureId = -1;  
  51.    
  52. // The bitmap we want to load as a texture.  
  53. private Bitmap mBitmap;  
  54.    
  55. /** 
  56.  * Set the bitmap to load into a texture. 
  57.  * 
  58.  * @param bitmap 
  59.  */  
  60. public void loadBitmap(Bitmap bitmap) {  
  61.  this.mBitmap = bitmap;  
  62.  mShouldLoadTexture = true;  
  63. }  
  64.    
  65. /** 
  66.  * Loads the texture. 
  67.  * 
  68.  * @param gl 
  69.  */  
  70. private void loadGLTexture(GL10 gl) {  
  71.  // Generate one texture pointer...  
  72.  int[] textures = new int[1];  
  73.  gl.glGenTextures(1, textures, 0);  
  74.  mTextureId = textures[0];  
  75.    
  76.  // ...and bind it to our array  
  77.  gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);  
  78.    
  79.  // Create Nearest Filtered Texture  
  80.  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,  
  81.  GL10.GL_LINEAR);  
  82.  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,  
  83.  GL10.GL_LINEAR);  
  84.    
  85.  // Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE  
  86.  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,  
  87.  GL10.GL_CLAMP_TO_EDGE);  
  88.  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,  
  89.  GL10.GL_REPEAT);  
  90.    
  91.  // Use the Android GLUtils to specify a two-dimensional texture image  
  92.  // from our bitmap  
  93.  GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);  
  94. }</pre>  
  95. <p>最后修改draw方法来渲染材质:</p>  
  96. <br>  
  97. <pre class="java" name="code">// Indicates if we need to load the texture.  
  98. private boolean mShouldLoadTexture = false;  
  99.    
  100. /** 
  101.  * Render the mesh. 
  102.  * 
  103.  * @param gl 
  104.  *            the OpenGL context to render to. 
  105.  */  
  106. public void draw(GL10 gl) {  
  107.  ...  
  108.    
  109.  // Smooth color  
  110.  if (mColorBuffer != null) {  
  111.  // Enable the color array buffer to be used during rendering.  
  112.  gl.glEnableClientState(GL10.GL_COLOR_ARRAY);  
  113.  gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);  
  114.  }  
  115.    
  116.  if (mShouldLoadTexture) {  
  117.  loadGLTexture(gl);  
  118.  mShouldLoadTexture = false;  
  119.  }  
  120.  if (mTextureId != -1 && mTextureBuffer != null) {  
  121.  gl.glEnable(GL10.GL_TEXTURE_2D);  
  122.  // Enable the texture state  
  123.  gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  
  124.    
  125.  // Point to our buffers  
  126.  gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);  
  127.  gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);  
  128.  }  
  129.    
  130.  gl.glTranslatef(x, y, z);  
  131.    
  132.  ...  
  133.    
  134.  // Point out the where the color buffer is.  
  135.  gl.glDrawElements(GL10.GL_TRIANGLES, mNumOfIndices,  
  136.  GL10.GL_UNSIGNED_SHORT, mIndicesBuffer);  
  137.    
  138.  ...  
  139.    
  140.  if (mTextureId != -1 && mTextureBuffer != null) {  
  141.  gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  
  142.  }  
  143.    
  144.  ...  
  145.    
  146. }</pre>  
  147. <p><br>  
  148.  本例使用的SimplePlane定义如下:</p>  
  149. <p> </p>  
  150. <p> </p>  
  151. <pre class="java" name="code">package se.jayway.opengl.tutorial.mesh;  
  152.    
  153. /** 
  154.  * SimplePlane is a setup class for Mesh that creates a plane mesh. 
  155.  * 
  156.  * @author Per-Erik Bergman (per-erik.bergman@jayway.com) 
  157.  * 
  158.  */  
  159. public class SimplePlane extends Mesh {  
  160.  /** 
  161.  * Create a plane with a default with and height of 1 unit. 
  162.  */  
  163.  public SimplePlane() {  
  164.  this(11);  
  165.  }  
  166.    
  167.  /** 
  168.  * Create a plane. 
  169.  * 
  170.  * @param width 
  171.  *            the width of the plane. 
  172.  * @param height 
  173.  *            the height of the plane. 
  174.  */  
  175.  public SimplePlane(float width, float height) {  
  176.  // Mapping coordinates for the vertices  
  177.  float textureCoordinates[] = { 0.0f, 2.0f, //  
  178.  2.0f, 2.0f, //  
  179.  0.0f, 0.0f, //  
  180.  2.0f, 0.0f, //  
  181.  };  
  182.    
  183.  short[] indices = new short[] { 012132 };  
  184.    
  185.  float[] vertices = new float[] { -0.5f, -0.5f, 0.0f,  
  186.  0.5f, -0.5f, 0.0f,  
  187.  -0.5f,  0.5f, 0.0f,  
  188.  0.5f, 0.5f, 0.0f };  
  189.    
  190.  setIndices(indices);  
  191.  setVertices(vertices);  
  192.  setTextureCoordinates(textureCoordinates);  
  193.  }  
  194. }</pre>  
  195. <p><a href="http://www.imobilebbs.com/wordpress/wp-content/uploads/2011/06/20110601002.png"><img class="aligncenter size-full wp-image-1578" title="20110601002" alt="" src="http://www.imobilebbs.com/wordpress/wp-content/uploads/2011/06/20110601002.png" width="333" height="493"></a></p>  
  196. <p>本例示例代码<a href="http://www.imobilebbs.com/download/android/opengles/OpenGLESTutorial4.zip">下载</a> ,到本篇为止介绍了OpenGL ES开发的基本方法,更详细的教程将在以后发布,后面先回到Android ApiDemos中OpenGL ES的示例。<br>  
  197. </p>  
  198. <p> </p>  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值