Android 带网格的三维拾取

Android 带网格的三维拾取,android,opengl-es,3d,picking,Android,Opengl Es,3d,Picking,当用户轻触android手机屏幕时,我正在尝试3d拾取 它有时会工作,但当我旋转屏幕-->时,光线不会击中球体 我将使用我目前拥有的源代码粘贴源代码: a) class renderer.java: ... // variables used public static picking gPicker = null; public static vector3 campos = new vector3(0,0, 500); public s

当用户轻触android手机屏幕时,我正在尝试3d拾取

它有时会工作,但当我旋转屏幕-->时,光线不会击中球体

我将使用我目前拥有的源代码粘贴源代码:

a) class renderer.java:

... // variables used
    public static   picking gPicker     = null;   
    public static   vector3 campos      = new vector3(0,0, 500);
    public static   vector3 sphpos      = new vector3(60,-40,0);
...




... // this function is called when user taps Screen 
public void screenWasTapped(vector2 touchcoords) 
{
    // get current time
    now = System.currentTimeMillis();

    // can shoot/tap every 100 msecs., not earlyer.
    if (now > mLastFiredTime + mInterval) 
    {
        // do we have a valid GL context?
        if(gGL!=null)
        {   
            // screen was tapped , so call "pick" function wich will check if ray hits sphere wich is located at "sphpos".
            gPicker.pick(gGL, gScreenWidth, gScreenHeight, touchcoords.x, touchcoords.y);

            // update last time
            mLastFiredTime = now;
        }
    }
}
....
以下是GL OnSurface更改的设置:

public void onSurfaceChanged(GL10 gl, int width, int height) 
{
    // To prevent divide by zero
    if (height == 0) height = 1;   
    float aspect = (float) width/height;

    // Set the viewport (display area) to cover the entire window
    gl.glViewport(0, 0, width, height);

    // Setup perspective projection, with aspect ratio matches viewport
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();                
    // Use perspective projection
    GLU.gluPerspective(gl, 60.0f, aspect, 0.1f, 5000.f);

    gl.glMatrixMode(GL10.GL_MODELVIEW); 
    gl.glLoadIdentity();                

    // Fast Perspective Calculations
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); 
    gl.glEnable(GL10.GL_TEXTURE_2D);


    // Enable GL Blending.
    gl.glEnable(GL10.GL_BLEND);
    gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);

    // Drawing order & culling face settings.
    gl.glFrontFace(GL10.GL_CW);     // Front face in counter-clockwise orientation
    gl.glEnable(GL10.GL_CULL_FACE);     // Enable cull face
    gl.glCullFace(GL10.GL_BACK);        // Cull the back face (don't display)


    gScreenWidth  = width;
    gScreenHeight = height; 
}
…这就是我绘制场景的方式:

public void onDrawFrame(GL10 gl) 
{
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

    gTimer.startupdate();
    float dt = gTimer.getElapsed();

    gl.glLoadIdentity();
    gl.glTranslatef(-campos.x, -campos.y, -campos.z);
    gl.glRotatef(tableRotXAngle, 1, 0, 0); 
    gl.glRotatef(tableRotYAngle, 0, 1, 0f);


        gl.glColor4f(0,1,1,1);
        gl.glPushMatrix();
        gl.glTranslatef(sphpos.x,sphpos.y,sphpos.y); 
            newgame.gPyramid.render(gl);            // draw pyramid at 3d location specified by "sphpos"
        gl.glPopMatrix();
        gl.glColor4f(1,1,1,1);



        doGameAI(dt);
        doDisplayHUD(gl);

    gTimer.stopupdate();
    gl.glFlush();
}
重要注意事项此处:这是一个弧形摄像机旋转,摄像机始终在中心坐标(0,0,0)处旋转,并向后平移500个单位(参见campos初始化)

b) 类“picker.java”:

    public class picking 
    {

   picking(GL10 gl)
   {
    MatrixGrabber mg = new MatrixGrabber();
    mg.getCurrentState(gl);
   }

(UPDATED)
public void pick(GL10 gl, int width, int height, float xTouch, float yTouch) 
{
    MatrixGrabber mg = new MatrixGrabber();
    mg.getCurrentState(gl);

    int[] viewport = {0, 0, width, height};

    float[] nearCoOrds  = new float[3];
    float[] farCoOrds   = new float[3];
    float[] temp        = new float[4];
 // float[] temp2       = new float[4];

    float winx = xTouch, winy =(float)viewport[3] - yTouch;

    displayMatrix(mg.mModelView);
    displayMatrix(mg.mProjection);



    int result = GLU.gluUnProject(winx, winy, 0.0f, mg.mModelView, 0, mg.mProjection, 0, viewport, 0, temp, 0);
    // Matrix.multiplyMV(temp2, 0, mg.mModelView, 0, temp, 0);
    if(result == GL10.GL_TRUE){
        nearCoOrds[0] = temp[0] / temp[3];
        nearCoOrds[1] = temp[1] / temp[3];
        nearCoOrds[2] = temp[2] / temp[3];

    }



    Log.d("redwing", " ---> near pos "  + Float.toString(nearCoOrds[0]) + "," 
                                        + Float.toString(nearCoOrds[1]) + "," 
                                        + Float.toString(nearCoOrds[2]));

    result = GLU.gluUnProject(winx, winy, 1.0f , mg.mModelView, 0, mg.mProjection, 0, viewport, 0, temp, 0);
    // Matrix.multiplyMV(temp2,0, mg.mModelView, 0, temp, 0);
    if(result == GL10.GL_TRUE){
        farCoOrds[0] = temp[0] / temp[3];
        farCoOrds[1] = temp[1] / temp[3];
        farCoOrds[2] = temp[2] / temp[3];
    }

    Log.d("redwing", " ---> far pos "   + Float.toString(farCoOrds[0]) + "," 
                                        + Float.toString(farCoOrds[1]) + "," 
                                        + Float.toString(farCoOrds[2]));



    vector3 rayDirection = new vector3(farCoOrds[0]-nearCoOrds[0], farCoOrds[1]-nearCoOrds[1], farCoOrds[2]-nearCoOrds[2]);

    Log.d("redwing", " ---> raylen ="+ Float.toString(rayDirection.getLength()));

    rayDirection.setUnit();

    Log.d("redwing", " ---> dir "   + Float.toString(rayDirection.x) + "," 
                                    + Float.toString(rayDirection.y) + "," 
                                    + Float.toString(rayDirection.z));



    if(rayHitSphere(renderer.campos, rayDirection, renderer.sphpos, 10))
    {
        Log.e("redwing", "****************");
        Log.e("redwing", "ray hits OBJECT!");
        Log.e("redwing", "****************");
    }


}      


boolean rayHitSphere(vector3 rayPos, vector3 rayDir, vector3 sphereCntr, float radius)
{
      vector3 w = rayPos.sub(sphereCntr);   
      float A = rayDir.dot(rayDir);         
      float B = 2*w.dot(rayDir);            
      float C = w.dot(w) - radius*radius;   

      float D = B*B-4.0f*A*C;

      if(D>=0.0f)
      return true;
      else 
      return false;
    }


void displayMatrix(float[] m, String tag)
{
    for(byte i=0;i<4;i++)
    {
        Log.v("redbase "+tag, "mtx" + Byte.toString(i) + " - "  + new DecimalFormat("#.####").format(m[i*4+0])+","
                                                                + new DecimalFormat("#.####").format(m[i*4+1])+","
                                                                + new DecimalFormat("#.####").format(m[i*4+2])+","
                                                                + new DecimalFormat("#.####").format(m[i*4+3]));
    }
}
公共类选取
{
拣选(GL10 gl)
{
MatrixGrabber mg=新MatrixGrabber();
mg.getCurrentState(德国劳埃德船级社);
}
(更新)
公共空心拾取(GL10 gl、整型宽度、整型高度、浮点X触摸、浮点Y触摸)
{
MatrixGrabber mg=新MatrixGrabber();
mg.getCurrentState(德国劳埃德船级社);
int[]视口={0,0,宽度,高度};
float[]nearCoOrds=新的float[3];
float[]farCoOrds=新的float[3];
浮动[]温度=新浮动[4];
//float[]temp2=新的float[4];
float winx=xTouch,winy=(float)视口[3]-yTouch;
显示矩阵(mg.mModelView);
显示矩阵(mg.m投影);
int result=GLU.glunproject(winx,winy,0.0f,mg.mModelView,0,mg.mProjection,0,viewport,0,temp,0);
//矩阵。多重平均值(temp2,0,mg.mModelView,0,temp,0);
如果(结果==GL10.GL\u真){
nearCoOrds[0]=temp[0]/temp[3];
nearCoOrds[1]=temp[1]/temp[3];
nearCoOrds[2]=临时[2]/临时[3];
}
Log.d(“redwing”,“-->near pos”+Float.toString(nearCoOrds[0])+,”
+Float.toString(nearCoOrds[1])+“,”
+Float.toString(nearCoOrds[2]);
结果=GLU.glunproject(winx,winy,1.0f,mg.mModelView,0,mg.mProjection,0,viewport,0,temp,0);
//矩阵。多重平均值(temp2,0,mg.mModelView,0,temp,0);
如果(结果==GL10.GL\u真){
farCoOrds[0]=temp[0]/temp[3];
farCoOrds[1]=temp[1]/temp[3];
farCoOrds[2]=temp[2]/temp[3];
}
Log.d(“redwing”,“-->far pos”+Float.toString(farCoOrds[0])+”,“
+Float.toString(farCoOrds[1])+“,”
+Float.toString(farCoOrds[2]);
vector3光线方向=新矢量3(farCoOrds[0]-nearCoOrds[0],farCoOrds[1]-nearCoOrds[1],farCoOrds[2]-nearCoOrds[2]);
Log.d(“redwing”,“-->raylen=“+Float.toString(rayDirection.getLength()));
rayDirection.setUnit();
Log.d(“redwing”、“-->dir”+Float.toString(rayDirection.x)+”
+Float.toString(光线方向.y)+“,”
+Float.toString(raydroduction.z));
if(光线球体(renderer.campos、光线方向、renderer.sphpos、10))
{
Log.e(“红翼”,“*************”);
e(“红翼”,“射线击中目标!”);
Log.e(“红翼”,“*************”);
}
}      
布尔光线球体(矢量3光线位置、矢量3光线方向、矢量3球体中心、浮动半径)
{
vector3 w=光线位置sub(sphereCntr);
浮点A=光线方向点(光线方向);
浮动B=2*w.dot(rayDir);
浮点数C=w。点(w)-半径*半径;
浮点数D=B*B-4.0f*A*C;
如果(D>=0.0f)
返回true;
其他的
返回false;
}
void displayMatrix(浮点[]m,字符串标记)
{
对于(字节i=0;位置0.011649653附近的i,-0.0066829454499.9
06-02 12:15:22.661:D/redwing(5524):->far位置581.6618,-333.6764,-4493.4097
06-02 12:15:22.661:D/红翼(5524):-->raylen=5038.134
06-02 12:15:22.661:D/红翼(5524):-->dir 0.115449525,-0.06622883,-0.991103
06-02 12:15:22.661:E/红翼(5524):****************
06-02 12:15:22.661:E/红翼(5524):射线击中目标!
06-02 12:15:22.661:E/红翼(5524):****************
06-02 12:15:30.671:D/redwing(5524):屏幕分辨率480x764
06-02 12:15:30.671:D/红翼(5524):分接坐标(337.04843440.11392
06-02 12:15:30.671:V/redbase(5524):mtx0-0.9684,0.1802,0.1725,0
06-02 12:15:30.671:V/redbase(5524):mtx1-0,0.6913,-0.7226,0
06-02 12:15:30.681:V/redbase(5524):mtx2--0.2495,0.6997,0.6695,0
06-02 12:15:30.681:V/redbase(5524):mtx3-0,0,-500,1
06-02 12:15:30.681:V/redbase(5524):mtx0-2.7568,0,0,0
06-02 12:15:30.681:V/redbase(5524):mtx1-0,1.7321,0,0
06-02 12:15:30.681:V/redbase(5524):mtx2-0,0,-1,-1
06-02 12:15:30.681:V/redbase(5524):mtx3-0,0,-0.2,0
06-02 12:15:30.681:D/红翼(5524):-->86.22043,-361.2092334.655号位置附近
06-02 12:15:30.691:D/红翼(5524):-->far位置-144.609532943.3904,-3498.0571
06-02 12:15:30.691:D/红翼(5524):-->raylen=5065.9
06-02 12:15:30.691:D/redwing(5524):-->dir-0.04556544,0.65232235,-0.7565708
  • 如果我不旋转场景,那么我就成功了
  • 但是…如果我旋转场景,那么就没有点击:(

    • 不是100%肯定我理解所有代码,但在我看来,您不应该将gluUnproject的结果与modelview矩阵相乘

      如果unproject在世界坐标中给出了单击位置,并且您正在世界坐标中对球体位置进行测试,我不明白您为什么要通过modelview转换unproject


      如果您确实想将点击转换为相机空间,那么您的球体位置也需要进行转换,我看这还没有完成。

      从最初的代码浏览来看,这似乎是一个屏幕分辨率改变的问题。当屏幕旋转时,您的代码似乎没有转换宽度和高度。这可以d是关闭的,但这是一个可能的问题。

      ok,然后执行两个步骤:1)使用modelview mtx转换球体位置,2)删除矩阵。multipleYMV(temp2,0,mg.mModelView,0,tem
           Here are some values from Eclipse console when User tapped screen:
           (UPDATED - i get a Hit!)
          <<< NOT ROTATED SCENE >>
          06-02 12:15:22.611: D/redwing(5524): screen resolution 480x764
          06-02 12:15:22.611: D/redwing(5524): tapped coordinate ( 317.07507,426.2164
          06-02 12:15:22.621: V/redbase(5524): mtx0 - 1,0,0,0
          06-02 12:15:22.631: V/redbase(5524): mtx1 - 0,1,0,0
          06-02 12:15:22.631: V/redbase(5524): mtx2 - 0,0,1,0
          06-02 12:15:22.631: V/redbase(5524): mtx3 - 0,0,-500,1
          06-02 12:15:22.641: V/redbase(5524): mtx0 - 2.7568,0,0,0
          06-02 12:15:22.641: V/redbase(5524): mtx1 - 0,1.7321,0,0
          06-02 12:15:22.641: V/redbase(5524): mtx2 - 0,0,-1,-1
          06-02 12:15:22.651: V/redbase(5524): mtx3 - 0,0,-0.2,0
          06-02 12:15:22.651: D/redwing(5524):  ---> near pos 0.011649653,-0.0066829454,499.9
          06-02 12:15:22.661: D/redwing(5524):  ---> far pos 581.6618,-333.6764,-4493.4097
          06-02 12:15:22.661: D/redwing(5524):  ---> raylen =5038.134
          06-02 12:15:22.661: D/redwing(5524):  ---> dir 0.115449525,-0.06622883,-0.991103
          06-02 12:15:22.661: E/redwing(5524): ****************
          06-02 12:15:22.661: E/redwing(5524): ray hits OBJECT!
          06-02 12:15:22.661: E/redwing(5524): ****************
      
      
          <<< ROTATED SCENE!!  UPDATED - Still NO HIT!  >>
          06-02 12:15:30.671: D/redwing(5524): screen resolution 480x764
          06-02 12:15:30.671: D/redwing(5524): tapped coordinate ( 337.04843,440.11392
          06-02 12:15:30.671: V/redbase(5524): mtx0 - 0.9684,0.1802,0.1725,0
          06-02 12:15:30.671: V/redbase(5524): mtx1 - 0,0.6913,-0.7226,0
          06-02 12:15:30.681: V/redbase(5524): mtx2 - -0.2495,0.6997,0.6695,0
          06-02 12:15:30.681: V/redbase(5524): mtx3 - 0,0,-500,1
          06-02 12:15:30.681: V/redbase(5524): mtx0 - 2.7568,0,0,0
          06-02 12:15:30.681: V/redbase(5524): mtx1 - 0,1.7321,0,0
          06-02 12:15:30.681: V/redbase(5524): mtx2 - 0,0,-1,-1
          06-02 12:15:30.681: V/redbase(5524): mtx3 - 0,0,-0.2,0
          06-02 12:15:30.681: D/redwing(5524):  ---> near pos 86.22043,-361.2092,334.655
          06-02 12:15:30.691: D/redwing(5524):  ---> far pos -144.60953,2943.3904,-3498.0571
          06-02 12:15:30.691: D/redwing(5524):  ---> raylen =5065.9
          06-02 12:15:30.691: D/redwing(5524):  ---> dir -0.04556544,0.65232235,-0.7565708