使用OpenGL ES绘制3D图形需要注意的几点是:
1. Android的三维坐标系默认原点位于屏幕中央。
2. 绘制3D图形时,各个顶点的坐标是以原点为参照的,比如顶点坐标为(0.5,0,0), 表示顶点在正x轴的二分之一处。
3. 绘制前需调用glTranslatef(x, y, z) 函数设置图形的参照原点。
4. OpenGL ES绘制的图形都是由若干个三角形组合起来的。
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLSurfaceView.Renderer;
public class MyRenderer implements Renderer {
float[] taperVertices = new float[]{//三棱锥的四个顶点
0.0f,0.4f,0.0f,
-0.4f,-0.4f,-0.4f,
0.4f,-0.4f,-0.4f,
0.0f,-0.4f,0.4f
};
int[] taperColors = new int[]{//三棱锥的四个顶点的颜色
655335,0,0,0,
0,655335,0,0,
0,0,655335,0,
655335,655335,0,0,
};
private byte[] taperFacets = new byte[]{//三棱锥的四个面
0,1,2,
0,1,3,
1,2,3,
0,2,3
};
float[] cubeVertices = new float[]{//正方体的8个顶点
0.4f,0.4f,0.4f,
0.4f,-0.4f,0.4f,
-0.4f,-0.4f,0.4f,
-0.4f,0.4f,0.4f,
0.4f,0.4f,-0.4f,
0.4f,-0.4f,-0.4f,
-0.4f,-0.4f,-0.4f,
-0.4f,0.4f,-0.4f,
};
private byte[] cubFacets = new byte[]{//正方体的6个矩形面(12个三角面)
0,1,2,
0,2,3,
2,3,7,
2,6,7,
0,3,7,
0,4,7,
4,5,6,
4,6,7,
0,1,4,
1,4,5,
1,2,6,
1,5,6
};
FloatBuffer taperVerticesBuffer;
IntBuffer taperColorBuffer;
ByteBuffer taperFacesBuffer;
FloatBuffer cubeVerticesBuffer;
ByteBuffer cubeFacesBuffer;
private float rotateX = 0;
private float rotateY = 0;
public void setRotateX(float rotateX) {
this.rotateX = this.rotateX + rotateX;
}
public void setRotateY(float rotateY) {
this.rotateY = this.rotateY + rotateY;
}
public MyRenderer() {
taperVerticesBuffer = floteBufferUtil(taperVertices);
taperColorBuffer = intBufferUtil(taperColors);
taperFacesBuffer = ByteBuffer.wrap(taperFacets);
cubeVerticesBuffer = floteBufferUtil(cubeVertices);
cubeFacesBuffer = ByteBuffer.wrap(cubFacets);
}
private IntBuffer intBufferUtil(int[] arr) {
IntBuffer mBuffer;
//初始化ByteBuffer,长度是arr数组的4倍,因为一个int占4字节
ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
//数组排列用nativeOrder
qbb.order(ByteOrder.nativeOrder());
mBuffer = qbb.asIntBuffer();
mBuffer.put(arr);
mBuffer.position(0);
return mBuffer;
}
private FloatBuffer floteBufferUtil(float[] arr) {
FloatBuffer mBuffer;
//初始化ByteBuffer,长度是arr数组的4倍,因为一个flote占4字节
ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
//数组排列用nativeOrder
qbb.order(ByteOrder.nativeOrder());
mBuffer = qbb.asFloatBuffer();
mBuffer.put(arr);
mBuffer.position(0);
return mBuffer;
}
@Override
public void onDrawFrame(GL10 arg0) {
arg0.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);//清除屏幕缓存和深度缓存
arg0.glEnableClientState(GL10.GL_VERTEX_ARRAY);//启用顶点坐标数据
arg0.glEnableClientState(GL10.GL_COLOR_ARRAY);//启用顶点颜色数据
arg0.glMatrixMode(GL10.GL_MODELVIEW);//设置当前矩阵模式为模型视图
/////////////////////////////绘制第一个图形//////////////////////////////////////////////////////////////////
arg0.glLoadIdentity();
arg0.glTranslatef(0.0f, 0.5f, 0.0f);
arg0.glRotatef(rotateY, 0.0f, 1.0f, 0.0f);//沿着Y轴旋转
arg0.glRotatef(rotateX, 1.0f, 0.0f, 0.0f);
arg0.glVertexPointer(3, GL10.GL_FLOAT, 0, taperVerticesBuffer);//设置顶点位置数据
arg0.glColorPointer(4, GL10.GL_FIXED, 0, taperColorBuffer);//设置顶点颜色数据
arg0.glDrawElements(GL10.GL_TRIANGLE_STRIP, taperFacesBuffer.remaining(), GL10.GL_UNSIGNED_BYTE, taperFacesBuffer);//按taperFacesBuffer指定的面绘制三角形
/////////////////////////////绘制第二个图形//////////////////////////////////////////////////////////////////
arg0.glLoadIdentity();
arg0.glTranslatef(0.0f, -0.5f, 0.0f);
arg0.glRotatef(rotateY, 0.0f, 1.0f, 0.0f);
arg0.glRotatef(rotateX, 1.0f, 0.0f, 0.0f);
arg0.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeVerticesBuffer);
arg0.glDrawElements(GL10.GL_TRIANGLE_STRIP, cubeFacesBuffer.remaining(), GL10.GL_UNSIGNED_BYTE, cubeFacesBuffer);
//绘制结束
arg0.glFinish();
arg0.glDisableClientState(GL10.GL_VERTEX_ARRAY);//禁用顶点坐标数据
arg0.glDisableClientState(GL10.GL_COLOR_ARRAY);//禁用顶点颜色数据
rotateX+=0.5;
rotateY+=0.5;
}
@Override
public void onSurfaceChanged(GL10 arg0, int arg1, int arg2) {
arg0.glViewport(0, 0, arg1, arg2);//设置3D视窗的大小及位置
arg0.glMatrixMode(GL10.GL_PROJECTION);//设置当前矩阵模式为投影模式
arg0.glLoadIdentity();//初始化单位矩阵
float ratio = (float)arg1/arg2;
arg0.glFrustumf(ratio, ratio, -1, 1, 1, 10);//设置透视视窗的空间大小
}
@Override
public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) {
arg0.glDisable(GL10.GL_DITHER);//关闭抗抖动
arg0.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);//设置系统对透视进行修正
arg0.glClearColor(0, 0, 0, 0);
arg0.glShadeModel(GL10.GL_SMOOTH);//设置平滑模式
arg0.glEnable(GL10.GL_DEPTH_TEST);//启用深度测试
arg0.glDepthFunc(GL10.GL_LEQUAL);//设置深度测试的类型
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
public class MainActivity extends ActionBarActivity {
MyRenderer renderer;
GestureDetector gestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GLSurfaceView surfaceView = new GLSurfaceView(this);
renderer = new MyRenderer();
surfaceView.setRenderer(renderer);
setContentView(surfaceView);
gestureDetector = new GestureDetector(new MyGestureDetectorListener());
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
public class MyGestureDetectorListener implements OnGestureListener {
@Override
public boolean onDown(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
arg2 = arg2 > 2000 ? 2000 : arg2;
arg2 = arg2 < -2000 ? -2000 : arg2;
arg3 = arg3 > 2000 ? 2000 : arg3;
arg3 = arg3 < -2000 ? -2000 : arg3;
renderer.setRotateX(arg3);
renderer.setRotateY(arg2);
return true;
}
@Override
public void onLongPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
float arg3) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
}
}
本文介绍了使用OpenGL ES绘制3D图形的关键步骤,包括理解Android的三维坐标系、设置图形的参照原点、利用顶点和颜色数据绘制3D形状,如三棱锥和正方体,并通过手势监听实现图形的旋转效果。示例代码展示了如何创建和绘制这两个3D形状,以及如何处理触摸事件以改变旋转角度。

1万+

被折叠的 条评论
为什么被折叠?



