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、至此,整个项目已开发完毕,单击执行,便会得到上面效果;