how can I sort by texture when I already have to draw back to front?

Started by
11 comments, last by EDI 19 years, 5 months ago
So in my isometric game (using d3d9) I need to a) minimize the number of texture switches b) draw all my objects back to front so that everything overlaps properly. If I draw everything back to front, then theres the possibility that the texture would need to be switched almost every tile, resulting in 1000+ texture changes. If I try to minimize the number of texture changes by sorting by texture, then the scene doesnt draw back to front, and it doesnt look right. I cant use the z-buffer because my textures use alpha blending and semi-transparency. And Im also using my z coordinate so I can zoom my 'camera' in and out. It would be possible to put multiple images into one large texture, and then just render the right image by changing the vertex texture coordinates. The problem is that some graphics cards only support 256 x 256 textures, and even on modern cards I could never fit all my images onto one texture. I would always need several different textures, and if the scene was set up so that images from one texture needed to be next to images from another texture, we still get lots of switching back an forth between those two textures. Does anyone know an efficient solution to this problem? or am I just stuck with lots of texture changes? what is considered the maximum number of texture changes per fram e these days if you still want decent framerates?
Advertisement
It's my understanding that the 256x256 limit is all but erradicated, and should not become a design limitation. [IIRC a card with such limitations has not been produced in a decade, someone more knowledgable please clarify?]

You've already touched upon probably the easiest method, simply grouping images onto one texture. It doesn't have to be all the images, but even putting 8 similar images on 1 texture will cut down the switches 8 times [assuming images can be grouped easily].

Another that might help is by doing layered rendering. This is a little more complex.

So assuming a tile based game like civilization. Instead of drawing the land, then the resources, then the city, then the unit, then the effects and -THEN- moving to the next tile and doing the same thing, you draw all of the land, then all of the resources, then all of the cities... and so on.

What that gains you is the ability to group images onto textures more efficiently. In the first, you would likely have to switch textures on each draw, since terrain will usually be on one, then cities another... In the 2nd, since all of the possible terrains can be fit upon one texture sheet, you can draw them all without a switch or later loading the texture again.

And don't worry so much about the texture switching rants around here. Even doing a switch for each and every tile will still push a few thousand tiles on relatively modern hardware at decent rates. More than enough to make decent games without worrying about infrastructure.

ok, thanks. What size should I make my textures then? I've searching for a site that compares max texture size and other capabilities of popular video cards, but havent found anything.
Quote:Original post by elpool
ok, thanks. What size should I make my textures then? I've searching for a site that compares max texture size and other capabilities of popular video cards, but havent found anything.


Eh, dunno that one. I've just been making them the size they needed to be to fit what was needed. I've loaded 1600x1200 and it worked fine [albeit with a slight delay at loading time]
1024x1024 is available on all cards you care about.
2048x2048 or higher is available on all cards being sold now.

The bigger question is: are DXT compressed textures available? The answer is "yes" for all Radeons, all GeForces, and all Intel Extremes, but "no" for TNT2 and ATI Rage series. DXT compression saves TONS of memory, and makes texture loading faster (because you load pre-compressed textures from disk, which means less I/O).
enum Bool { True, False, FileNotFound };
Don't sweat textue changes so much. They're to be avoided, but not feared. Grouping by texture is obviously a huge plus, but putting 20 or so tiles into a single texture will probably have even larger gains. Combining the two will have the biggest gains of all.

I'd worry more about calling 1000 unique DrawIndexedPrimitive (or whatever your API of choice is) calls with matching SetTextures, rather than buffering up a bunch of vertices at a time.
Quote:Original post by elpool
ok, thanks. What size should I make my textures then? I've searching for a site that compares max texture size and other capabilities of popular video cards, but havent found anything.


You can probably query the maximum texture size supported by the hardware (never used d3d but opengl supports this) and then generate those tileset textures by merging smaller textures together. But keep in mind that larger textures can slow your game down (more than smaller ones) when they don't fit in the card's memory.

Example: You fit all your tiles to two textures but only one of them fits the memory. Number of texture changes is reduced but those changes become more expensive because textures are moved between the video memory and the main memory. If you use smaller textures there are more changes but they are cheaper (less data to transfer if textures have to be moved or the wanted texture is already in the video memory).

I'm not expert in video cards and stuff so feel free to point out my mistakes :)
You probably don't need to alpha blend everything. For stuff that is opaque, or has hard edges (every pixel is either on or off) you could use the z-buffer. Just draw the opaque stuff first, and then turn off depth writes when you draw the semi-transparent stuff. In addition to saving on texture switches, you probably want to be able to draw your primitives in batches.

As suggested earlier, drawing the scene in multiple passes of similar objects can also allow you to group your textures better. If you are able to draw, for example, all your background tiles in one pass you could have a texture holding all the tile artwork needed for a scene. Of course if you can't break up your scene this way (if background tiles can occlude other sprites) then this won't help. But at least most of your background tiles are probably opaque so you can use the depth buffer here.

You could make it batch them on the fly, have your drawing functions generate the vertices then when it comes time to render. Use the DrawPrimitives to draw textures used by consecutive triangles. Sort of like Run length encoding (RLE) but run length batching instead. That way its efficient whenever it can be and when you can't batch it resorts to changing textures. You would still want to keep your art in the back of the scene in one group of textures and foreground stuff in another group to minimize switching.
yeah I guess I'll just have to experiment using different texture sizes.

I'm already using two rendering passes, drawing all the floor tiles first because nothing is ever behind the floor tiles, and then drawing everything else. I'm not using anything like an outdoor terrain, but a more urban/indoor environment, meaning all my walls, objects, and characters have to be on the same level.

the upside to this I guess, is that if my line-of-sight algorithm does its job, then if the player is in an office building, I wont need to switch away from the office texture very often.

-------------------
Jarski said:
You can probably query the maximum texture size supported by the hardware (never used d3d but opengl supports this) and then generate those tileset textures by merging smaller textures together. But keep in mind that larger textures can slow your game down (more than smaller ones) when they don't fit in the card's memory.
-------------------

I was thinking of doing some sort of surface packing like this, because then it would be really easy to change texture sizes for optimal performance.

Anyone know how I would go about doing this? would I just load the files into surfaces, then lock the surfaces and copy the bits? Would this work with .dds files using DXT compression? and how would something like this affect things like mip maps, etc.?

thanks for the help

This topic is closed to new replies.

Advertisement