glOrtho setup for rendering "impostors" into a texture.

Sage
Posts: 1,199
Joined: 2004.10
Post: #1
Actually, using the phrase "imposter" here is perhaps a bit too fancy.

I'm prototyping having my trees render 3 views to a texture map ( +X, +Y, -Z ) for use in distant rendering. I'd render those distant trees by rendering the three planes, with the appropriate texture coordinates. (For reference, my engine creates a small number of unique tree "prototypes" and then positions thousands of lightweight clones of them on the stage so as to not use up way to much memory -- which is to say that if I have 4 prototypes, I'll only need to render four impostors. )

Anyway, this morning I wrote some test code just to see if I could render a single view of the tree into a square texture. After all, baby steps first. My approach goes like this:

1) get the combined AABB of the tree's solid geometry and its foliage ( the foliage is a separate object, with its own bounds ).

2) Create and bind an FBO.

3) Set up a viewport corresponding to the FBO's texture size ( obviously, when I render more views I'll partition ).

4) Set up an ortho projection to encompass the tree's bounding box

5) Set up the modelview to look at the tree

6) Render

Seems straightforward enough. When I run it via OpenGL Profiler and take a look at the rendered texture, I *do* see the tree and it's leaves. The thing is, I'm only seeing the top of the tree, and the near and far planes are screwy, in that I'm getting obvious clipping.

Here's my code:

Code:
void Tree::generateImposter( void )
{
    _renderingImposter = true;

    /*
        For the purposes of development, at first, we'll just set
        up an ortho projection and an FBO to render into, looking
        down the +Y axis. The ortho projection will correspond
        to the dimension of the tree's AABB and the viewport will
        correspond to the texture size.
    */
    
    AABB bb( aabb() + _foliage->aabb() );
    mat4 modelview;
    
    int size = 512;
    FrameBufferObject renderTexture( size, size, GL_TEXTURE_2D, false,
                                     FrameBufferObject::DepthBuffer | FrameBufferObject::AlphaChannel );
    

    glMatrixMode( GL_PROJECTION );
    glPushMatrix();
    {
        glLoadIdentity();
        glViewport( 0, 0, size, size );
        
        /*
            Setup ortho projection to represent tree's cubic (aabb) region
        */
        glOrtho( bb.minx, bb.maxx, bb.minz, bb.maxz, bb.miny, bb.maxy );
                
        /*
            Create a modelview to look at center of tree.
            Pull back on y so we can see all of tree.
        */
        
        vec3 eye( bb.center() ), at( bb.center() );
        eye.y = bb.miny;
        
        modelview.look_at( eye, at, vec3( 0,0,1 ));
        glMatrixMode( GL_MODELVIEW );
        glLoadMatrixf( modelview.mat );
        
        /*
            Bind render texture
        */
        renderTexture.begin();
    
        glClearColor( 0,0,0,0 );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        
        Light *light = world()->primaryLight();
        
        // render self
        setupState( Normal, SinglePass_Solid, light );
        display( SinglePass_Solid, light );
        teardownState( Normal, SinglePass_Solid );

        // render foliage        
        _foliage->setupState( Normal, SinglePass_Solid, light );
        _foliage->display( SinglePass_Solid, world()->primaryLight() );
        _foliage->teardownState( Normal, SinglePass_Solid );
            
        /*
            Unbind, and cleanup
        */
        renderTexture.end();

        glPopMatrix();
    }
    glPopMatrix();
    
    /*
        Now, release texture from FBO ( since on destruction FBO would
        otherwise free it ) and bind it to _imposterTexture
    */

    renderTexture.releaseTextureOwnership();
    TextureManager *tm = Application::instance()->textureManager();
    _imposterTexture = tm->take( renderTexture.textureID(), renderTexture.width(), renderTexture.height(),
                                 renderTexture.components(), renderTexture.format() );

    _renderingImposter = false;
}

For a little side-note, I use a z-as-up camera. It's just the way I prefer things. I think my problems might lie in confusion between my tree's AABB ( where x/y is the horizontal plane and z is up ) and the glOrtho command.

Does anybody have any suggestions?

Finally screenshots for clarity. Here's the actual tree:
[Image: ActualTree.png]

And here's the "imposter", or rather just its head in gl profiler:
[Image: Imposter.png]

( yeah, the rendering's ugly. I'll probably have to futz around to make certain the blending on the foliage looks right in render-to-texture, but right now I'm more concerned with getting the whole tree in there )
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #2
For what it's worth, I solved the projection issue. It makes sense in retrospect, but the fact that I use z-up is only relevant in the modelview matrix, not the projection matrix when I set up the ortho projection.

Now to tackle why the leaves draw with hideous halos...
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #3
TomorrowPlusX Wrote:Now to tackle why the leaves draw with hideous halos...

Don't you need to render it as pre-multiplied to keep it from blending with the white background?

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #4
Skorche Wrote:Don't you need to render it as pre-multiplied to keep it from blending with the white background?

That's an interesting point. I'm rendering against an FBO with an alpha channel, and am clearing everything to zero ( glClear( 0,0,0,0 )).

How would I render as pre-multiplied?
Quote this message in a reply
Oldtimer
Posts: 834
Joined: 2002.09
Post: #5
Rendering against a black background should do the trick. Just to be sure that you are doing that, try setting the blend function in OpenGL Profiler to GL_ONE, GL_ZERO. That will make the texture show up with the background color - if it is white, then that's what's causing your halos. Smile
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #6
That makes sense. I just did it, and I'm getting what "appears" to be a white background. I use scare quotes because the big white block seems to have the classic aqua pinstripes in it, which I find somewhat disturbing.

So, this begs the question, why isn't my calling glClear actually clearing to black?

[Image: GL_ONE-GL_ZERO.png]
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #7
That looks perfectly as if you clear the impostor to glClear(0,0,0,0), and there is no blending when you draw the texture. Since the texture is all transparent, you see through your view onto the window's background, which are the pinstripes.
Quote this message in a reply
Sage
Posts: 1,403
Joined: 2005.07
Post: #8
btw glClear takes r, g, b, a, and if a is 0 it does nothing.

Sir, e^iπ + 1 = 0, hence God exists; reply!
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #9
unknown Wrote:btw glClear takes r, g, b, a, and if a is 0 it does nothing.

Huh. So what do you do when you want to clear alpha to zero?
Quote this message in a reply
Member
Posts: 168
Joined: 2004.10
Post: #10
TomorrowPlusX Wrote:Huh. So what do you do when you want to clear alpha to zero?
If you don't have a transparent window context thing set up, why would you want to do that? If the of clear is to draw over with a large rectangle effectively, except in hardware with some other kind of complications, why would you draw an invisible clear on top? Isn't that completely pointless?
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #11
unknown Wrote:btw glClear takes r, g, b, a, and if a is 0 it does nothing.
False information. Clearing to transparent black is the typical thing to do, and it certainly works with alpha set to 0.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #12
socksy Wrote:If you don't have a transparent window context thing set up, why would you want to do that? If the of clear is to draw over with a large rectangle effectively, except in hardware with some other kind of complications, why would you draw an invisible clear on top? Isn't that completely pointless?

Because I'm rendering to texture, and I want the parts of the texture not rendered to to be fully transparent.

ThemsAllTook Wrote:False information. Clearing to transparent black is the typical thing to do, and it certainly works with alpha set to 0.

Well, that's reassuring (thanks!), but I still have the problem to fix...
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #13
I think you need to multiply the incoming and destination alpha together, it looks like it's just replacing the destination alpha.

Edit: Yeah, I think you need to use glBlendFuncSeperate() so that you can multiply the alpha values separately from the RGB values.

Edit #2: I was thinking about this more while eating. You need to blend towards 1 not 0. So instead of multiplying you would need an alpha blending factor like src(1-dst) + dst. I think that
Code:
glBlendFuncSeperate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE)
Should work.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #14
I have found that using GLProfiler to view the back buffer and alpha buffer while rendering is very helpful to understand how your final RTT result is formed.
Quote this message in a reply
Sage
Posts: 1,199
Joined: 2004.10
Post: #15
Skortche! I think you're right. I was contemplating this while looking at what the render looks like when drawn on-screen See the screenshot: [Image: Screenshots-2006-05-07-00.png]

I came to the same conclusion, that alpha's being saturated, e.g., wherever a fragment makes it to the render buffer, alpha's being saturated to one.

I'd *never* even heard of this glBlendFuncSeparate... I was going to ask if there was something that did what it sounds like that does. I'm going to read the manpages. Thank you so much!

@arrekusu -- can GL Profiler allow me to see the renderbuffer contents when I'm doing RTT? I thought it only allowed me to see the contents of the display context.

EDIT: To use glBlendFuncSeparate, with some googling it looks like I only have to enable GL_BLEND ( but the only place I saw that was on a german Wikki, and I don't speak German... ) so is that correct? Or so I have to enable a different token?
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Rendering Heightmap using texture data ardowz 3 932 Feb 25, 2014 10:25 AM
Last Post: SethWillits
  FBO rendering to GL_ALPHA texture Fenris 11 5,875 Jun 4, 2009 03:18 PM
Last Post: Fenris
  bug in OpenGL setup for NSOpenGL subclass (I think) backslash 2 3,698 Jul 18, 2007 01:10 PM
Last Post: backslash
  HELP!!! Simple glOrtho problem! Marvin 3 3,940 Jun 27, 2007 10:23 AM
Last Post: Marvin
  xCode/SDL Setup hammonjj 2 4,719 Mar 2, 2007 06:37 AM
Last Post: hammonjj