Mailing Lists: Apple Mailing Lists

Image of Mac OS face in stamp
 
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 2D Games with OpenGL



(I considered taking this off-list, but the discussion is still relevant to GL. It's a bit long though, so apologies to those of you who already have enough to read!)

On Sep 17, 2004, at 9:26 PM, Lee Morgan wrote:
On Sep 17, 2004, at 9:39 PM, Alex Eddy wrote:
You don't necessarily need a Z buffer with 2D ortho content, if you just keep track of your draw order. You'll need it if you mix 2D and 3D.
So just keep track of my own layering and then draw in the proper order - could this really be faster than using a z buffer?

Yes, slightly, assuming relatively modest object counts (say, a dozen layers, one thousand sprites.) You trade per-frame CPU sorting for the depth buffer clear time and the per-pixel depth test comparison. These are very optimized on recent GPUs though so it won't make a big difference. You will however also save the VRAM used by the depth component of the framebuffer, which might be nice if you're already low on VRAM.



I assume I still get "free" rotation and scaling this way?

Yes, that's just manipulating transformations and texture filtering, unrelated to the Z buffer.



That's a funny texture depth-- usually you want 15/1 or 24/8. You really must use a standard BGRA format for paging speed.
It was a type-o. I was planning on using 15-bit textures with a 8-bit alpha.
The ideal for 15-bit textures instead of 24-bit was to keep down on the bandwidth of loading textures to the card (if / when paging does occur).
However since you say 24-bit is better on paging speed I suppose I should switch to that depth.

If you are intending to update textures often, then you should stick to 32 or 16 bpp BGRA. If you really want to have 15 bit RGB and 8 bit A, then you'll have to make one RGB texture and one A texture and use a second texture unit to mask. Also, be warned that while this will save you 8 bits per texel on the ATI cards, I'm pretty sure that the nvidia cards don't support an A8 internal texture format-- they will upconvert it to L8A8 behind your back, so you'll still be using 32 bits in VRAM. It's probably easiest to just use RGBA8 if you need 8 bits of alpha. RGB5A1 is fine if you don't care about the alpha, and well worth the VRAM saving if you can stand some color quality loss. (The ATI cards also support R3G3B2, if you really want to pack the textures in, but it looks pretty bad and isn't supported on nvidia.) You might also check out the DXTC compressed formats, many games use these. They're only appropriate for prerendered artwork that isn't being animated though.



One idea for the backgrounds, to expand on John's suggestion, is to keep a render-to-texture texture for each scrolling layer. These live in VRAM and are the size of the viewport (or smaller, for layers in the distance-- since you can scale them up with filtering for that out-of-focus look.) Keep your huge artwork/blockset textures in AGP, and draw strips from them into the layer textures as needed whenever you are actually scrolling. That way the paging is limited, and your onscreen compositing happens quickly (if you need to reuse a layer texture multiple times per draw, for blur effects or whatever.) This approach also bypasses some filtering problems that can happen if you render multiple quads directly into the viewport and you need to rotate or scale.
Sounds a lot like a wrapping blitter (such as the one used in SpriteWorld for those who are familiar with it).
So the basic idea is to only draw the area of the level which was just scrolled into view into it's appropriate part of a screen size texture, and then render the final texture and sprites to the screen. Makes for a very fast frame rate.

Yes, the render-to-texture texture is treated as a wrap-around work area (aka "toroidal scrolling region.") You draw into it wherever the newly exposed area is, and then blit then whole thing as four quads (or two, if you only need strict vertical or horizontal scrolling) to the viewport.



However when parallax scrolling comes in it is a bit less helpful. Since each frame the backgrounds would have to be offset differently - causing more or less the entire screen to be redrawn again.

It's exactly as useful. You keep a render-to-texture work texture for each parallax layer, and in each of these you only update a small portion every frame. But you composite them all stacked on top of each other, updating the entire viewport, every frame. (Unless you have a really good reason, you should throw away any old CPU-era notions you have about tracking dirty rectangle updates in GL. Just update the whole viewport, let the GPU do its thing.)


Note that overall, this method will end up using more total texture RAM than you'd need just drawing artwork layers directly into the viewport. But it minimizes AGP paging in the case where you have tons of artwork, by caching the currently visible layer portions into work textures in VRAM. And it allows you to treat each layer as a single texture, which eliminates filtering artifacts (that you would have, drawing a layer as i.e. a mesh of quads each textured from disparate portions of a texture altas) and enables various effects that might otherwise be costly (reusing the same layer multiple times, transforming a layer as a single object, etc.)

Also, I should probably clarify the difference between my using the term "render-to-texture texture", and John's talk about updating subtexture portions. In the simple case of 2D panning over huge artwork, all you need to do is glTexSubImage2D the appropriate areas (this is in fact what my simple TileScroller demo does.) But for more interesting games, you might want to creatively reuse artwork elements in your layers, so you really need a render-to-texture context per layer. Then you can draw from the artwork however you like; transforming, colorizing, etc the artwork pieces as you update the exposed portion of the layer. I'm sure you can come up with some interesting applications if you think about it.


Speaking of parallax scrolling what would be the best way to to create a tiled background using OpenGL? I don't think creating a quad the size of the level and just setting it's texture coords so that the texture repeats isn't the best way.

No, that actually won't work if you are using rectangle textures (which are, btw, required for optimal texture uploads) because REPEAT wrap mode isn't supported. If you simply want to fill the viewport with large repeating art just draw four (or two, for strict H/V scrolling) quads textured from the appropriate section of the artwork. However, if you want rotation, or your viewport scale does not match your texture scale (as may be the case when you need to support multiple display resolutions) or you otherwise need fractional texturing (for example scrolling by subpixel amounts) then you will have to watch out for filtering artifacts at the quad seams. In the render-to-texture approach I used in my Tilescroller demo, I handle this by faking REPEAT mode; I make the layer texture slightly bigger than it needs to be (2 texels wider, rounding up to the nearest 8 texels, and 2 texels taller) and copy any updated edge texels to the opposite border. But you can also check Apple's OpenGL Image sample code for how to handle it manually by overlapping the quad edges in the right way.



hope this helps (and you were able to read through my excessive use of parentheses)
-alex


_______________________________________________
Do not post admin requests to the list. They will be ignored.
Mac-opengl mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/mac-opengl/email@hidden

This email sent to email@hidden
References: 
 >Re: 2D Games with OpenGL (From: Alex Eddy <email@hidden>)
 >Re: 2D Games with OpenGL (From: Lee Morgan <email@hidden>)



Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2007 Apple Inc. All rights reserved.