Android3D游戏开发之为三角形添加纹理
今天,来为大家演示的是三角形纹理贴图。在看之前,有必要回头去看下我的另一篇Android OpenGL es 纹理坐标设定与贴图规则一文。呵呵,下面开始我们得开发之旅;
首先,还是先来看下运行效果:
这里还实现了另一个功能:当我们点击图片,移动旋转,图片会改变形状,截图如下:
下面来一起开发这个简单的项目吧。
1、创建一个Android项目,在这里我命名为StripTexture。
2、在res/drawable-mdpi文件中导入一张图片,这里我是导入一张hao.png.如上面效果图。
3、我们在原有的包下新建一个Texture.java类,该类的主要目的是绘制三角形,具体代码如下:
public class Texture { private IntBuffer vertexBuffer; private FloatBuffer textureBuffer; public float mAngleY; public float mAngleZ; int vCount=0; int textureId; int one = 0x10000; public Texture(int textureId){ this.textureId=textureId; //顶点坐标数据的初始化================begin============================ vCount=3; int vertices[]=new int[]{ 0,one,0, //上顶点 -one,-one,0, //左下点 one,-one,0 }; //vertices.length*4是因为一个整数有四个字节 ByteBuffer vbb=ByteBuffer.allocateDirect(vertices.length*4); vbb.order(ByteOrder.nativeOrder());//设置字节顺序 vertexBuffer=vbb.asIntBuffer();//转换为int型缓存 vertexBuffer.put(vertices);//向缓存区中放入顶点坐标数据 vertexBuffer.position(0);//设置缓冲区起始位置 float textureCoors[]=new float[]{//顶点纹理S、T坐标值数组 0,1, 1,1, 0.5f,0 }; //创建顶点纹理数据缓冲 //textureCoors.length*4是因为一个float型数为四个字节 ByteBuffer cbb=ByteBuffer.allocateDirect(textureCoors.length*4); cbb.order(ByteOrder.nativeOrder());//设置字节顺序 textureBuffer=cbb.asFloatBuffer();//转换为float型缓冲 textureBuffer.put(textureCoors);//向缓冲区中放入顶点着色数据 textureBuffer.position(0);//设置缓冲区起始位置 } public void drawSelf(GL10 gl){ //沿Z轴旋转 gl.glRotatef(mAngleZ, 0, 0, 1); //沿Y轴旋转 gl.glRotatef(mAngleY, 0, 1, 0); //允许设置顶点 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); /*为顶点指定坐标数据,其中第一个参数每个顶点的坐标数量为3 xyz , * 第二个参数顶点坐标值的类型为 GL_FIXED(固定),第三个参数 * 连续顶点坐标数据之间的间隔,第四个参数顶点坐标数据*/ gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertexBuffer); //开启纹理 gl.glEnable(GL10.GL_TEXTURE_2D); //允许使用纹理数组 gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); //为纹理指定坐标数据 gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer); //帮顶指定名称ID纹理 gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); //绘制图形 gl.glDrawArrays(GL10.GL_TRIANGLES, 0, vCount); //关闭纹理设置 gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); //关闭顶点设置 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } }
4、在原有的包下面在新建一个名叫MySurfaceView的类,该类继承GLSurfaceView,并实现了onTouchEvent屏幕触摸单击事件,用于显示绘制的图形,在该类地内部,有一内部类,该内部类继承了Readerer用于为三角形贴上纹理。具体代码如下:
public class MySurfaceView extends GLSurfaceView{ private SceneRenderer mRenderer;//场景渲染器 private float mPreviousY;//上次的触控位置Y坐标 private float mPreviousX;//上次的触控位置X坐标 private float TOUCH_SCALE_FACTOR=180.0f/320;;//角度缩放比例 public MySurfaceView(Context context) { super(context); // TODO Auto-generated constructor stub mRenderer = new SceneRenderer(); //创建场景渲染器 setRenderer(mRenderer); //设置渲染器 setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//设置渲染模式为主动渲染 } public boolean onTouchEvent(MotionEvent e) { float y = e.getY(); float x = e.getX(); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: float dy = y - mPreviousY;//计算触控笔Y位移 float dx = x - mPreviousX;//计算触控笔Y位移 mRenderer.texTri.mAngleY += dy * TOUCH_SCALE_FACTOR;//设置沿x轴旋转角度 mRenderer.texTri.mAngleZ += dx * TOUCH_SCALE_FACTOR;//设置沿z轴旋转角度 requestRender();//重绘画面 } mPreviousY = y;//记录触控笔位置 mPreviousX = x;//记录触控笔位置 return true; } private class SceneRenderer implements GLSurfaceView.Renderer{ Texture texTri; int textureId;//纹理ID @Override public void onDrawFrame(GL10 gl) { // TODO Auto-generated method stub gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); //设置模型观察矩阵 gl.glMatrixMode(GL10.GL_MODELVIEW); //重置观察矩阵 gl.glLoadIdentity(); //移入屏幕2.5个单位 gl.glTranslatef(0.0f, 0.0f, -2.5f); //绘制图形 texTri.drawSelf(gl); } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { // TODO Auto-generated method stub //计算透视投影的比例 float ratio=(float)width/height; //设置视窗大小及位置 gl.glViewport(0, 0, width, height); //设置当前矩阵为投影矩阵 gl.glMatrixMode(GL10.GL_PROJECTION); //重置投影矩阵 gl.glLoadIdentity(); //调用此方法计算产生透视投影矩阵 gl.glFrustumf(-ratio, ratio, -1, 1, 1, 20); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // TODO Auto-generated method stub gl.glDisable(GL10.GL_DITHER);//关闭抗抖动 //设置特定Hint项目的模式,这里为设置为使用快速模式 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); //设置屏幕背景色黑色RGBA gl.glClearColor(0, 0, 0, 0); //设置着色模型为平滑着色 gl.glShadeModel(GL10.GL_SMOOTH); //启用深度测试 gl.glEnable(GL10.GL_DEPTH_TEST); //初始化纹理 textureId=initTexture(gl,R.drawable.hao); texTri=new Texture(textureId); } } public int initTexture(GL10 gl,int id){ //创建纹理,这里指定一个纹理 int[] textures=new int[1]; gl.glGenTextures(1, textures,0); int currTextureId=textures[0]; //绑定纹理 gl.glBindTexture(GL10.GL_TEXTURE_2D, currTextureId); 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); //为纹理指定图片 Bitmap bitmap=BitmapFactory.decodeResource(getResources(), id); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); bitmap.recycle(); return currTextureId;//返回纹理ID } }
5、在Activity中创建MySurfaceView对象,并把Activity中的内容设置为显示SurfaceView,如下:
package com.wyf.wpf; import android.app.Activity; import android.os.Bundle; public class MyActivity extends Activity { MySurfaceView mGLSurfaceView; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLSurfaceView = new MySurfaceView(this); setContentView(mGLSurfaceView); mGLSurfaceView.requestFocus();//获取焦点 mGLSurfaceView.setFocusableInTouchMode(true);//设置为可触控 } }6、至此,整个项目已开发完毕,单击执行,便会得到上面效果;