1.main.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_liner"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
</LinearLayout>
2.MainActivity.java类
package com.example.triangle;
import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
public class MainActivity extends Activity {
private MySurfaceView mSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mSurfaceView = new MySurfaceView(this); //创建MySurfaceView对象
mSurfaceView.requestFocus(); //获取焦点
mSurfaceView.setFocusableInTouchMode(true); //设置为可触控
LinearLayout ll = (LinearLayout) this.findViewById(R.id.main_liner); //获得线性布局的引用
ll.addView(mSurfaceView); //将视图加载到线性布局中
}
@Override
protected void onPause() {
super.onPause(); //继承父类的onPause()方法
mSurfaceView.onPause(); //调用onPause()方法
}
@Override
protected void onResume() {
super.onResume(); //调用父类的onResume()方法
mSurfaceView.onResume(); //调用onResume()方法
}
}
3.MySurfaceView.java类
package com.example.triangle;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;
public class MySurfaceView extends GLSurfaceView {
private final float TOUCH_SCALE_FACTOR = 180.0f / 320; //角度放缩比例
private SceneRenderer myRenderer; //场景渲染器
private float myPreviousY; //上次屏幕上的触控位置的Y坐标
private float myPreviousX; //上次屏幕上的触控位置的X坐标
public MySurfaceView(Context context) {
super(context);
myRenderer = new SceneRenderer(); //创建场景渲染器
this.setRenderer(myRenderer); //设置渲染器
this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); //渲染模式为主动渲染
}
@Override
public boolean onTouchEvent(MotionEvent event) { //触摸事件回调方法
float y = event.getY(); //获得当前触点的Y坐标
float x = event.getX(); //获得当前触点的X坐标
switch(event.getAction()){
case MotionEvent.ACTION_MOVE:
float dy = y - myPreviousY; //滑动距离在Y轴方向上的垂直距离
float dx = x - myPreviousX; //活动距离在X轴方向上的垂直距离
myRenderer.tr.yAngle += dy * TOUCH_SCALE_FACTOR; //设置沿y轴旋转角度
myRenderer.tr.zAngle += dx * TOUCH_SCALE_FACTOR; //设置沿z轴旋转角度
requestRender(); //渲染画面
}
myPreviousY = y; //前一次触控位置的Y坐标
myPreviousX = x; //前一次触控位置的X坐标
return true; //事件成功返回true
}
private class SceneRenderer implements GLSurfaceView.Renderer{
Triangle tr = new Triangle(); //创建三角形对象
public SceneRenderer() { //构造器
}
@Override
public void onDrawFrame(GL10 gl) { //重写onDrawFrame()方法
gl.glEnable(GL10.GL_CULL_FACE); //设置为打开背面剪裁
gl.glShadeModel(GL10.GL_SMOOTH); //设置着色模型为平滑着色
gl.glFrontFace(GL10.GL_CCW); //设置自定义卷绕顺序:逆时针为正面
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); //清除缓存
gl.glMatrixMode(GL10.GL_MODELVIEW); //设置当前矩阵为模式矩阵
gl.glLoadIdentity(); //设置当前矩阵为单位矩阵
gl.glTranslatef(0, 0, -2.0f); //把坐标系往z轴负方向平移2.0f个单位
tr.drawSelf(gl); //调用具体绘制方法
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height); //设置视口大小和位置
gl.glMatrixMode(GL10.GL_PROJECTION); //设置矩阵为投影矩阵
gl.glLoadIdentity(); //设置矩阵为单位矩阵
float ratio = (float)width/height; //比例大小
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); //设置投影模式
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glDisable(GL10.GL_DITHER); //关闭抗抖动
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); //设置模式
gl.glClearColor(0, 0, 0, 0); //设置屏幕背景色为黑色
gl.glEnable(GL10.GL_DEPTH_TEST); //启动深度检测
}
}
}
4.Triangle.java类
package com.example.triangle;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import javax.microedition.khronos.opengles.GL10;
public class Triangle {
private IntBuffer myVertexBuffer; //顶点坐标数据缓冲
private IntBuffer myColorBuffer; //顶点着色数据缓冲
private ByteBuffer myIndexBuffer; //顶点构建的索引数据缓冲
int vCount = 0; //顶点数量
int iCount = 0; //索引数量
float yAngle = 0; //绕y轴旋转的角度
float zAngle = 0; //绕z轴旋转的角度
public Triangle() {
vCount = 3; //设定顶点数量
final int UNIT_SIZE = 10000; //放缩比例
int []vertices = new int[]{ //创建顶点数据数组
-8 * UNIT_SIZE,6 * UNIT_SIZE,0,
-8 * UNIT_SIZE,-6 * UNIT_SIZE,0,
8 * UNIT_SIZE,-6 * UNIT_SIZE,0,
};
//创建顶点坐标数据缓存,由于不同平台字节顺序不同,数据单元不是字节的要经ByteBuffer转换
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); //开辟新的内存块
vbb.order(ByteOrder.nativeOrder()); //设置为本地平台的字节顺序
myVertexBuffer = vbb.asIntBuffer(); //转换为int型缓冲
myVertexBuffer.put(vertices); //向缓冲区中放入顶点坐标数据
myVertexBuffer.position(0); //设置缓冲区的起始位置
final int one = 66535; //支持65535色色彩通道
int []colors = new int[]{ //创建顶点颜色值数组
one,one,one,0, //每个顶点4个色彩值RGBA
one,one,one,0,
one,one,one,0,
};
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4); //开辟新的内存块
cbb.order(ByteOrder.nativeOrder()); //设置为本地平台的字节顺序
myColorBuffer = cbb.asIntBuffer(); //转换为int型缓冲
myColorBuffer.put(colors); //向缓冲区中放入顶点颜色坐标数据
myColorBuffer.position(0); //设置缓冲区的起始位置
//为三角形构造索引数据初始化
iCount = 3; //设置索引数量
byte []indices = new byte[]{ //创建索引数组
0,1,2
};
//创建三角形构造索引数据缓冲
myIndexBuffer = ByteBuffer.allocateDirect(indices.length); //开辟新的内存块
myIndexBuffer.put(indices); //想缓冲区中放入索引坐标数据
myIndexBuffer.position(0); //设置缓冲区的起始位置
}
public void drawSelf(GL10 gl){ //实现具体绘制方法
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); //启用顶点坐标数组
gl.glEnableClientState(GL10.GL_COLOR_ARRAY); //启用顶点颜色数组
gl.glRotatef(yAngle, 0, 1, 0); //根据yAngle的角度值,绕y轴旋转yAngle
gl.glRotatef(zAngle, 0, 0, 1); //根据zAngle的角度值,绕z轴旋转zAngle
//为画笔指定顶点坐标数据(每个顶点的坐标数量为3,顶点坐标值的类型为GL_FIXED,连续顶点坐标数据之间的间隔,顶点坐标来源)
gl.glVertexPointer(3, GL10.GL_FIXED, 0, myVertexBuffer);
//为画笔指定顶点颜色数据(每个顶点的颜色值数量为4,顶点坐标值的类型为GL_FIXED,连续顶点坐标数据之间的间隔,顶点颜色值来源)
gl.glColorPointer(4, GL10.GL_FIXED, 0, myColorBuffer);
//绘制图形(填充模式,顶点数量,索引值的类型,索引值数据)
gl.glDrawElements(GL10.GL_TRIANGLES, iCount, GL10.GL_UNSIGNED_BYTE, myIndexBuffer);
}
}
显示效果:
1.正面时截图
2.旋转时截图