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