1

当用户点击 android 手机的屏幕时,我正在尝试进行 3d 选择。

它有时会起作用,但是当我旋转屏幕时->射线没有击中球体

我将把源代码粘贴到现在为止:

a)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 OnSurfaceChanged 设置:

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]));
    }
}

}

只是不知道我要去哪里错了.. :(请帮助!!

     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
  • 如果我不旋转场景,那我就成功了!
  • 但是..如果我确实旋转场景,那么没有命中:(
4

2 回答 2

0

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

如果 unproject 给出了世界坐标中的点击位置,并且您正在测试世界坐标中的球体位置,我看不出您为什么要通过模型视图来转换 unproject。

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

于 2012-06-02T08:36:45.550 回答
0

从您的代码的初始演练来看,它看起来像是屏幕分辨率更改的问题。当屏幕旋转时,您的代码似乎没有转置宽度和高度。这可能是关闭的,但它作为一个可能的问题脱颖而出。

于 2012-06-04T00:58:19.493 回答