2011-11-02 244 views
0

我試圖用屏幕寬度的100%來顯示一個正方形多邊形,然後,我想我必須放大它(用Z軸),直到多邊形邊框在屏幕邊框上。如何將頂點座標轉換爲屏幕像素座標?

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

問題是出現了問題,使用gluProject返回的outputCoords數組給我假的值,然後我做錯了什麼。例如,如果我將Z值設爲-1,15,我可以看到我的多邊形的屏幕寬度是否完全相同......但outputCootrds數組告訴我這些罕見的值:175,16,0.9! ! 175,16!這是錯誤的,因爲多邊形具有完全相同的屏幕寬度,並且從屏幕的0像素開始:S

如果有人可以幫助我解釋用代碼示例實現此目的的正確方法,請我真的需要幫助。我收穫了數以千計的關於將頂點轉換爲像素座標的教程和stackoverflow問題,但所有這些教程,指南和問題都無法幫助我通過代碼實現此目的。

這是myGlSurfaceView類,計算屏幕像素座標的代碼是方法。

public class MySurfaceView extends GLSurfaceView implements Renderer { 
private Context context; 
private Square square; 
private float xrot;     //X Rotation 
private float yrot;     //Y Rotation 
private float zrot;     //Z Rotation 
private float xspeed;    //X Rotation Speed 
private float yspeed;    //Y Rotation Speed 
private float z = -1.15f;   //Profundidad en el eje Z 
private float oldX; //valor anterior de X, para rotación 
private float oldY; //valor anterior de Y, para rotación 
private final float TOUCH_SCALE = 0.2f;  //necesario para la rotación 

//create the matrix grabber object in your initialization code 
private MatrixGrabber mg = new MatrixGrabber();   

private boolean firstTimeDone=false; //true si la aplicación ya ha sido inicializada. 

public MySurfaceView(Context context, Bitmap image) { 
    super(context); 
    this.context = context; 
    setEGLConfigChooser(8, 8, 8, 8, 16, 0); //fondo transparente 
    getHolder().setFormat(PixelFormat.TRANSLUCENT); //fondo transparente 
    //Transformamos esta clase en renderizadora 
    this.setRenderer(this); 
    //Request focus, para que los botones reaccionen 
    this.requestFocus(); 
    this.setFocusableInTouchMode(true); 
    square = new Square(image);         
} 

public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
    gl.glDisable(GL10.GL_DITHER);    //dithering OFF 
    gl.glEnable(GL10.GL_TEXTURE_2D);   //Texture Mapping ON 
    gl.glShadeModel(GL10.GL_SMOOTH);   //Smooth Shading 
    gl.glClearDepthf(1.0f);      //Depth Buffer Setup 
    gl.glEnable(GL10.GL_DEPTH_TEST);   //Depth Testing ON 
    gl.glDepthFunc(GL10.GL_LEQUAL); 
    gl.glClearColor(0,0,0,0); //fondo transparente 
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);   
    //Cargamos la textura del cubo. 
    square.loadGLTexture(gl, this.context); 
} 

public void onDrawFrame(GL10 gl) { 
    //Limpiamos pantalla y Depth Buffer 
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 
    gl.glLoadIdentity(); 
    //Dibujado 
    gl.glTranslatef(0.0f, 0.0f, z);   //Move z units into the screen 
    gl.glScalef(0.8f, 0.8f, 0.8f);   //Escalamos para que quepa en la pantalla 
    //Rotamos sobre los ejes. 
    gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f); //X 
    gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f); //Y 
    gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f); //Z 
    //Dibujamos el cuadrado 
    square.draw(gl);  
    //Factores de rotación. 
    xrot += xspeed; 
    yrot += yspeed;   


    if (!firstTimeDone) 
    {  
     /////////////// NEW CODE FOR SCALING THE AR IMAGE TO THE DESIRED WIDTH /////////////////    
     mg.getCurrentProjection(gl); 
     mg.getCurrentModelView(gl);      
     float [] modelMatrix = new float[16]; 
     float [] projMatrix = new float[16]; 
     modelMatrix=mg.mModelView; 
     projMatrix=mg.mProjection;   
     int [] mView = new int[4]; 
     mView[0] = 0; 
     mView[1] = 0; 
     mView[2] = 800; //width 
     mView[3] = 480; //height 
     float [] outputCoords = new float[3]; 
     GLU.gluProject(-1.0f, -1.0f, z, modelMatrix, 0, projMatrix, 0, mView, 0, outputCoords, 0); 

     int i=0; 
     System.out.print(i); 
     // firstTimeDone=true; 
    } 
} 

//si el surface cambia, resetea la vista, imagino que esto pasa cuando cambias de modo portrait/landscape o sacas el teclado físico en móviles tipo Droid. 
public void onSurfaceChanged(GL10 gl, int width, int height) { 
    if(height == 0) {      
     height = 1;       
    } 
    gl.glViewport(0, 0, width, height);  //Reset Viewport 
    gl.glMatrixMode(GL10.GL_PROJECTION); //Select Projection Matrix 
    gl.glLoadIdentity();     //Reset Projection Matrix 
    //Aspect Ratio de la ventana 
    GLU.gluPerspective(gl, 45.0f, (float)width/(float)height, 0.1f, 100.0f); 
    gl.glMatrixMode(GL10.GL_MODELVIEW);  //Select Modelview Matrix 
    gl.glLoadIdentity();     //Reset Modelview Matrix   

} 

public boolean onTouchEvent(MotionEvent event) { 
    float x = event.getX(); 
    float y = event.getY(); 
    switch (event.getAction()) 
    { 
     case MotionEvent.ACTION_MOVE: 
      //Calculamos el cambio 
      float dx = x - oldX; 
      float dy = y - oldY; 
      xrot += dy * TOUCH_SCALE; 
      yrot += dx * TOUCH_SCALE; 
      //Log.w("XXXXXX", "ACTION_MOVE_NO_ZOOM"); 
      break; 
    } 
    oldX = x; 
    oldY = y; 
    return true; //El evento ha sido manejado 
} 

public void zoomIn(){ 
    z=z+0.2f; 
    if (z>-1.0f) 
     z=-1.0f; 
} 
public void zoomOut(){ 
    z=z-0.2f; 
    if (z<-20.0f) 
     z=-20.0f; 
} 
public void rotateL(){ 
    zrot=zrot+3.0f; 
} 
public void rotateR(){ 
    zrot=zrot-3.0f; 
} 
public void reset() 
{ 
    xrot=0; 
    yrot=0; 
    zrot=0; 
    xspeed=0; 
    yspeed=0; 
    z = -5.0f; 
} 
} 

這是我的平方類別:

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 vertices[] = 
{ 
-0.8f, -0.8f, 0.0f,  //Bottom Left 
0.8f, -0.8f, 0.0f,  //Bottom Right 
-0.8f, 0.8f, 0.0f,  //Top Left 
0.8f, 0.8f, 0.0f 
}; 
*/ 
//Coordenadas (u, v) de las texturas  
/* 
private float texture[] = 
{   
    //Mapping coordinates for the vertices 
    0.0f, 0.0f, 
    0.0f, 1.0f, 
    1.0f, 0.0f, 
    1.0f, 1.0f 
}; 
*/ 
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; 
    } 
} 
} 
+0

可能的重複[gluProject函數如何工作?我無法理解它](http://stackoverflow.com/questions/7980430/how-does-the-gluproject-function-work-i-cant-understand-it) –

+0

您的'MatrixGrabber'類是否正常工作並且給你正確的矩陣?而且您的視口實際上是800x480,您將其硬編碼到該功能中? –

+0

srry打開另一個問題,但另一個問題只是關於gluProject。 MatrixGrabber應該可以工作,它是Google Android的官方Java類。視口是800x480,因爲它是橫向仿真器1.6的分辨率。 – NullPointerException

回答

1

如果我看到正確的,你把gluProject的Z值是你把glTranslate相同的值。但您仍然使用頂點(-1, -1, 0)繪製多邊形,z翻譯來自glTranslate調用(這反過來修改了模型視圖矩陣)。但是這個矩陣也用於gluProject,所以實際發生的是你翻譯z兩次(不完全一樣,因爲第一次翻譯被旋轉進一步扭曲)。所以放在同一個頂點,你也畫多邊形,這將是(-1, -1, 0)而不是(-1, -1, z)

記住gluProject做同樣的事情OpenGL的管路改造(在我的答案一樣解釋到其他幾乎完全一樣的問題),所以你必須與你喂的OpenGL管道用相同的值給它(你的多邊形的頂點),如果你想要相同的結果(多邊形覆蓋屏幕)。

+0

如果我傳遞-1 -1 0到gluProject函數,那麼在outPutCOrds數組上返回的值爲0 0 0:S – NullPointerException

+0

並且z不應該爲0,因爲Z應該是-1.15,z = -1.15,多邊形填充屏幕寬度的100%,這是我的第一個目標,當我學會如何做到這一點時,我會用多邊形寬度的動態值來做到這一點。請告訴我什麼是錯的,我不能解決這個問題:/ – NullPointerException

+0

@ AndroidUser99不,z應該是0。當您使用z = -1.15(使用'glTranslate')翻譯它時,多邊形(z = 0)會填滿屏幕。但'gluProject'使用這個完全相同的翻譯。所以,當你將z = -1.15傳遞給'gluProject'時,這個z被進一步轉換爲模型視圖矩陣(包含你傳遞給'glTranslate'的z)。如果仍然有關於gluProject和OpenGL轉換流程的工作情況,請閱讀我答案的最後一段。 –

相關問題