3D物体的碰撞和2D类似,都是根据坐标来计算物体的距离,判断是否碰撞。下面举个简单的列子吧,我这个列子比较局限,简单,只是为了说明这个方法而已,大家可以参照方法进行改进,下面看看代码吧。
package yy.cal;
import android.app.Activity;
import android.os.Bundle;
import android.widget.LinearLayout;
public class GLSurfaceViewActivity extends Activity {
private MySurfaceView mSurfaceView;//声明MySurfaceView对象
public 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() {
// TODO Auto-generated method stub
super.onPause();
mSurfaceView.onPause();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mSurfaceView.onResume();
}
}
package yy.cal;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.view.KeyEvent;
import android.view.MotionEvent;
public class MySurfaceView extends GLSurfaceView{
private final float TOUCH_SCALE_FACTOR = 180.0f/320;//角度缩放比例
private SceneRenderer mRenderer;//场景渲染器
private float mPreviousX;//上次的触控位置X坐标
public MySurfaceView(Context context) {
super(context);
mRenderer = new SceneRenderer(); //创建场景渲染器
setRenderer(mRenderer); //设置渲染器
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//设置渲染模式为主动渲染
}
//触摸事件回调方法
@Override
public boolean onTouchEvent(MotionEvent e) {
float x = e.getX();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dx = x - mPreviousX;//计算触控笔X位移
mRenderer.angle += dx * TOUCH_SCALE_FACTOR;//设置沿x轴旋转角度
requestRender();
//重绘画面
}
mPreviousX = x;//记录触控笔位置
return true;
}
public boolean onKeyDown(int keyCode,KeyEvent event){
if(keyCode==KeyEvent.KEYCODE_DPAD_UP)
{
mRenderer.x +=0.5f;
}
if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN){
mRenderer.x -=0.5f;
}
if(keyCode==KeyEvent.KEYCODE_DPAD_LEFT){
mRenderer.angle+=90;
}
if(keyCode==KeyEvent.KEYCODE_DPAD_RIGHT){
mRenderer.angle+=90;
}
return super.onKeyDown(keyCode, event);
}
private class SceneRenderer implements GLSurfaceView.Renderer
{
Cube cube=new Cube();//立方体
float angle=45;//总旋转角度
float x=0,y=0,z=0;
public void onDrawFrame(GL10 gl) {
//设置为打开背面剪裁
gl.glEnable(GL10.GL_CULL_FACE);
//设置着色模型为平滑着色
gl.glShadeModel(GL10.GL_SMOOTH);
//清除颜色缓存于深度缓存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
//设置当前矩阵为模式矩阵
gl.glMatrixMode(GL10.GL_MODELVIEW);
//设置当前矩阵为单位矩阵
gl.glLoadIdentity();
GLU.gluLookAt//不太可能变形的视角——小视角
(
gl,
0f, //人眼位置的X
10f, //人眼位置的Y
15.0f, //人眼位置的Z
0, //人眼球看的点X
0f, //人眼球看的点Y
0, //人眼球看的点Z
0,
1,
0
);
//旋转总坐标系
gl.glRotatef(angle, 0, 1, 0);
//绘制右立方体
gl.glPushMatrix();
gl.glTranslatef(x, y, z);
cube.drawSelf(gl);
gl.glPopMatrix();
gl.glPushMatrix();
gl.glTranslatef(2, 0, 0);
cube.drawSelf(gl);
gl.glPopMatrix();
if(x>1.0f&&x<3.0f){
ColorRect.flag=false;
}else{
ColorRect.flag=true;
}
}
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) height/width ;
//调用此方法计算产生透视投影矩阵
//gl.glFrustumf( -1, 1,-ratio, ratio, 1, 100); //可能变形的视角——大视角
gl.glFrustumf( -1, 1,-ratio, ratio, 8f, 100); //不太可能变形的视角——小视角
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//关闭抗抖动
gl.glDisable(GL10.GL_DITHER);
//设置特定Hint项目的模式,这里为设置为使用快速模式
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST);
//设置屏幕背景色黑色RGBA
gl.glClearColor(0,0,0,0);
//启用深度测试
gl.glEnable(GL10.GL_DEPTH_TEST);
}
}
}
package yy.cal;
import javax.microedition.khronos.opengles.GL10;
import static yy.cal.Constant.*;
public class Cube {
//用于绘制各个面的颜色矩形
ColorRect cr=new ColorRect(SCALE,SCALE);
public void drawSelf(GL10 gl)
{
//总绘制思想:通过把一个颜色矩形旋转移位到立方体每个面的位置
//绘制立方体的每个面
gl.glPushMatrix();
//绘制前小面
gl.glPushMatrix();
gl.glTranslatef(0, 0, UNIT_SIZE*SCALE);
cr.drawSelf(gl);
gl.glPopMatrix();
//绘制后小面
gl.glPushMatrix();
gl.glTranslatef(0, 0, -UNIT_SIZE*SCALE);
gl.glRotatef(180, 0, 1, 0);
cr.drawSelf(gl);
gl.glPopMatrix();
//绘制上大面
gl.glPushMatrix();
gl.glTranslatef(0,UNIT_SIZE*SCALE,0);
gl.glRotatef(-90, 1, 0, 0);
cr.drawSelf(gl);
gl.glPopMatrix();
//绘制下大面
gl.glPushMatrix();
gl.glTranslatef(0,-UNIT_SIZE*SCALE,0);
gl.glRotatef(90, 1, 0, 0);
cr.drawSelf(gl);
gl.glPopMatrix();
//绘制左大面
gl.glPushMatrix();
gl.glTranslatef(UNIT_SIZE*SCALE,0,0);
gl.glRotatef(-90, 1, 0, 0);
gl.glRotatef(90, 0, 1, 0);
cr.drawSelf(gl);
gl.glPopMatrix();
//绘制右大面
gl.glPushMatrix();
gl.glTranslatef(-UNIT_SIZE*SCALE,0,0);
gl.glRotatef(90, 1, 0, 0);
gl.glRotatef(-90, 0, 1, 0);
cr.drawSelf(gl);
gl.glPopMatrix();
gl.glPopMatrix();
}
}
package yy.cal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import javax.microedition.khronos.opengles.GL10;
public class ColorRect {
private FloatBuffer mVertexBuffer;//顶点坐标数据缓冲
private IntBuffer mColorBuffer,mColorBuffer1,mColor;//顶点着色数据缓冲
int vCount=0;//顶点数量
static boolean flag=true;
public ColorRect(float width,float height)
{
//顶点坐标数据的初始化================begin============================
vCount=6;
final float UNIT_SIZE=1.0f;
float vertices[]=new float[]
{
0,0,0,
width*UNIT_SIZE,height*UNIT_SIZE,0,
-width*UNIT_SIZE,height*UNIT_SIZE,0,
-width*UNIT_SIZE,-height*UNIT_SIZE,0,
width*UNIT_SIZE,-height*UNIT_SIZE,0,
width*UNIT_SIZE,height*UNIT_SIZE,0
};
//创建顶点坐标数据缓冲
//vertices.length*4是因为一个整数四个字节
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
vbb.order(ByteOrder.nativeOrder());//设置字节顺序
mVertexBuffer = vbb.asFloatBuffer();//转换为Float型缓冲
mVertexBuffer.put(vertices);//向缓冲区中放入顶点坐标数据
mVertexBuffer.position(0);//设置缓冲区起始位置
//特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer
//转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题
//顶点坐标数据的初始化================end============================
//顶点着色数据的初始化================begin============================
final int one = 65535;
int colors[]=new int[]//顶点颜色值数组,每个顶点4个色彩值RGBA
{
one,one,one,0,
0,0,one,0,
0,0,one,0,
0,0,one,0,
0,0,one,0,
0,0,one,0,
};
//创建顶点着色数据缓冲
//vertices.length*4是因为一个int型整数四个字节
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
cbb.order(ByteOrder.nativeOrder());//设置字节顺序
mColorBuffer = cbb.asIntBuffer();//转换为int型缓冲
mColorBuffer.put(colors);//向缓冲区中放入顶点着色数据
mColorBuffer.position(0);//设置缓冲区起始位置
int colors1[]=new int[]
{
0,0,one,0,
0,0,one,0,
0,0,one,0,
one,one,one,0,
0,0,one,0,
0,0,one,0,
};
ByteBuffer cbb1 = ByteBuffer.allocateDirect(colors1.length*4);
cbb1.order(ByteOrder.nativeOrder());
mColorBuffer1 = cbb1.asIntBuffer();//转换为int型缓冲
mColorBuffer1.put(colors1);//向缓冲区中放入顶点着色数据
mColorBuffer1.position(0);//设置缓冲区起始位置
//特别提示:由于不同平台字节顺序不同数据单元不是字节的一定要经过ByteBuffer
//转换,关键是要通过ByteOrder设置nativeOrder(),否则有可能会出问题
//顶点着色数据的初始化================end============================
}
public void drawSelf(GL10 gl)
{
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//启用顶点坐标数组
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//启用顶点颜色数组
//为画笔指定顶点坐标数据
gl.glVertexPointer
(
3, //每个顶点的坐标数量为3 xyz
GL10.GL_FLOAT, //顶点坐标值的类型为 GL_FIXED
0, //连续顶点坐标数据之间的间隔
mVertexBuffer //顶点坐标数据
);
if(flag){
mColor=mColorBuffer;
}else{
mColor=mColorBuffer1;
}
//为画笔指定顶点着色数据
gl.glColorPointer
(
4, //设置颜色的组成成分,必须为4—RGBA
GL10.GL_FIXED, //顶点颜色值的类型为 GL_FIXED
0, //连续顶点着色数据之间的间隔
mColor //顶点着色数据
);
//绘制图形
gl.glDrawArrays
(
GL10.GL_TRIANGLE_FAN, //以三角形方式填充
0, //开始点编号
vCount //顶点的数量
);
}
}
package yy.cal;
public class Constant {
public static final float UNIT_SIZE=1.0f;//单位尺寸
public static final float SCALE=0.5f;//尺寸缩放比
}