OpenGL纹理是一种位图,可以把它粘贴到OpenGL物体的表面上。比如可以获取一张邮票的图像粘贴到正方形中,使正 方形看起来像一张邮票。要使邮票保持合适的方向,以便图像井然有序地排列,则必须获得形状的每个顶点并在正方形上标记出来,以便邮票和正方形的形状保持一 致。在OpenGL中引入了纹理坐标。
OpenGL 假设纹理图始终为1×1的正方形,其原点位于(0.0)处,右下角为(1,1)。如下图。
纹理坐标与顶点坐标之间的映射如下图:
所以我们用的浮点数组不只是要存储4个点的位置,还要存储纹理坐标值
vertices.put( new float[] { -80f, -120f, 0.0f, 1.0f,
vertices.put( new float[] { -80f, -120f, 0.0f, 1.0f,
80f, -120f,1.0f, 1.0f,
-80f, 120f,0.0f, 0.0f,
80f, 120f, 1.0f, 0.0f});
处理完纹理坐标与顶点坐标之间的映射关系后,剩余工作包括将纹理位图加载到内存,为它分配纹理ID,以便重用此纹理。
来看下完整代码吧,注意我们代码中纹理坐标和顶点坐标分开存放了,这样更加清晰点,不然还要stride(跳过)内存。
package com.waitingfy.android.glbasics; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLSurfaceView; import android.opengl.GLUtils; import android.opengl.GLSurfaceView.Renderer; import android.os.Bundle; import android.util.Log; import android.view.Window; import android.view.WindowManager; public class TexturedRectangleTest extends Activity { public GLSurfaceView glView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 去掉activity的标题,全屏显示 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); glView = new GLSurfaceView(this); glView.setRenderer(new SimpleRenderer()); setContentView(glView); } @Override public void onResume() { super.onPause(); glView.onResume(); } @Override public void onPause() { super.onPause(); glView.onPause(); } class SimpleRenderer implements Renderer { FloatBuffer vertices; FloatBuffer texture; ShortBuffer indices; int textureId; public SimpleRenderer() { ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4 * 2 * 4); byteBuffer.order(ByteOrder.nativeOrder()); vertices = byteBuffer.asFloatBuffer(); // vertices.put( new float[] { -80f, -120f,0,1f, // 80f, -120f, 1f,1f, // -80f, 120f, 0f,0f, // 80f,120f, 1f,0f}); vertices.put( new float[] { -80f, -120f, 80f, -120f, -80f, 120f, 80f, 120f}); ByteBuffer indicesBuffer = ByteBuffer.allocateDirect(6 * 2); indicesBuffer.order(ByteOrder.nativeOrder()); indices = indicesBuffer.asShortBuffer(); indices.put(new short[] { 0, 1, 2,1,2,3}); ByteBuffer textureBuffer = ByteBuffer.allocateDirect(4 * 2 * 4); textureBuffer.order(ByteOrder.nativeOrder()); texture = textureBuffer.asFloatBuffer(); texture.put( new float[] { 0,1f, 1f,1f, 0f,0f, 1f,0f}); indices.position(0); vertices.position(0); texture.position(0); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { Log.d("GLSurfaceViewTest", "surface created"); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { Log.d("GLSurfaceViewTest", "surface changed: " + width + "x" + height); } @Override public void onDrawFrame(GL10 gl) { textureId = loadTexture("bobrgb888.png",gl); //定义显示在屏幕上的什么位置(opengl 自动转换) gl.glViewport(0, 0, glView.getWidth(), glView.getHeight()); gl.glClear(GL10.GL_COLOR_BUFFER_BIT); gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); gl.glOrthof(-160, 160, -240, 240, 1, -1); gl.glEnable(GL10.GL_TEXTURE_2D); //绑定纹理ID gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertices); gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texture); // gl.glRotatef(1, 0, 1, 0); gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 6, GL10.GL_UNSIGNED_SHORT, indices); } public int loadTexture(String fileName,GL10 gl) { try { Bitmap bitmap = BitmapFactory.decodeStream(getAssets().open( fileName)); int textureIds[] = new int[1]; gl.glGenTextures(1, textureIds, 0); int textureId = textureIds[0]; gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); 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_NEAREST); gl.glBindTexture(GL10.GL_TEXTURE_2D, 0); bitmap.recycle(); return textureId; } catch (IOException e) { Log.d("TexturedRectangleTest", "couldn't load asset 'bobrgb888.png'!"); throw new RuntimeException("couldn't load asset '" + fileName + "'"); } } } }
注意下我们这里用到的图片”bobrgb888.png”是png格式,存放在/assets/下,长宽是128*128,好像纹理图片最好是2的n次方大小,而且是正方形。
下面是示例代码下载:gl-basics
Hahhaaha. I’m not too bright today. Great post!
[…] DirectX中的纹理跟Opengl中的是类似的,可以参考这篇文章 Android 中使用OpenGL ES进行2D开发(纹理Texture使用) […]
Good,It is wirte clearly.
[…] DirectX中的纹理跟Opengl中的是类似的,可以参考这篇文章 Android 中使用OpenGL ES进行2D开发(纹理Texture使用) […]