Archived

This topic is now archived and is closed to further replies.

Sorting textures/multitextured objects?

This topic is 5540 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''ve been wondering... Since one is supposed to render everything sorted on its texture, to minimize texture changes, how is it possible to encapsulate things in your scene in objects? Take this simplified example, for instance, suppose I have a terrain with a grass texture, some rocks here and there with a stone texture, and some trees, consisting of a trunk (some wood texture) and a sphere on top, with a leafy green texture. The logical choice would be to make a terrain class, a rock class, and a tree class, and then have instances of these classes draw themselves. So:
  
for (int i=0; i < numTrees; i++)
  TreeObj[i]->Render();

for (int i=0; i < numRocks; i++)
  RockObj[i]->Render();

TerrainObj->Render();
  
That would render all the trees, then all the rocks, then the terrain. However: The tree consists of a sphere with a green texture, and a trunk with a brown texture. So if I had 20 trees, the texture would change 40 times just to draw the same tree. Now, the obvious solution would be to either use one big tree texture for the object, but is that really a good idea? Wouldn''t it be a tremendous pain to get the texture aligned right on the object? Especially with more complex objects? The other idea would be to loose the tree object, and make separate trunk and leaf objects. But that sounds like a really bad idea. It would completely loose the object oriented design benefits, and with very complex objects, would result in a maze of miniature object instances. What to do?

Share this post


Link to post
Share on other sites
There are many different solutions to this problem, depending on your programming style. One way to address this in an "object" way is to make all of your class draw themselves to different vertex buffers depending on their texture. Then, you render the buffers X number of polys at a time, where X is the most efficient number balancing CPU and GPU usage. In an world editor, you''re doing this over and over and it''s slow; in your app, you do it once (unless your geometry changes dynamically) and it''s pretty fast.

Of course, that means that you''ll need a number of vertex buffers equal to the number of textures you use, and that''s not the most efficient. You could do the same thing with index buffers by storing all of your geometry in one vertex buffer and having your objects draw their indexes into the appropriate texture-based index buffer.

Or, you can do what most of us probably do which is be as efficient as possible within an object using drawsubset and dealing with the textureswap hit, while maxing out what we can (such as terrain) using whatever method we can.

Or, you can create custom textures for each object such that your tree has one texture instead of 2, per your example. Same with terrain - one big texture with subtextures for ground, grass, etc.

See what I mean? Lots of solutions and the best one for you depends on your style, patience, and the application ; )

Share this post


Link to post
Share on other sites
Hey, thanks a lot. That''s given me some ideas to work on. I suppose the single vertexbuffer/multiple indexbuffer idea would be the most efficient method. Just dealing with the textureswap hit, although probably unavoidable at times, doesn''t seem like the elegant thing to do.

One thing puzzles me, though. This is probably just a language difference, but I don''t understand what you mean with "Then, you render the buffers X number of polys at a time, where X is the most efficient number balancing CPU and GPU usage."

What do you mean by that? Wouldn''t I just set a texture and then render the appropriate buffer once, and then move on with the next texture/buffer?

Share this post


Link to post
Share on other sites
You can do that, and it will probably work fine. There''s a debate going on on various boards about the number of vertices/polys that should be batched with one call of DrawWhatever. It involves trying to balance the amount of work the CPU is doing vs. what the GPU is doing. You can pass a huge buffer to be drawn, but the GPU can only draw so fast.

Ideally, you want the CPU to be sending data (or requests) up to the GPU such that when the GPU is ready for more, the CPU is just sending the data, essentially balancing the draw time of each request with the time it takes the CPU to build the request.

Honestly, I don''t understand this enough at a hardware level to know exactly what''s really going on, but I do notice a difference if I send 1 buffer with 20,000 vertices up vs. 20 buffers with 1,000 vertices.

Share this post


Link to post
Share on other sites
what i''m going to do for my renderer is instead of having the ''Render'' method render it will push that object onto the correct linked list for its texture, render states, etc. so i end up with a bunch of stacks of objects all with the same texture/render states/etc. then i just set the textre/state and render that stack, go onto the next stack. i''m not sure if it will work yet, since i''ve not gotten there yet.

Share this post


Link to post
Share on other sites
Well, lets say that I have an object (like your tree) with two different textures. I could really store that as one object with two different meshes.

Tree
/ \
Truck Leaves


Now my rendering engine could accept pointers to meshes to draw. In other words, at run-time, make a linked list (or vector) of meshes and then sort them by texture. Then, if you have some way to say that they are equal or not-equal, you can sort them based on the object geometric data as well to minimize vertex buffer changes. Now I simply draw my list by changing a texture, and then drawing all the objects in the list until I come to another one with a different texture.

But this will create a tradeoff of course. It may be that changing vertex buffers or changing the vertex/pixel shader is your slow point. It really all depends on your game and what''s going on. In the NVidia docs, Mr. Huddy once mentions that a certain nameless game found that sorting by Shaders was the way to sort for optimial performance.

There is no real right/wrong way with GPU''s anymore... they do way too much stuff now. It all depends on your situation. Lots of profiling and trying lots of possible methods is the only real way to optimal performance. While there are people here who can give little bits of advice, the only real way is to try and see.


As a little example, in a certain project I''m working on, uploading vertices to a dynamic vertex buffer was my slow point. It was a LARGE terrain engine, too big to store in non-dynamic vertex buffers. So my only solution was to upload all the vertices each frame. No amount of texture/shader sorting was gonna change the fact that an AGP4x bus is only so fast.

Anyway, good luck. Don''t be afraid to implement all the methods... it''s the only way to try and maximize performance. Either that or give your code to someone and let them do it for you... but hey, that''s no fun for anyone.

Share this post


Link to post
Share on other sites
quote:
Original post by Bas Paap
That would render all the trees, then all the rocks, then the terrain. However: The tree consists of a sphere with a green texture, and a trunk with a brown texture. So if I had 20 trees, the texture would change 40 times just to draw the same tree.



What you can consider is not having the ''draw'' that you mention mean a call to drawprimitive directy, but instead your own class that takes in objects, and places them in lists sorted by texture, then when you''re done, this class efficiently draws everything using the texture sorted lists of polygons.

Share this post


Link to post
Share on other sites