1
我使用min3d和我在網上發現的一些代碼實現了射線採集,但是當我實現它時,我注意到它的某些時候意味着當我點擊一個盒子時有時出錯一個被挑選。有時候,挑選的人甚至不在屏幕上。這花了相當多的代碼,以在第一時間得到實現,但是主要的兩種方法我稱之爲有以下幾種:Android上的OpenGl ES對射線採集代碼進行微調
private void rayPicking(float x, float y)
{
//intersection with near plane
float[] near = new float[4];
GLU.gluUnProject(x, scene.getViewport()[3] - y, 0f, scene.getGrabber().mModelView, 0, scene.getGrabber().mProjection, 0, scene.getViewport(), 0, near, 0);
if (near[3] != 0)
{
near[0] = near[0]/near[3];
near[1] = near[1]/near[3];
near[2] = near[2]/near[3];
}
Number3d near3 = new Number3d(near[0], near[1], near[2]);
//and far plane
float[] far = new float[4];
GLU.gluUnProject(x, scene.getViewport()[3] - y, 1f, scene.getGrabber().mModelView, 0, scene.getGrabber().mProjection, 0, scene.getViewport(), 0, far, 0);
if (far[3] != 0)
{
far[0] = far[0]/far[3];
far[1] = far[1]/far[3];
far[2] = far[2]/far[3];
}
Number3d far3 = new Number3d(far[0], far[1], far[2]);
Box firstPicked = null;
Box currentModel = null;
Number3d currentCoords = null;
Number3d firstPickedCoords = new Number3d();
if (!sceneBoxes.isEmpty())
{
//here we check each model if it was tapped and if several models were tapped, we take only that which is closer to the near clipping plane
Iterator<Box> itr = sceneBoxes.iterator();
while (itr.hasNext())
{
currentModel = itr.next();
currentCoords = new Number3d(currentModel.position().x, currentModel.position().y, currentModel.position().z);
if (picked (far3, near3, currentCoords, 1.2f))
if (firstPicked==null)
{
firstPicked = currentModel;
firstPickedCoords.setAllFrom(currentCoords);
}
else if (Number3d.add(currentCoords, near3).length() < Number3d.add(firstPickedCoords, near3).length())
{
firstPicked = currentModel;
firstPickedCoords.setAllFrom(currentCoords);
}
}
}
if (firstPicked != null) // if model picked
{
String temp = firstPicked.getTitle();
String temp2 = firstPicked.getLink();
Log.w("3d touch working "+temp, "3d touch working "+temp);
Intent intent = new Intent(CurAct.this, WebViewer.class);
intent.putExtra("clkURL", temp2);
intent.putExtra("clkUID", curr_uid);
intent.putExtra("rid", curr_rid);
startActivity(intent);
firstPicked = null;
temp = null;
temp2 = null;
}
}
private boolean picked(Number3d a, Number3d b, Number3d q, float r)
{
float ab = (float) Math.sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
float aq = (float) Math.sqrt((a.x-q.x)*(a.x-q.x)+(a.y-q.y)*(a.y-q.y)+(a.z-q.z)*(a.z-q.z));
float bq = (float) Math.sqrt((b.x-q.x)*(b.x-q.x)+(b.y-q.y)*(b.y-q.y)+(b.z-q.z)*(b.z-q.z));
float p = (ab + aq + bq)/2;
float hh = (float) Math.sqrt(p * (p - ab) * (p - aq) * (p - bq));
float h;
if (ab!=0) h = 2 * hh/ab; else h = 2*hh;
if (aq<h) h = aq;
if (bq<h) h = bq;
if (h<r)return true; else return false;
}
現在我也曾嘗試推行域剔除,但已經做了,它減緩事情一路下滑,因爲我沒有做太多的工作來優化它,它本身並沒有運行。但是如果有人能夠看,並且可以給我一些關於如何使它更準確的指示,那將是非常棒的。在這裏我稱之爲採摘方法。
_glSurfaceView.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent e) {
switch (e.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
startX = e.getX();
startY = e.getY();
trace = 0.0f;
time = System.currentTimeMillis();
touchMode = DRAG;
break;
case MotionEvent.ACTION_UP:
// we use ray picking only when the tap wasn't longer than 0.5 sec and if we almost didn't move our finger
//Log.w("this is touch y"+e.getY()+" viewport is"+scene.getViewport()[3], "this is touch x"+e.getX());
if ((System.currentTimeMillis()-time < 500) && (trace<scene.getViewport()[3]*0.075)) rayPicking(e.getX(), e.getY());
time = 0;
case MotionEvent.ACTION_POINTER_UP:
touchMode = NONE;
break;
}
return true;
}
}
);
我不記得目前如何,但我能夠糾正我所遇到的關於我的射線拾取準確性的問題。從我記得我從某處我應該加入的地方減去,反之亦然,它把所有東西都扔掉了。當我有機會看到我的代碼並回復你。 – 2012-04-26 19:48:04
我確認http://android-raypick.blogspot.ca/的代碼正在工作,我在我的應用程序中使用它。所有的計算都是正確的,但內存分配是巨大的。您可能需要重新設計代碼,以便不分配千字節的內存來檢查光線與900個三角形的交點。 – keaukraine 2012-09-21 06:37:46
@keaukraine:我不能讓它工作,在這裏發佈了一個問題http://stackoverflow.com/questions/14185279/ray-picking-in-opengl-es-2-0,希望你能看看看看我是否在正確的軌道上。 – Araw 2013-01-12 12:40:15