现在我们已经创建了一个多纹理的立方体,但是如何判断当前点击的是哪个面呢?下面我们来看看JPCT-AE拾取。
在JPCT-AE的Wiki中已存在了对拾取的介绍:http://www.jpct.net/wiki/index.php/Picking。在Wiki中介绍了两种拾取方式,但是在Android中只支持第二中方式。原文如下:
The compatible way
This works with all renderers and all objects, but depending on the scene it might by a bit slower. It's the only one that is available in jPCT-AE. Unlike the former approach, this is actually a kind of collision detection, which is why it triggers collision events too. Just like above, you have to make your objects pickable. However, because it's a collision detection, this works different. Instead of using setSelectable(...), you have to use setCollisionMode(...). For example:
obj.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
Like above, you need your 2D picking coordinates. With them, you need a direction vector in world space. This is simple:
SimpleVector dir=Interact2D.reproject2D3DWS(camera, frameBuffer, x, y).normalize();
Armed with this vector, you can now go to World and do
Object[] res=world.calcMinDistanceAndObject3D(camera.getPosition(), dir, 10000 /*or whatever*/);
The result is an Object[]-array with the Float-distance to the picked object in the first slot and the picked Object3D in the second. If nothing has been hit, the result will be [COLLISION_NONE, null].
现在通过修改我们之前的代码,来判断当前点击的立方体面。private void CreateBox() {
cube = new Object3D(0);
// 前
yi = new Object3D(2);
yi.addTriangle(GetPoint(-30, -30, 30), 0.0f, 0.0f,
GetPoint(30, -30, 30), 1.0f, 0.0f, GetPoint(-30, 30, 30), 0.0f,
1.0f, TextureManager.getInstance().getTextureID("yi"));
yi.addTriangle(GetPoint(30, -30, 30), 1.0f, 0.0f,
GetPoint(30, 30, 30), 1.0f, 1.0f, GetPoint(-30, 30, 30), 0.0f,
1.0f, TextureManager.getInstance().getTextureID("yi"));
cube.addChild(yi);
world.addObject(yi);
yi.setCollisionMode( Object3D.COLLISION_CHECK_OTHERS);
// 上
shi = new Object3D(2);
shi.addTriangle(GetPoint(-30, 30, 30), 0.0f, 0.0f,
GetPoint(30, 30, 30), 1.0f, 0.0f, GetPoint(-30, 30, -30), 0.0f,
1.0f, TextureManager.getInstance().getTextureID("shi"));
shi.addTriangle(GetPoint(30, 30, 30), 1.0f, 0.0f,
GetPoint(30, 30, -30), 1.0f, 1.0f, GetPoint(-30, 30, -30),
0.0f, 1.0f, TextureManager.getInstance().getTextureID("shi"));
cube.addChild(shi);
world.addObject(shi);
shi.setCollisionMode( Object3D.COLLISION_CHECK_OTHERS);
// 后
zhu = new Object3D(2);
zhu.addTriangle(GetPoint( -30, 30, -30), 0.0f, 0.0f,
GetPoint(30, 30, -30), 1.0f, 0.0f, GetPoint(-30, -30, -30),
0.0f, 1.0f, TextureManager.getInstance().getTextureID("zhu"));
zhu.addTriangle(GetPoint(30, 30, -30), 1.0f, 0.0f,
GetPoint(30, -30, -30), 1.0f, 1.0f, GetPoint(-30, -30, -30),
0.0f, 1.0f, TextureManager.getInstance().getTextureID("zhu"));
cube.addChild(zhu);
world.addObject(zhu);
zhu.setCollisionMode( Object3D.COLLISION_CHECK_OTHERS);
// 下
xing = new Object3D(2);
xing.addTriangle(GetPoint(-30, -30, -30), 0.0f, 0.0f,
GetPoint(30, -30, -30), 1.0f, 0.0f, GetPoint(-30, -30, 30),
0.0f, 1.0f, TextureManager.getInstance().getTextureID("xing"));
xing.addTriangle(GetPoint(30, -30, -30), 1.0f, 0.0f,
GetPoint(30, -30, 30), 1.0f, 1.0f, GetPoint( -30, -30, 30), 0.0f,
1.0f, TextureManager.getInstance().getTextureID("xing"));
cube.addChild(xing);
world.addObject(xing);
xing.setCollisionMode( Object3D.COLLISION_CHECK_OTHERS);
// 左
wan = new Object3D(2);
wan.addTriangle(GetPoint( -30, -30, -30), 0.0f, 0.0f,
GetPoint(-30, -30, 30), 1.0f, 0.0f, GetPoint(-30, 30, -30),
0.0f, 1.0f, TextureManager.getInstance().getTextureID("wan"));
wan.addTriangle(GetPoint( -30, -30, 30), 1.0f, 0.0f,
GetPoint(-30, 30, 30), 1.0f, 1.0f, GetPoint(-30, 30, -30),
0.0f, 1.0f, TextureManager.getInstance().getTextureID("wan"));
cube.addChild(wan);
world.addObject(wan);
wan.setCollisionMode( Object3D.COLLISION_CHECK_OTHERS);
// 右
wen = new Object3D(2);
wen.addTriangle(GetPoint(30, -30, 30), 0.0f, 0.0f,
GetPoint(30, -30, -30), 1.0f, 0.0f, GetPoint(30, 30, 30), 0.0f,
1.0f, TextureManager.getInstance().getTextureID("wen"));
wen.addTriangle(GetPoint(30, -30, -30), 1.0f, 0.0f,
GetPoint(30, 30, -30), 1.0f, 1.0f, GetPoint(30, 30, 30), 0.0f,
1.0f, TextureManager.getInstance().getTextureID("wen"));
cube.addChild(wen);
world.addObject(wen);
wen.setCollisionMode( Object3D.COLLISION_CHECK_OTHERS);
cube.strip();
cube.build();
world.addObject(cube);
cube.setCulling(false);
cube.scale( 0.4f);
cube.rotateZ( 180);
cube.setCollisionMode( Object3D.COLLISION_CHECK_OTHERS);
在CBoxRander中添加如下方法:
public int Pickint( int fX, int fY){
//fY = fb.getHeight() - fY;
SimpleVector dir = Interact2D.reproject2D3DWS( cam, fb, fX, fY).normalize();
Object[] res=world.calcMinDistanceAndObject3D(cam.getPosition(), dir, 10000 );
Object3D picked = (Object3D)res[1];
if( picked == null)
return -1;
if( picked.getID() == yi.getID())
return 1;
else if( picked.getID() == shi.getID())
return 2;
else if( picked.getID() == zhu.getID())
return 3;
else if( picked.getID() == xing.getID())
return 4;
else if( picked.getID() == wan.getID())
return 5;
else if( picked.getID() == wen.getID())
return 6;
return -1;
}
world.calcMinDistanceAndObject3D()返回的是一个包含两个元素的数组,res[0]为起点到焦点的距离,res[1]为当前被拾取的Object3D对象。当射线未与任何物体相交时,res[0]=COLLISION_NONE,res[1]=null.
在BoxView::onTouchEvent中添加如下代码
int a = mRander.Pickint( (int)me.getX(), (int)me.getY());
a就是我们选择的面的序列了。