1.简介
上一篇已经将一个平面图形绘制出来了,这一次我们将在上一次绘制出来的图形的表面上进行纹理贴图。
图片准备:(宽高须为2的N次方)
最终图片是以Bitmap形式。现在考虑如何把这张图片映射到绘制的平面上?
纹理坐标数据以图片左上角为(0,0),右下角为(1,1)为基础
上一篇文章已经知道,面数组为{0,1,2,3,4,5}绘制,所以要给组成面的每个顶点,映射一个纹理坐标数据,如下:
float[]{
0f,0f , 1f,1f , 1f,0f
}
这样一张图片就全部映射到绘制的平面上了。
2.代码
public class OtherShader implements GLSurfaceView.Renderer{ FloatBuffer vertextBuffer; //纹理坐标数据 FloatBuffer textureBuffer; ByteBuffer faceBuffer; private float roate; //使用的纹理 int texture; Context context; public OtherShader(Context context) { this.context = context; vertextBuffer = floatArray2Buffer(vertex); faceBuffer = ByteBuffer.wrap(face); textureBuffer = floatArray2Buffer(text); } float[] vertex = new float[]{ -0.5f , 0.5f , 0f , -0.5f , -0.5f , 0f , 0.5f , -0.5f , 0f , -0.5f , 0.5f , 0f , 0.5f , -0.5f , 0f , 0.5f , 0.5f , 0f }; byte[] face = new byte[]{ 0,1,2, 3,4,5 }; //纹理坐标数据 float[] text = { 0f,0f , 0f,1f , 1f,1f, 0f,0f , 1f,1f , 1f,0f }; //将顶点颜色数组转换为IntBuffer,是OpenGl ES所需要的,可以不设置顶点颜色 private IntBuffer intArray2Buffer(int[] rect1color) { IntBuffer intBuffer; //不用该方法得到IntBuffer,因为Android平台限制,Buffer必须为native Buffer,所以要通过allocateDirect()创建 //并且该Buffer必须是排序的,所以要order()方法进行排序 //intBuffer = IntBuffer.wrap(rect1color); //因为一个int=4字节 ByteBuffer bb = ByteBuffer.allocateDirect(rect1color.length * 4); bb.order(ByteOrder.nativeOrder()); intBuffer = bb.asIntBuffer(); intBuffer.put(rect1color); intBuffer.position(0); //移到第一个点的数据 return intBuffer; } //将顶点位置数组转换为FloatBuffer,是OpenGl ES所需要的 private FloatBuffer floatArray2Buffer(float[] rect1) { FloatBuffer floatBuffer; //不用该方法得到FloatBuffer,因为Android平台限制,Buffer必须为native Buffer,所以要通过allocateDirect()创建 //并且该Buffer必须是排序的,所以要order()方法进行排序 //floatBuffer = FloatBuffer.wrap(rect1); //因为一个int=4字节 ByteBuffer bb = ByteBuffer.allocateDirect(rect1.length * 4); bb.order(ByteOrder.nativeOrder()); floatBuffer = bb.asFloatBuffer(); floatBuffer.put(rect1); floatBuffer.position(0); //移到第一个点的数据 return floatBuffer; } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { //关闭抗抖动 gl.glDisable(GL10.GL_DITHER); //修正系统透视 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT , GL10.GL_FASTEST); //设置阴影平滑模式 gl.glShadeModel(GL10.GL_SMOOTH); //启用深度测试 记录Z轴深度 gl.glEnable(GL10.GL_DEPTH_TEST); //设置深度测试的类型 gl.glDepthFunc(GL10.GL_LEQUAL); //*******启用2D纹理************* gl.glEnable(GL10.GL_TEXTURE_2D); //加载纹理 loadTexture(gl); } private void loadTexture(GL10 gl) { Bitmap bitmap = null; bitmap = BitmapFactory.decodeResource(context.getResources() , R.drawable.bj); int[] textures = new int[1]; gl.glGenTextures(1 , textures , 0); texture = textures[0]; gl.glBindTexture(GL10.GL_TEXTURE_2D , 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); 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); GLUtils.texImage2D(GL10.GL_TEXTURE_2D , 0 , bitmap , 0); if (bitmap != null){ bitmap.recycle(); } } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { //设置3D窗口的大小及位置 gl.glViewport(0 , 0 , width , height ); //将矩阵模式设置为投影矩阵 gl.glMatrixMode(GL10.GL_PROJECTION); //初始化单位矩阵 gl.glLoadIdentity(); //计算透视窗宽高比 float ratio = (float)width/height; //设置透视视窗的空间大小 默认为 -1,1,-1,1,-1,1 //gl.glFrustumf(-ratio , ratio , -1 , 1 ,1 , 10); } @Override public void onDrawFrame(GL10 gl) { //清除屏幕缓存和深度缓存 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); //启用顶点坐标数据 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); //设置当前矩形堆栈为模型堆栈 gl.glMatrixMode(GL10.GL_MODELVIEW); //启用纹理贴图坐标数组 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); //重置当前的模型视图矩阵 gl.glLoadIdentity(); //如果需要用颜色填充平面,还需要禁用顶点颜色数据 gl.glColor4f(0.2f , 1.0f , 0.2f , 0.0f); gl.glDisableClientState(GL10.GL_COLOR_ARRAY); //绕y轴旋转 //gl.glRotatef(roate , 0f , 1f , 0f); //设置顶点位置数据 gl.glVertexPointer(3 , GL10.GL_FLOAT , 0 , vertextBuffer); //设置贴图数组 gl.glTexCoordPointer(2 , GL10.GL_FLOAT , 0 , textureBuffer); //根据顶点绘制平面 //执行贴图 gl.glBindTexture(GL10.GL_TEXTURE_2D , texture); gl.glDrawElements(GL10.GL_TRIANGLES, faceBuffer.remaining() , GL10.GL_UNSIGNED_BYTE , faceBuffer); //停止绘制 gl.glFinish(); //停用坐标数据 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); //禁用纹理数组 gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); roate+=1; if (roate == 360){ roate = 0; } } }