2011-07-14 88 views
6

我在Android OpenGL-ES 2.0上,並且經過了所有的限制後,我無法弄清楚如何將2D屏幕觸摸帶到我擁有的3D點。我無法得到正確的結果。Android OpenGL 3D採摘

我正在嘗試將射線射入點雲,然後我可以將我的點距離與射線進行比較,找到最接近的點。

public class OpenGLRenderer extends Activity implements GLSurfaceView.Renderer { 
    public PointCloud ptCloud; 
    MatrixGrabber mg = new MatrixGrabber(); 
... 
    public void onDrawFrame(GL10 gl) { 

     gl.glDisable(GL10.GL_COLOR_MATERIAL); 
     gl.glDisable(GL10.GL_BLEND); 
     gl.glDisable(GL10.GL_LIGHTING); 

     //Background drawing 
     if(customBackground) 
      gl.glClearColor(backgroundRed, backgroundGreen, backgroundBlue, 1.0f); 
     else 
      gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 

     if (PointCloud.doneParsing == true) { 
      if (envDone == false) 
       setupEnvironment(); 

      // Clears the screen and depth buffer. 
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 

      gl.glMatrixMode(GL10.GL_PROJECTION); 
      gl.glLoadIdentity(); 
      GLU.gluPerspective(gl, 55.0f, (float) screenWidth/(float) screenHeight, 10.0f ,10000.0f); 

      gl.glMatrixMode(GL10.GL_MODELVIEW); 

      gl.glLoadIdentity(); 
      GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, 
           centerX, centerY, centerZ, 
           upX, upY, upZ); 

      if(pickPointTrigger) 
       pickPoint(gl); 


      gl.glPushMatrix(); 

      gl.glTranslatef(_xTranslate, _yTranslate, _zTranslate); 
      gl.glTranslatef(centerX, centerY, centerZ); 
      gl.glRotatef(_xAngle, 1f, 0f, 0f); 
      gl.glRotatef(_yAngle, 0f, 1f, 0f); 
      gl.glRotatef(_zAngle, 0f, 0f, 1f); 
      gl.glTranslatef(-centerX, -centerY, -centerZ); 

      ptCloud.draw(gl); 

      gl.glPopMatrix(); 
     } 
    } 
} 

這是我的揀選功能。我已經設置的位置在屏幕中間只用於調試目的:

public void pickPoint(GL10 gl){ 

     mg.getCurrentState(gl); 

     double mvmatrix[] = new double[16]; 
     double projmatrix[] = new double[16]; 
     int viewport[] = {0,0,screenWidth, screenHeight}; 

     for(int i=0 ; i<16; i++){ 
      mvmatrix[i] = mg.mModelView[i]; 
      projmatrix[i] = mg.mProjection[i]; 
     } 

     mg.getCurrentState(gl); 

     float realY = ((float) (screenHeight) - pickY); 
     float nearCoords[] = { 0.0f, 0.0f, 0.0f, 0.0f }; 
     float farCoords[] = { 0.0f, 0.0f, 0.0f, 0.0f }; 


     GLU.gluUnProject(screenWidth/2, screenHeight/2, 0.0f, mg.mModelView, 0, mg.mProjection, 0, 
        viewport, 0, nearCoords, 0); 
     GLU.gluUnProject(screenWidth/2, screenHeight/2, 1.0f, mg.mModelView, 0, mg.mProjection, 0, 
        viewport, 0, farCoords, 0); 

     System.out.println("Near: " + nearCoords[0] + "," + nearCoords[1] + "," + nearCoords[2]); 
     System.out.println("Far: " + farCoords[0] + "," + farCoords[1] + "," + farCoords[2]); 



     //Plot the points in the scene 
     nearMarker.set(nearCoords); 
     farMarker.set(farCoords); 
     markerOn = true; 

     double diffX = nearCoords[0] - farCoords[0]; 
     double diffY = nearCoords[1] - farCoords[1]; 
     double diffZ = nearCoords[2] - farCoords[2]; 

     double rayLength = Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2) + Math.pow(diffZ, 2)); 
     System.out.println("rayLength: " + rayLength); 

     pickPointTrigger = false; 
    } 

改變persepctive zNear和遠沒有預期的結果,一個1.0-1000.0觀點的遠點怎麼可能11個單位?

GLU.gluPerspective(gl, 55.0f, (float) screenWidth/(float) screenHeight, 1.0f ,100.0f); 
..... 
07-18 11:23:50.430: INFO/System.out(31795): Near: 57.574852,-88.60514,37.272636 
07-18 11:23:50.430: INFO/System.out(31795): Far: 0.57574844,0.098602295,0.2700405 
07-18 11:23:50.430: INFO/System.out(31795): rayLength: 111.74275719790872 

GLU.gluPerspective(gl, 55.0f, (float) width/(float) height, 10.0f , 1000.0f); 
... 
07-18 11:25:12.420: INFO/System.out(31847): Near: 5.7575016,-7.965394,3.6339219 
07-18 11:25:12.420: INFO/System.out(31847): Far: 0.057574987,0.90500546,-0.06634784 
07-18 11:25:12.420: INFO/System.out(31847): rayLength: 11.174307289026638 

尋找任何建議或希望在我的代碼中看到的錯誤。非常感激。我儘可能多地賞金(這一直是個問題)。

回答

9

我也在處理這個問題 - 這是一個非常惱人的問題。我有兩個潛在的線索:1.不知何故,最終的z取決於相機的位置,而不是你期望的。當攝像機z爲0時,不管winZ是什麼,結果z都是-1。到目前爲止,我一直在研究生成的z,所以我沒有在其他座標上有任何確切的數字,但是現在我混淆了我的代碼和代碼,並且發現報告光線長度越大,相機從(0,0,0)處獲得的距離越遠。在(0,0,0)時,光線長度被報告爲0.一個小時前,我收集了一堆點(cameraZ,winZ,resultZ)並將它們插入到Mathematica中。結果似乎表明了雙曲線的東西;其中一個變量固定,另一個則導致結果z線性變化,變化率取決於固定變量。

我的第二個領導是從http://www.gamedev.net/topic/420427-gluunproject-question/;箭魚引述式:

WinZ =(1.0F/fNear-1.0F/fDistance)/(1.0F/fNear-1.0F/FFAR)

現在,這似乎並不與匹配我收集的數據,但它可能值得一看。我想我會看看我能否弄清楚這個東西的數學運算,並找出錯誤的原因。讓我知道如果你想出任何東西。哦也,這裏是安裝在我收集的數據公式:

-0.11072114015496763 - 10.000231721597817 X - 0.0003149873867479971 x^2 - 0.8633277851535017 Y + 9.990256062051143 x y + 8.767260632968973 *^- 9Ÿ^ 2

Wolfram Alpha的繪製它像這樣: http://www.wolframalpha.com/input/?i=Plot3D[-0.11072114015496763%60+-+10.000231721597817%60+x+-++++0.0003149873867479971%60+x^2+-+0.8633277851535017%60+y+%2B++++9.990256062051143%60+x+y+%2B+8.767260632968973%60*^-9+y^2+%2C+{x%2C+-15%2C++++15}%2C+{y%2C+0%2C+1}]


AHA!成功!據我所知,gluUnProject只是簡單的破碎。或者,沒有人理解如何使用它。無論如何,我做了一個功能,正確地取消了gluProject功能,看起來真的是他們用來以某種方式畫到屏幕上!代碼如下:

public float[] unproject(float rx, float ry, float rz) {//TODO Factor in projection matrix 
    float[] modelInv = new float[16]; 
    if (!android.opengl.Matrix.invertM(modelInv, 0, mg.mModelView, 0)) 
     throw new IllegalArgumentException("ModelView is not invertible."); 
    float[] projInv = new float[16]; 
    if (!android.opengl.Matrix.invertM(projInv, 0, mg.mProjection, 0)) 
     throw new IllegalArgumentException("Projection is not invertible."); 
    float[] combo = new float[16]; 
    android.opengl.Matrix.multiplyMM(combo, 0, modelInv, 0, projInv, 0); 
    float[] result = new float[4]; 
    float vx = viewport[0]; 
    float vy = viewport[1]; 
    float vw = viewport[2]; 
    float vh = viewport[3]; 
    float[] rhsVec = {((2*(rx-vx))/vw)-1,((2*(ry-vy))/vh)-1,2*rz-1,1}; 
    android.opengl.Matrix.multiplyMV(result, 0, combo, 0, rhsVec, 0); 
    float d = 1/result[3]; 
    float[] endResult = {result[0] * d, result[1] * d, result[2] * d}; 
    return endResult; 
} 

public float distanceToDepth(float distance) { 
    return ((1/fNear) - (1/distance))/((1/fNear) - (1/fFar)); 
} 

它目前假定以下全局變量: 毫克 - 與當前矩陣 視口中的MatrixGrabber - 浮子[4]與視({X,Y,寬度,高度})

它需要的變量與gluUnProject應該採用的變量相同。例如:

float[] xyz = {0, 0, 0}; 
xyz = unproject(mouseX, viewport[3] - mouseY, 1); 

這將返回遠端平面上鼠標下的點。我還添加了一個函數來轉換指定距離的相機和它的0-1 ...表示...的東西。像這樣:

unproject(mouseX, viewport[3] - mouseY, distanceToDepth(5)); 

這將返回鼠標在相機下5點的單位。 我用問題中給出的方法測試了這個 - 我檢查了近平面和遠平面之間的距離。當f近似爲0.1,fFar爲100時,距離應該是99.9。據我所知,無論攝像頭的位置或方向如何,我都一直得到大約99.8977。哈哈,很高興有這個想法。讓我知道,如果你/沒有任何問題,或者如果你想讓我重寫它而不是使用全局變量的輸入。希望這可以幫助一些人;在認真解決這個問題之前,我一直在想這個問題。


嘿,所以,已經想通了它是如何應該是,我已經想通了什麼,他們在實施gluUnProject錯過。他們忘記了(意圖不要和不告訴任何人?)除以所得矢量的第四個元素,這有助於使矢量正常化或類似的東西。 gluProject在應用矩陣之前將其設置爲1,因此在完成撤消操作後它需要爲1。長話短說,你可以實際使用gluUnProject,但你需要傳遞一個浮動[4],然後在第四次一個把所有得到的座標,就像這樣:

float[] xyzw = {0, 0, 0, 0}; 
android.opengl.GLU.gluUnProject(rx, ry, rz, mg.mModelView, 0, mg.mProjection, 0, this.viewport, 0, xyzw, 0); 
xyzw[0] /= xyzw[3]; 
xyzw[1] /= xyzw[3]; 
xyzw[2] /= xyzw[3]; 
//xyzw[3] /= xyzw[3]; 
xyzw[3] = 1; 
return xyzw; 

XYZW現在應該包含有關空間座標。這似乎與我拼湊在一起的完全一樣。它可能會更快一點;我認爲他們結合了其中一個步驟。

+0

我已經取得了一些進展。我可以得到** nearCoords **,並從** farCoords **的**方向**(我只是按照Z_FAR的大小)進行迭代,並且該射線與我實際選擇的距離稍微接近。看看這是如何爲你工作的。 – RedLeader

+0

我還沒有嘗試在nearCoords的方向上進行迭代,但是 - 部分原因在於,對於我來說,nearCoords和farCoords都沒有與我首先點擊的位置有很大關係。我注意到gluUnProject似乎不能工作(以一種新的方式) - 我通過gluProject運行了一些座標,然後將結果立即通過gluUnProject運行,並得到了完全不同的結果。我目前正在嘗試進行逆向變換。我注意到你使用lookAt進行拾取,但是有一系列的繪製變換。這是爲什麼? – Erhannis

+0

這只是我的設計,它的工作有點,不完全是點(它的關閉,如果我選擇在左邊,不是那麼接近右邊),但它非常準確.. – RedLeader