开发者

Problems drawing in OpenGL ES 2D Orthographic (Ortho) mode

I've been beating my head against the desk trying to figure this out for days now, and after scouring Stack Overflow and the web, I haven't found any examples that have worked for me. I've finally got code that's seems close, so maybe you guys (and gals?) can help me figure this out.

My first problem is that I'm trying to implement a motion blur by taking a screen grab as a texture, then drawing the texture over the next frame with transparency -- or use more frames for more blur. (If anyone's interested, this is the guide I followed: http://www.codeproject.com/KB/openGL/MotionBlur.aspx)

I've got the screen saving as a texture working fine. The issue I'm having is drawing in Ortho mode on top of the screen. After much head ba开发者_运维知识库nging, I finally got a basic square drawing, but my lack of OpenGL ES understanding and an easy to follow example are holding me back now. I need to take the texture I saved, and draw it into the square I drew. Nothing I've been doing seems to work.

Also, my second problem, is drawing more complex 3d models into Ortho mode. I can't seem to get any models to draw. I'm using the (slightly customized) min3d framework (http://code.google.com/p/min3d/), and I'm trying to draw Object3d's in Ortho mode just like I draw them in Perspective mode. As I understand it, they should draw the same, they should just not have depth. Yet I don't seem to see them at all.

Here's the code I'm working with. I've tried a ton of different things and this is the closest I've gotten (actually drawing something on the screen that can be seen). I still have no idea how to get a proper 3d model drawing in the ortho view. I'm sure I'm doing something horribly wrong and probably completely misunderstanding some basic aspects of OpenGL drawing. Let me know if there's any other code I need to post.

// Gets called once, before all drawing occurs
//
private void reset()
{
    // Reset TextureManager
    Shared.textureManager().reset();

    // Do OpenGL settings which we are using as defaults, or which we will not be changing on-draw

    // Explicit depth settings
    _gl.glEnable(GL10.GL_DEPTH_TEST);                                   
    _gl.glClearDepthf(1.0f);
    _gl.glDepthFunc(GL10.GL_LESS);                                      
    _gl.glDepthRangef(0,1f);                                            
    _gl.glDepthMask(true);                                              

    // Alpha enabled
    _gl.glEnable(GL10.GL_BLEND);                                        
    _gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);    

    // "Transparency is best implemented using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 
    // with primitives sorted from farthest to nearest."

    // Texture
    _gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); // (OpenGL default is GL_NEAREST_MIPMAP)
    _gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); // (is OpenGL default)

    // CCW frontfaces only, by default
    _gl.glFrontFace(GL10.GL_CCW);
    _gl.glCullFace(GL10.GL_BACK);
    _gl.glEnable(GL10.GL_CULL_FACE);

    // Disable lights by default
    for (int i = GL10.GL_LIGHT0; i < GL10.GL_LIGHT0 + NUM_GLLIGHTS; i++) {
        _gl.glDisable(i);
    }

    //
    // Scene object init only happens here, when we get GL for the first time
    // 
}

// Called every frame
//
protected void drawScene()
{   
    if(_scene.fogEnabled() == true) {
        _gl.glFogf(GL10.GL_FOG_MODE, _scene.fogType().glValue());
        _gl.glFogf(GL10.GL_FOG_START, _scene.fogNear());
        _gl.glFogf(GL10.GL_FOG_END, _scene.fogFar());
        _gl.glFogfv(GL10.GL_FOG_COLOR, _scene.fogColor().toFloatBuffer() );
        _gl.glEnable(GL10.GL_FOG);
    } else {
        _gl.glDisable(GL10.GL_FOG);
    }

    // Sync all of the object drawing so that updates in the mover
    // thread can be synced if necessary
    synchronized(Renderer.SYNC)
    {
        for (int i = 0; i < _scene.children().size(); i++)
        {
            Object3d o = _scene.children().get(i);
            if(o.animationEnabled())
            {
                ((AnimationObject3d)o).update();
            }
            drawObject(o);
        }
    }

    //
    //
    //
    // Draw the blur

    // Set Up An Ortho View
    _switchToOrtho();

    _drawMotionBlur();

    // Switch back to the previous view
    _switchToPerspective();

    _saveScreenToTexture("blur", 512);
}

private void _switchToOrtho()
{
    // Set Up An Ortho View
    _gl.glDisable(GL10.GL_DEPTH_TEST);
    _gl.glMatrixMode(GL10.GL_PROJECTION); // Select Projection
    _gl.glPushMatrix(); // Push The Matrix
    _gl.glLoadIdentity(); // Reset The Matrix
    _gl.glOrthof(0f, 480f, 0f, 800f, -1f, 1f);
    //_gl.glOrthof(0f, 480f, 0f, 800f, -100f, 100f);
    _gl.glMatrixMode(GL10.GL_MODELVIEW); // Select Modelview Matrix
    _gl.glPushMatrix(); // Push The Matrix
    _gl.glLoadIdentity(); // Reset The Matrix
}

private void _switchToPerspective()
{
    // Switch back to the previous view
    _gl.glEnable(GL10.GL_DEPTH_TEST);
    _gl.glMatrixMode(GL10.GL_PROJECTION);
    _gl.glPopMatrix();
    _gl.glMatrixMode(GL10.GL_MODELVIEW);
    _gl.glPopMatrix(); // Pop The Matrix
}

private void _saveScreenToTexture(String $textureId, int $size)
{
    // Save the screen as a texture
    _gl.glViewport(0, 0, $size, $size);
    _gl.glBindTexture(GL10.GL_TEXTURE_2D, _textureManager.getGlTextureId($textureId));
    _gl.glCopyTexImage2D(GL10.GL_TEXTURE_2D,0,GL10.GL_RGB,0,0,512,512,0);
    _gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
    _gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
    _gl.glViewport(0, 0, 480, 800);
}

private void _drawMotionBlur()
{
    // Vertices
    float squareVertices[] = {
        -3f, 0f,     // Bottom Left
        475f, 0f,     // Bottom Right
        475f, 800f, // Top Right
        -3f, 800f  // Top Left
    };

    ByteBuffer vbb = ByteBuffer.allocateDirect(squareVertices.length * 4);
    vbb.order(ByteOrder.nativeOrder());
    FloatBuffer vertexBuffer = vbb.asFloatBuffer();
    vertexBuffer.put(squareVertices);
    vertexBuffer.position(0);

    //
    //
    // Textures
    FloatBuffer textureBuffer;  // buffer holding the texture coordinates
    float texture[] = {         
            // Mapping coordinates for the vertices
            0.0f, 1.0f,     // top left     (V2)
            0.0f, 0.0f,     // bottom left  (V1)
            1.0f, 1.0f,     // top right    (V4)
            1.0f, 0.0f      // bottom right (V3)
    };
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(squareVertices.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    textureBuffer = byteBuffer.asFloatBuffer();
    textureBuffer.put(texture);
    textureBuffer.position(0);
    //
    //
    //

    _gl.glLineWidth(3.0f);
    _gl.glTranslatef(5.0f, 0.0f, 0.0f);
    _gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);
    _gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

    _gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);
    //_gl.glTranslatef(100.0f, 0.0f, 0.0f);
    //_gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);
    //_gl.glTranslatef(100.0f, 0.0f, 0.0f);
    //_gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);


    _gl.glEnable(GL10.GL_TEXTURE_2D);
    _gl.glEnable(GL10.GL_BLEND);
    _gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    _gl.glLoadIdentity();

    //
    //
    //
    _gl.glBindTexture(GL10.GL_TEXTURE_2D, _textureManager.getGlTextureId("blur"));
    _gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
    _gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
    //
    //
    //

    _gl.glDisable(GL10.GL_BLEND);
    _gl.glDisable(GL10.GL_TEXTURE_2D);
    _gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}

EDIT: Here's a simpler example, it's all in the one function and doesn't include any of the saving the screen to a texture stuff. This is just drawing a 3d scene, switching to Ortho, drawing a square with a texture, then switching back to perspective.

// Called every frame
//
protected void drawScene()
{   
    // Draw the 3d models in perspective mode
    // This part works (uses min3d) and draws a 3d scene
    //
    for (int i = 0; i < _scene.children().size(); i++)
    {
        Object3d o = _scene.children().get(i);
        if(o.animationEnabled())
        {
            ((AnimationObject3d)o).update();
        }
        drawObject(o);
    }

    // Set Up The Ortho View to draw a square with a texture
    // over the 3d scene
    //
    _gl.glDisable(GL10.GL_DEPTH_TEST);
    _gl.glMatrixMode(GL10.GL_PROJECTION); // Select Projection
    _gl.glPushMatrix(); // Push The Matrix
    _gl.glLoadIdentity(); // Reset The Matrix
    _gl.glOrthof(0f, 480f, 0f, 800f, -1f, 1f);
    _gl.glMatrixMode(GL10.GL_MODELVIEW); // Select Modelview Matrix
    _gl.glPushMatrix(); // Push The Matrix
    _gl.glLoadIdentity(); // Reset The Matrix


    // Draw A Square With A Texture
    // (Assume that the texture "blur" is already created properly --
    // it is as I can use it when drawing my 3d scene if I apply it
    // to one of the min3d objects)
    //
    float squareVertices[] = {
        -3f, 0f,     // Bottom Left
        475f, 0f,     // Bottom Right
        475f, 800f, // Top Right
        -3f, 800f  // Top Left
    };

    ByteBuffer vbb = ByteBuffer.allocateDirect(squareVertices.length * 4);
    vbb.order(ByteOrder.nativeOrder());
    FloatBuffer vertexBuffer = vbb.asFloatBuffer();
    vertexBuffer.put(squareVertices);
    vertexBuffer.position(0);

    FloatBuffer textureBuffer;  // buffer holding the texture coordinates
    float texture[] = {         
            // Mapping coordinates for the vertices
            0.0f, 1.0f,     // top left     (V2)
            0.0f, 0.0f,     // bottom left  (V1)
            1.0f, 1.0f,     // top right    (V4)
            1.0f, 0.0f      // bottom right (V3)
    };
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(squareVertices.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    textureBuffer = byteBuffer.asFloatBuffer();
    textureBuffer.put(texture);
    textureBuffer.position(0);

    _gl.glLineWidth(3.0f);
    _gl.glTranslatef(5.0f, 0.0f, 0.0f);
    _gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);
    _gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

    _gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, 4);

    _gl.glEnable(GL10.GL_TEXTURE_2D);
    _gl.glEnable(GL10.GL_BLEND);
    _gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    _gl.glLoadIdentity();

    _gl.glBindTexture(GL10.GL_TEXTURE_2D, _textureManager.getGlTextureId("blur"));
    _gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
    _gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

    _gl.glDisable(GL10.GL_BLEND);
    _gl.glDisable(GL10.GL_TEXTURE_2D);
    _gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    // Switch Back To The Perspective Mode
    //
    _gl.glEnable(GL10.GL_DEPTH_TEST);
    _gl.glMatrixMode(GL10.GL_PROJECTION);
    _gl.glPopMatrix();
    _gl.glMatrixMode(GL10.GL_MODELVIEW);
    _gl.glPopMatrix(); // Pop The Matrix
}

EDIT2: Thanks to Christian's answer, I removed the second glVertexPointer and _gl.glBlendFunc (GL10.GL_ONE, GL10.GL_ONE); (I deleted them from the sample code above as well so it wouldn't confuse the question). I now have a texture rendering, but only in one of the triangles that make up the square. So I'm seeing a triangle in the left portion of the screen that has the texture applied. Why is it not being applied to both halves of the square? I think it's because I have only one of these calls: gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); so I'm literally only drawing one triangle.


First, you set the blend function to (GL_ONE, GL_ONE), which will just add the blur texture to the framebuffer and make the whole scene overbright. You probalby want to use (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), but then you have to make sure your blur texture has the correct alpha, by configuring the texture environment to use a constant value for the alpha (instead of the texture's) or use GL_MODULATE with a (1,1,1,0.5) coloured square. Alternatively use a fragment shader.

Second, you specify a size 3 in the second call to glVertexPointer, but your data are 2d vectors (the first call is right).

glOrtho is not neccessarily 2D, its just a camera without perspective distortion (farther objects don't get smaller). The parameters to glOrtho specify your screen plane size in view coordinates. Thus if your scene covers the world in the unit cube, an ortho of 480x800 is just too large (this is no problem if you draw other objects than in perspective, as your square or UI elements, but when you want to draw your same 3d objects the scales have to match). Another thing is that in ortho the near and far distances still matter, everything that falls out is clipped away. So if your camera is at (0,0,0) and you view along -z with a glOrtho of (0,480,0,800,-1,1), you will only see those objects that intersect the (0,0,-1)-(480,800,1)-box.

So keep in mind, that glOrtho and glFrustum (or gluPerspective) all define a 3d viewing volume. In ortho its a box and in frustum its, guess a frustum (capped pyramid). consult some more introductory texts on transformations and viewing if this was not clear enough.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜