android OpenGL-Es gluProject结果不准确?

时间:2012-03-09 13:51:38

标签: android opengl-es glu

我想在游戏中的3D模型上叠加一个图标。我正在使用gluProject来获取模型中心点的屏幕坐标,然后使用该数据在自定义视图上绘制图标:

在我的渲染器类中:

private void projectScreenCoords(GLSurfaceView view, GraphicsEntity ge, GL10 gl){

    MatrixGrabber matrixGrabber = new MatrixGrabber();
    matrixGrabber.getCurrentModelView(gl);  
    float[] modelMat = matrixGrabber.mModelView;
    matrixGrabber.getCurrentProjection(gl);
    float[] projMat = matrixGrabber.mProjection;
    gl.glMatrixMode(GL10.GL_MODELVIEW);

    // view port
    int[] viewport = new int[]{view.getTop(),view.getLeft(),view.getWidth(),view.getHeight()};


    float[] vector = new float[4];      
    GLU.gluProject(ge.getTransform().tx, ge.getTransform().ty, ge.getTransform().tz, modelMat, 0, projMat, 0, viewport, 0, vector, 0);

    ge.setScreenCoords(vector[0], viewport[3] - vector[1]);

}

和我的自定义视图:

protected void onDraw (Canvas canvas){
    Vector<GraphicsEntity> scene = renderer.getForegroundScene();

    for(int i = 0;i<scene.size();i++){
        GraphicsEntity ge = scene.get(i);
        float[] xy = ge.getScreenCoords();
        if(xy[0]>-1 && xy[1]>-1){
            canvas.drawBitmap(bitmap, xy[0]-bitmapWidth/2, xy[1]-bitmapHeight/2, null);
        }
        invalidate();
    }

}

我设置投影矩阵的地方:

    protected void setProjectionMatrix(GL10 gl){

        float ratio = (float) viewportWidth / viewportHeight;
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glFrustumf(-ratio*zoom, ratio*zoom, -1*zoom, 1*zoom, nearPlane, farPlane);

}

然而,距离屏幕中心越远,模型中心越远,图标就会被绘制出来:

enter image description here

显然,如果只是视口大小不正确(由于顶部/底部的条形图),那么图标将仅在y轴上关闭,但它们也在x轴上关闭。我错过了什么/做错了什么?另外我还没有使用gluProject返回的第3个值,但是它的值总是为0.7,所以我不确定它是如何被使用的呢?

使用SDK版本7,我在多个设备上测试了这个(运行Android 2.1的ZTE Blade和运行2.3.4的Kindle Fire),结果相同。 viewportWidth / Height和view.getWidth / Height()是相同的,view.getTop / Left()返回0. MatrixGrabber代码适用于gluUnProject,所以我有理由相信这不是问题


编辑:这是我与GL相关的其他绘图代码:

在渲染器中:

    // camera variables
protected float FOV = 60.0f;
protected float nearPlane = 3;
protected float farPlane = 7;

protected float eyeX = 0;
protected float eyeY = 0;
protected float eyeZ = 0;

protected float centreX = 0;
protected float centreY = 0;
protected float centreZ = ((farPlane - nearPlane) / 2) + nearPlane;

protected float upX = 0;
protected float upY = 1;
protected float upZ = 0;

protected float viewportWidth;
protected float viewportHeight;

// user camera control variables
protected float zoom = 1;
protected float rotatedX = 0;
protected float rotatedY = 0;
protected boolean zoomed = true;
protected TrackingTransform tracking;

protected void setWorldTransform(GL10 gl){

    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();

    // transforms the centre position to 0,0,0
    gl.glTranslatef(-centreX, -centreY, -centreZ);

}

protected void setModelRotation(GL10 gl, GraphicsEntity ge){

    if(ge.isTrackerball()){

        gl.glRotatef(rotatedX, 1.0f, 0, 0);
        gl.glRotatef(rotatedY, 0, -1.0f, 0);

        if(tracking!=null){
            synchronized(tracking){
                tracking.transform(gl);
            }
        }


    } else if(ge.isBackground()){

        gl.glTranslatef(centreX, centreY, centreZ);

        gl.glRotatef(rotatedX, 1.0f, 0, 0);
        gl.glRotatef(rotatedY, 0, -1.0f, 0);

        if(ge.isSkybox()==true){

            ge.getTransform().sx = nearPlane + 1.0f;
            ge.getTransform().sy = nearPlane + 1.0f;
            ge.getTransform().sz = nearPlane + 1.0f;

            ge.getTransform().tx = 0;
            ge.getTransform().ty = 0;
            ge.getTransform().tz = 0;

        }

    }           

}

protected void setModelViewMatrix(GL10 gl){
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();

    // not used:
    //GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, centreX, centreY, centreZ, upX, upY, upZ);        
}

@Override
public void onDrawFrame(GL10 gl) {

    // Set up various things before drawing
    gl.glFrontFace(GL10.GL_CW);
    gl.glEnable(GL10.GL_CULL_FACE);
    gl.glCullFace(GL10.GL_FRONT);
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    gl.glEnable(GL10.GL_DEPTH_TEST);

    // change projection matrix     
    float oldzoom = zoom;
    zoom = 1.0f;
    setProjectionMatrix(gl);
    zoom = oldzoom;

    // set global world transform (also changes to modelview)
    setWorldTransform(gl);

    // loop through and draw background models
    for(int i = 0;i<backgroundGraphicsEntities.size();i++){

        GraphicsEntity ge = backgroundGraphicsEntities.get(i);

        SimpleTransform t = ge.getTransform();
        int modelIndex = ge.getModelIndex();

        if(modelIndex>=0){

            gl.glPushMatrix();

            setModelRotation(gl, ge);

            t.transform(gl);

            if(ge.isSprite() && gl11flag){

                Sprite s = sprites.get(modelIndex);
                s.draw((GL11) gl, ge);

            } else {

                Model m = models.get(modelIndex); 
                if(m!=null){
                    m.draw(gl);
                }

            }

            gl.glPopMatrix();

        }

        if(i==0 && ge.isSkybox()){
            // if skybox, reset depth bit
            gl.glClear(GL10.GL_DEPTH_BUFFER_BIT);
        }

    }

    gl.glClear(GL10.GL_DEPTH_BUFFER_BIT);

    // change projection matrix (if zoomed)     
    setProjectionMatrix(gl);

    // change back to modelview
    gl.glMatrixMode(GL10.GL_MODELVIEW);

    // loop through and draw models
    for(int i = 0;i<graphicsEntities.size();i++){

        GraphicsEntity ge = graphicsEntities.get(i);

        SimpleTransform t = ge.getTransform();
        int modelIndex = ge.getModelIndex();

        if(modelIndex>=0){

            gl.glPushMatrix();

            setModelRotation(gl, ge);

            t.transform(gl);

            if(ge.isSprite() && gl11flag){

                Sprite s = sprites.get(modelIndex);
                s.draw((GL11) gl, ge);

            } else {

                Model m = models.get(modelIndex); 
                if(m!=null){
                    m.draw(gl);
                }

                if(projectScreenCoords){
                    projectScreenCoords(glSurfaceView, ge, gl);
                }

            }

            gl.glPopMatrix();

        }
    }

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {

    viewportWidth = width;
    viewportHeight = height;

    gl.glViewport(0, 0, width, height);

    setProjectionMatrix(gl);

}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {

    if(gl instanceof GL11){
        gl11flag = true;
    }

     gl.glClearColor(0, 0, 0, 1);
     gl.glShadeModel(GL10.GL_SMOOTH);
     gl.glEnable(GL10.GL_DEPTH_TEST);
     gl.glDepthMask(true);
     //gl.glClearDepthf(1.0f);
     gl.glDepthFunc(GL10.GL_LEQUAL);         
     //gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);

    setProjectionMatrix(gl);

}

然后在SimpleTransform中(即调用ge.getTransform()。transform(gl)时调用的内容):

public void transform(GL10 gl) {
    gl.glTranslatef(tx, ty, tz);        
    gl.glRotatef(rz, 0, 0, 1);
    gl.glRotatef(ry, 0, 1, 0);
    gl.glRotatef(rx, 1, 0, 0);
    gl.glScalef(sx, sy, sz);
}

和TrackingTransform:

@Override
public void transform(GL10 gl) {
    gl.glTranslatef(-tx, -ty, -tz);     
}

最后在model.draw()中:

public void draw(GL10 gl){

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

    // Pass the vertex buffer in
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0,
                             vertices);

    int textureID = material.getTexture().getTextureID();

    if(textureID>=0){

        // Enable Textures
        gl.glEnable(GL10.GL_TEXTURE_2D);

        // Get specific texture.
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);

        // Use UV coordinates.
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        // Pass in texture coordinates          
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureCoordinates);

    } 

    // Pass in vertex normals
    gl.glNormalPointer(GL10.GL_FLOAT, 0, normals);

    gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);

    gl.glDrawElements(GL10.GL_TRIANGLES, numindices,GL10.GL_UNSIGNED_SHORT, indices);

    gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);

    if(textureID>=0){
        // Disable buffers          
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    }

    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

}

1 个答案:

答案 0 :(得分:0)

问题根本不在于gluProject代码。事实上,这是在调用gluProject之前完成的翻译:

在onDrawFrame中:

                Model m = models.get(modelIndex); 
                if(m!=null){
                    m.draw(gl);

                    gl.glTranslatef(-tracking.getTransform().tx, -tracking.getTransform().ty, -tracking.getTransform().tz);

                    if(tickcount % projectFrequency == 0 ){
                        projectScreenCoords(glSurfaceView, ge, gl);
                    }

                }