先还是大体说一下这个程序的原理吧(正方体与球体之间)。
(1)建立相关对象:正方体,3个球体以及为它们铺上纹理
(2)分别为每个对象设定碰撞模式,方法为setCollisionMode(int mode),3个球体为COLLISION_CHECK_OTHERS,cube为COLLISION_CHECK_SELF
(3)将其添加到world对象中,及处理必要的Camera参数
(4)在onDrawFrame函数中进行碰撞处理工作,因为是球体与正方体之间的碰撞,所以采用了相近的椭圆碰撞检测checkForCollisionEllipsoid(如果要用球体检测checkForCollisionSpherical,也能很好工作,这在代码处有相应注释)
下面附上源代码
(1)Activity类
package sim.feel; import android.app.Activity; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLSurfaceView; import android.os.Bundle; /** * Activity类 * * @author Administrator * */ public class Basic_collision extends Activity { private GLSurfaceView glView; private MyRenderer mr = new MyRenderer(); // onCreate public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 传入Resources方法 LoadBitmap.loadb(getResources()); glView = new GLSurfaceView(this); glView.setRenderer(mr); setContentView(glView); } } // 载入位图文件 class LoadBitmap { public static Bitmap bitmap; // 载入位图方法 public static void loadb(Resources res) { bitmap = BitmapFactory.decodeResource(res, R.drawable.icon); } }
(2)MyRenderer类
package sim.feel; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLSurfaceView.Renderer; import com.threed.jpct.Camera; import com.threed.jpct.Config; import com.threed.jpct.FrameBuffer; import com.threed.jpct.Logger; import com.threed.jpct.Object3D; import com.threed.jpct.Primitives; import com.threed.jpct.RGBColor; import com.threed.jpct.SimpleVector; import com.threed.jpct.Texture; import com.threed.jpct.TextureManager; import com.threed.jpct.World; import com.threed.jpct.util.MemoryHelper; /** * MyRenderer类 * * @author Administrator * */ public class MyRenderer implements Renderer { // FrameBuffer对象 private FrameBuffer fb; // World对象 private World world; // RGBColor private RGBColor back = new RGBColor(50, 50, 100); // Object3D对象 private Object3D sphere1 = null; private Object3D sphere2 = null; private Object3D sphere3 = null; private Object3D cube = null; // SimpleVector // 通过设置组件的x,y,z向量来创建一个SimpleVector对象 private SimpleVector move = new SimpleVector(0, 0.3, 1); // 被碰撞Object3D的x,y,z(此处该对象为球体) private SimpleVector ellips = new SimpleVector(7, 7, 7); private SimpleVector tmp = new SimpleVector(); // FPS private int fps = 0; private long time = System.currentTimeMillis(); private boolean stop = false; // 默认构造 // 对该项目的一些优化 public MyRenderer() { // 绘制的最多的Polygon数量,默认为4096,此处如果超过500,则不绘制 Config.maxPolysVisible = 500; // 最远的合适的平面,默认为1000 Config.farPlane = 1500; // Modifies the multiplicator for the transparency calculations in // jPCT-AE. The actual formula is trans=offset+objTrans*mul, default for // offset is 0.1f. Config.glTransparencyMul = 0.1f; // Modifies the offset for the transparency calculations in jPCT-AE. The // actual formula is trans=offset+objTrans*mul, default for offset is // 0.1f. Config.glTransparencyOffset = 0.1f; // 使JPCT-AE这个引擎使用顶点而不是顶点数组缓冲对象,因为它可能会使某些硬件更快 // 但在Samsung Galaxy,它并不能工作的很好,可能使之崩溃,这就是它默认为false的原因 Config.useVBO = true; Texture.defaultToMipmapping(true); Texture.defaultTo4bpp(true); } public void onDrawFrame(GL10 gl) { try { if (!stop) { // Do collision detections(碰撞检测) // 第1个参数为cube的移动(translation) // 第2个参数为碰撞的区域大小(ellips) // 此处的第3个参数为:递归深度的碰撞检测,较高的值将提高碰撞检测精度,而且降低性能。合理的值介于1和5。 // trsn包含当前的坐标信息 SimpleVector trsn = cube.checkForCollisionEllipsoid(move, ellips, 5); // 用下面的球体间碰撞也能很好的工作 // SimpleVector trsn = cube.checkForCollisionSpherical(move, 2); // "移动这个对象通过改变其在JPCT-AE坐标系下的矩阵" cube.translate(trsn); // 如果cube当前z轴坐标大于 // 100,重置当前cube的旋转值到默认值,换言之,没有了旋转 if (cube.getTranslation(tmp).z > 50) { // 清除旋转 cube.clearTranslation(); // 重置为初始值 cube.translate(10, -40, -30); } // 以定义好的RGBColor清屏 fb.clear(back); // 变换和灯光所有的多边形 world.renderScene(fb); // 绘制由renderScene产生的场景 world.draw(fb); // 渲染显示图像 fb.display(); // fps加1 fps++; // 打印输出fps if (System.currentTimeMillis() - time > 1000) { System.out.println(fps + "fps"); fps = 0; time = System.currentTimeMillis(); } } else { if (fb != null) { fb.dispose(); fb = null; } } } catch (Exception e) { e.printStackTrace(); // 打印异常信息 Logger.log("Drawing thread terminated!", Logger.MESSAGE); } } public void onSurfaceChanged(GL10 gl, int width, int height) { if (fb != null) { fb = null; } // 新产生一个FrameBuffer对象 fb = new FrameBuffer(gl, width, height); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { Logger.log("onCreate"); // 混合渲染 gl.glEnable(GL10.GL_BLEND); gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA); // 新建world对象 world = new World(); // 纹理相关 TextureManager tm = TextureManager.getInstance(); Texture texture2 = new Texture(LoadBitmap.bitmap); tm.addTexture("texture2", texture2); // 初始化各3D元素 // 返回一个给定数量的面,第一个20表示面的数量,第二是球体的缩放 sphere1 = Primitives.getSphere(20, 20); // 以纹理对象的方式给对象包装上纹理 sphere1.calcTextureWrapSpherical(); // 为sphere1设置纹理图片 sphere1.setTexture("texture2"); // 复制当前的Object3D对象 sphere2 = sphere1.cloneObject(); sphere3 = sphere1.cloneObject(); // 返回一个立方体,其中2为其缩放变量 cube = Primitives.getCube(2); // 以Z轴20处来旋转球体(其实就是向里移动球体) sphere2.translate(0, 0, 20); // 以Z轴40处来旋转球体 sphere3.translate(0, 0, 40); // 以(10, -40, -30)来旋转立方体 cube.translate(10, -40, -30); cube.setAdditionalColor(RGBColor.GREEN); // 将3D元素添加到world对象中 world.addObject(sphere1); world.addObject(sphere2); world.addObject(sphere3); world.addObject(cube); // 建立碰撞模式 sphere1.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS); world.addObject(sphere1); sphere2.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS); world.addObject(sphere1); sphere3.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS); world.addObject(sphere1); // 建立碰撞模式 cube.setCollisionMode(Object3D.COLLISION_CHECK_SELF); // 设置环境光 world.setAmbientLight(255, 255, 255); // 编译所有对象 world.buildAllObjects(); // Camera相关 Camera cam = world.getCamera(); // 向里以50的速度移动 cam.moveCamera(Camera.CAMERA_MOVEOUT, 50); // 向外以60的速度移动 cam.moveCamera(Camera.CAMERA_MOVEUP, 60); // 以sphere2对象作为中心视角 cam.lookAt(sphere2.getTransformedCenter()); // 回收内存 MemoryHelper.compact(); } }
运行效果如下图所示: