[…]
The most straightforward method is in fact very simple: Just use
OpenGL as a 2D rendering API! Render each tile as a quad (or if
you’re going to use vertex blending effects, two triangles, as you
can’t know for sure how a quad is split up).
Ok, this seems easy to understand. Instead of one big quad covering all
the screen, I have several small quads which will be arranged side by
side. Fine. However, I lost it when you mentioned using vertex blending
effects. Why would quads not do in such scenario?
Well, fist of all, the fundamental reason for the problem: Most cards
accelerate only triangles, so anything with 4+ vertices will have to be
split up into triangles.
Vertex blending effects usually involve setting up different color and
alpha “modulation parameters” for each vertex of a polygon. OpenGL will
interpolate the parameters across the polygon. (If all vertices have the
same color and alpha, there’s no problem, as the interpolation will
effectively be a NOP.)
The problem is that the result may differ slightly depending on how the
card actually renders the polygon. In the case of a quad, there are two
ways to split into triangles - and you can’t know for user which way the
current driver will do it.
So, by explicitly passing triangles, you can’t really avoid the problem,
but at least you can control how the splitting is done.
[…]
The most serious issue with this method is that it’s a bit
complicated and somewhat expensive to get it to work with sub-pixel
accurate smooth scrolling. Even pretty old cards will do subpixel
accuracy for the texturing, but cards without h/w antiaiazing will
just round the screen coordinates of the vertices to the nearest
integer pixel. That is, you get hard and inaccurate edges, even if
the textures are filtered.
Humm, I am not sure I have got this one. First, what do you mean by
subpixel accuracy?
Interpolation of textures to simulate positioning of graphics with higher
accuracy than one pixel.
I thought that pixels were as fine as you could go
in terms of granularity…
They are - if you can dictate the video refresh rate, and design the game
to have suitable scrolling speeds.
However, in real life, that’s more or less futile. You don’t always get
the refresh rate you ask for (if you can ask for one at all!), and
perhaps constant speed scrolling isn’t all that exciting in the long
run…
So, to achieve extremely smooth scrolling and animation, you’ll need to
calculate the scroll and sprite positions for each rendered frame based
on the actual time that frame will be displayed. The closer to the exact
positions you can get the rendered results appear, the smoother the
animation.
Or do you mean that, because of the screen
coordinates rounding, the texture mapping loses precision, resulting in
the inacurrate edges that you mention? I am just guessing here… Would
you be so kind to explain it a bit further?
Well, the problem with the edges is that most 3D cards will render
textures with sub pixel accuracy - but they won’t interpolate or
antialias polygon edges!
That is, if you move a tiled background without any special precautions
taken (and no FSAA) very slowly, the graphics will appear to "float"
smoothly (rather than “jump” one pixel at a time, as it normally does in
2D games) - BUT, the edges will still jump! That kind of ruins the ultra
smooth scrolling effect, obviously…
To get around that, you need to use either RGBA textures, or
multiple quads per tile + vertex alpha blending, effectively
implementing antialiazing on the application level.
Would that not be too slow? I mean, if I had, say, 4 or 5 quads per
tile, would that not mean that I would have 4 or 5 times more
processing per tile? Would that be acceptable?
That depends on you hardware. A hot machine with good drivers can be
capable of pushing thousands of polygons per frame at full frame rate, so
there might no actually be a problem.
Of course, it’s nice if you can get everything work even on low end 3D
accelerators, but at some point you simply have to turn some of the eye
candy off, and lower the rendering quality. (Which may include disabling
"Ultra Smooth Scrolling".)
A much more powerful, but also more complicated method, is to use a
hybrid of the two methods you suggested, and my method;
- Set up a small map, just one tile larger than the screen,
with large tiles. (Say, 64x64…256x256, depending on screen
resolution.) I’ll refer to this map as the “virtual screen”.
Do you mean that, for instance, in a horizontal scrolling setup, with
640x480 resolution and 64x64 tiles, I would need a 704x480 map (i.e.
one extra column of tiles)?
Yep. (If you have some experience with hardware scrolling on the Amiga,
C64 or VGA Mode-X, the extra row and column correspond to the “scroll
border” you’ll need unless you’re going to refresh the edges after every
scroll position change.)
[further description of the advanced technique]
I will skip the advanced technique for now, until I feel more
comfortable with the basic concepts.
Yeah, get started rather than scared off!
Of course, the same issues apply when it comes to sub-pixel accurate
scrolling; tile edges must be taken care of.
However, in this case, there are some shortcuts! As the virtual
screen tiles are specifically rendered to be combined in only one
way, there won’t be any tile matching issues that can screw up
texture filtering around the tile edges. All you need to do is
provide a border of extra pixels from surrounding tiles, and the
texture filtering will work correctly.
Here we are with the subpixel accuracy thing again. What happens at the
tile edges after all?
The 3D card will have to grab some extra pixels outside the actual
texture area, for the interpolation. Normally, those pixels will be
black, transparent or whatever - while they should contain graphics
from adjacent tiles to produce proper results!
If you don’t do anything about this, but just pass float vertex or
texture coordinates, you’ll get thin, “flickering” lines in between
tiles, rather than the desired illusion of a solid, contigous image.
Why will an extra border solve the problem?
Because you can fill that border in with pixels from the adjacent tiles,
so that interpolation will “chain” as if you had rendered the whole
screen as one quad.
BTW, you may have noticed that this is not a problem along the line along
with a quad is split. That’s because the line is in the middle of valid
texture data, rather than bordering to the void space outside the
texture. (Or “wrap limit”, if you disable texture clamping.)
I
know you must be thinking: “Quit being lazy and go try it to see for
yourself.” You are right, I should do that, and I will. The problem is
that I am still a little far from getting to that point and believe som
clarifying would be satisfying enough at this point.
Don’t worry! I wouldn’t blame you for going “Huh!? What’s that
flickering?” even if you did try it yourself. 3D accelerators can seem
to do the strangest things, unless you have a solid understanding of
their inner workings.
//David Olofson — Programmer, Reologica Instruments AB
.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------------> http://www.linuxdj.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |
-------------------------------------> http://olofson.net -'On Tuesday 29 January 2002 05:15, Ney Andr? de Mello Zunino wrote: