2011-11-02 83 views
3

我需要顯示一個正方形多邊形,其寬度爲屏幕的100%,然後,我必須放大它(使用Z軸),直到多邊形邊框觸摸屏幕邊框。gluProject功能如何工作?我無法理解它

我想實現這個使用gluProject將3D座標投影到2D屏幕座標。如果屏幕座標爲0或與寬度或高度相匹配,則它正在觸摸屏幕邊框。

問題是出現問題了,用gluProject返回的outputCoords數組給我提供了這些值:0,0,0.5,但是我的方形以屏幕爲中心,並且Z = -5.0f !!! !

我不明白這些價值觀......

這是我使用我的獲取屏幕上方形poligon的2D投影代碼:

此代碼是的onSurfaceCreated方法GLSurfaceView類,它必須放在另一種方法中?哪裏?

/////////////// NEW CODE FOR SCALING THE AR IMAGE TO THE DESIRED WIDTH ///////////////// 

     mg.getCurrentModelView(gl); 
     mg.getCurrentProjection(gl); 

     float [] modelMatrix = new float[16]; 
     float [] projMatrix = new float[16];   
     modelMatrix=mg.mModelView; 
     projMatrix=mg.mProjection; 
     int [] mView = new int[4]; 
     // Fill this with your window width and height 
     mView[0] = 0; 
     mView[1] = 0; 
     mView[2] = 800; //width 
     mView[3] = 480; //height 
     // Make sure you have 3 components in this array even if the screen only needs 2 
     float [] outputCoords = new float[3]; 
     // objX, objY, objZ are the coordinates of one of the borders 
     GLU.gluProject(-1.0f, -1.0f, 0.0f, modelMatrix, 0, projMatrix, 0, mView, 0, outputCoords, 0); 

這是我的平方類別:

public class Square { 
//Buffer de vertices 
private FloatBuffer vertexBuffer; 
//Buffer de coordenadas de texturas 
private FloatBuffer textureBuffer; 
//Puntero de texturas 
private int[] textures = new int[3]; 
//El item a representar 
private Bitmap image; 
//Definición de vertices 

private float vertices[] = 
{ 
    -1.0f, -1.0f, 0.0f,  //Bottom Left 
    1.0f, -1.0f, 0.0f,  //Bottom Right 
    -1.0f, 1.0f, 0.0f,  //Top Left 
    1.0f, 1.0f, 0.0f  //Top Right 
}; 

private float texture[] = 
{ 
    //Mapping coordinates for the vertices 
    0.0f, 1.0f, 
    1.0f, 1.0f, 
    0.0f, 0.0f, 
    1.0f, 0.0f 
}; 
//Inicializamos los buffers 
public Square(Bitmap image) { 
    ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4); 
    byteBuf.order(ByteOrder.nativeOrder()); 
    vertexBuffer = byteBuf.asFloatBuffer(); 
    vertexBuffer.put(vertices); 
    vertexBuffer.position(0); 

    byteBuf = ByteBuffer.allocateDirect(texture.length * 4); 
    byteBuf.order(ByteOrder.nativeOrder()); 
    textureBuffer = byteBuf.asFloatBuffer(); 
    textureBuffer.put(texture); 
    textureBuffer.position(0); 

    this.image=image; 
} 
//Funcion de dibujado 
public void draw(GL10 gl) { 
    gl.glFrontFace(GL10.GL_CCW); 
    //gl.glEnable(GL10.GL_BLEND); 
    //Bind our only previously generated texture in this case 
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); 
    //Point to our vertex buffer 
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); 
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer); 
    //Enable vertex buffer 
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
    //Draw the vertices as triangle strip 
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length/3); 
    //Disable the client state before leaving 
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
    //gl.glDisable(GL10.GL_BLEND);  
} 
//Carga de texturas 
public void loadGLTexture(GL10 gl, Context context) { 
    //Generamos un puntero de texturas 
    gl.glGenTextures(1, textures, 0);  
    //y se lo asignamos a nuestro array 
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); 
    //Creamos filtros de texturas 
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); 
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
    //Diferentes parametros de textura posibles GL10.GL_CLAMP_TO_EDGE 
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT); 
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);  
    /* 
    String imagePath = "radiocd5.png"; 
    AssetManager mngr = context.getAssets(); 
    InputStream is=null; 
    try { 
     is = mngr.open(imagePath); 
    } catch (IOException e1) { e1.printStackTrace(); } 
    */ 
    //Get the texture from the Android resource directory 
    InputStream is=null; 
    /* 
    if (item.equals("rim")) 
     is = context.getResources().openRawResource(R.drawable.rueda); 
    else if (item.equals("selector")) 
     is = context.getResources().openRawResource(R.drawable.selector); 
    */  
    /* 
    is = context.getResources().openRawResource(resourceId); 
    Bitmap bitmap = null; 
    try { 
     bitmap = BitmapFactory.decodeStream(is); 
    } finally { 
     try { 
      is.close(); 
      is = null; 
     } catch (IOException e) { 
     } 
    } 
    */ 
    Bitmap bitmap =image;  
    //con el siguiente código redimensionamos las imágenes que sean mas grandes de 256x256. 
    int newW=bitmap.getWidth(); 
    int newH=bitmap.getHeight(); 
    float fact; 
    if (newH>256 || newW>256) 
    { 
     if (newH>256) 
     { 
      fact=(float)255/(float)newH; //porcentaje por el que multiplicar para ser tamaño 256 
      newH=(int)(newH*fact); //altura reducida al porcentaje necesario 
      newW=(int)(newW*fact); //anchura reducida al porcentaje necesario 
     } 
     if (newW>256) 
     { 
      fact=(float)255/(float)newW; //porcentaje por el que multiplicar para ser tamaño 256 
      newH=(int)(newH*fact); //altura reducida al porcentaje necesario 
      newW=(int)(newW*fact); //anchura reducida al porcentaje necesario 
     } 
     bitmap=Bitmap.createScaledBitmap(bitmap, newW, newH, true); 
    }  
    //con el siguiente código transformamos imágenes no potencia de 2 en imágenes potencia de 2 (pot) 
    //meto el bitmap NOPOT en un bitmap POT para que no aparezcan texturas blancas. 
    int nextPot=256; 
    int h = bitmap.getHeight(); 
    int w = bitmap.getWidth(); 
    int offx=(nextPot-w)/2; //distancia respecto a la izquierda, para que la imagen quede centrada en la nueva imagen POT 
    int offy=(nextPot-h)/2; //distancia respecto a arriba, para que la imagen quede centrada en la nueva imagen POT 
    Bitmap bitmap2 = Bitmap.createBitmap(nextPot, nextPot, Bitmap.Config.ARGB_8888); //crea un bitmap transparente gracias al ARGB_8888 
    Canvas comboImage = new Canvas(bitmap2); 
    comboImage.drawBitmap(bitmap, offx, offy, null); 
    comboImage.save(); 

    //Usamos Android GLUtils para espcificar una textura de 2 dimensiones para nuestro bitmap 
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap2, 0); 

    //Checkeamos si el GL context es versión 1.1 y generamos los Mipmaps por Flag. Si no, llamamos a nuestra propia implementación 
    if(gl instanceof GL11) { 
     gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE); 
     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap2, 0); 
    } else { 
     buildMipmap(gl, bitmap2); 
    } 
    //Limpiamos los bitmaps 
    bitmap.recycle(); 
    bitmap2.recycle(); 
} 
//Nuestra implementación de MipMap. Escalamos el bitmap original hacia abajo por factor de 2 y lo asignamos como nuevo nivel de mipmap 
private void buildMipmap(GL10 gl, Bitmap bitmap) { 
    int level = 0; 
    int height = bitmap.getHeight(); 
    int width = bitmap.getWidth(); 
    while(height >= 1 || width >= 1) { 
     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0); 
     if(height == 1 || width == 1) { 
      break; 
     } 
     level++; 
     height /= 2; 
     width /= 2; 
     Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); 
     bitmap.recycle(); 
     bitmap = bitmap2; 
    } 
} 
} 

回答

11

gluProject究竟是幹什麼的固定功能轉換管道會做,太:

  1. 的3D頂點擴展到齊次座標通過附加一個1作爲第四個座標:v[3]=1

  2. 然後,將這個同質頂點乘以模型視圖矩陣和投影矩陣:v'=P*M*v

  3. 然後來到持續的分裂。通過除以第四座標,我們考慮了透視失真(如果您有正交投影,例如使用glOrtho,那麼v'[3]==1並且沒有透視失真):v"=v'/v'[3]

  4. 現在,您的觀察體積(場景的可見區域)中的所有內容都已轉換爲標準化的設備座標,[-1,1] - 立方體。所以需要做的是將其轉換爲屏幕座標[0,w] x [0,h]:x=w * (v"[0]+1)/2y = h * (v"[1]+1)/2。最後,將z座標從[-1,1]轉換爲[0,1],以給出寫入深度緩衝區的歸一化深度值:z = (v"[2]+1)/2

所以關鍵理解發生了什麼z值來實現,即在相機(在視圖空間中的Z值)的距離被第一轉化爲[-1,1]範圍內由投影矩陣,取決於近遠距離(您放入glOrthoglFrustumgluPerspective的近值和遠值)。然後,將此歸一化值轉換爲[0,1]範圍,以產生寫入深度緩衝區的最終深度值,並將gluProject計算爲窗口座標的z值。

所以你實際得到的(0, 0, 0.5)是你的屏幕的左下角,深度爲0.5。使用正交矩陣(沒有任何透視失真)和標識模型視圖矩陣,這將等於座標(left, bottom, (far-near)/2),其中bottom,left,nearfar是您放入glOrtho函數調用的相應參數(或具有類似功能的東西)。因此,頂點位於近距離和觀看體積的左下角中間(從相機看)。但是這不適用於透視投影,因爲在這種情況下,從視空間z座標到深度值的轉換不是線性的(儘管仍然是單調的)。

由於您放入頂點(-1, -1, 0),這可能意味着您的模型視圖矩陣是標識,您的投影矩陣對應於使用glOrtho(-1, 1, -1, 1, -1, 1)創建的矩陣,該矩陣也接近單位矩陣(儘管帶有鏡像z值,但因爲輸入z是0,你可能不會注意到它)。因此,如果這些值不是您期待的值(理解gluProject的工作情況,當然),也可能是您的矩陣未被正確檢索,並且您只獲得了身份矩陣,而不是實際的模型視圖和投影矩陣。

所以我認爲你的gluProject函數沒有問題。您也可以查看this question的答案,以深入瞭解OpenGL的默認轉換管道。雖然隨着頂點着色器的出現,某些階段可以以不同方式計算,但通常仍然遵循慣用模型 - >視圖 - >投影方法。

+0

wiki狀態?很好解釋。 –

+0

基督徒,我再次與gluProject問題:S,這是問題:http://stackoverflow.com/questions/8064805/gluproject-not-working-if-the-object-haves-z-1-0f-和它-被縮放到0-01f – NullPointerException