Sign in to follow this  
RealMarkP

Need Critique On Rendering Data Structures

Recommended Posts

RealMarkP    216
I'm having a hard time trying to manage my rendering. I looked into Scene graphs, and determined they might be a bit too complex for my task. I decided on a small transform graph and Octree combo. Take a look at my uml diagram and tell me what you think. Some notes: - Transform graph handles static objects as well as dynamic models with bones. - Renderables contain instances of Vertex and Index Buffers. - A renderable is passed in a shader which it sets it up for it's own rendering process (User controlled). - The renderer has a list of renderables which it iterates through (no sorting, atm). - The Octree is passed in a Frustum, AABB, Sphere, or ray and spits out a list of 'hit' objects. This can be used for rendering or picking alike. My questions are: - Are there any problems that jump out at you? - What's the best way to incorporate sorting into this architecture (By shader, texture, or other)? - How could a state sorting (or push/pop) render graph be incorporated? Be as meticulous as you want. What I'm looking for is constructive feed back and not 'OMG this sucks' comments. Thanks to everyone that replies!!

Share this post


Link to post
Share on other sites
bzroom    647
Quote:
Original post by RealMarkP
- What's the best way to incorporate sorting into this architecture (By shader, texture, or other)?


Typically this is done with a render queue. When the renderable graph is queried and iterated, the renderables are pushed into some kind of render queue container. This container is either sorted on insert, or passed off to another thread and sorted as a whole.

Sorting usually goes by:

1.) Render target
2.) Opaque/Transparent
3.) Shader
4.) Texture

And i'm always curious where vertex buffer fits in. Sometimes i think it should be before the shader sort, and sometimes i think it's after texture, it depends on how you store stuff in the vbo. if the VB is all of one material then sorting it with material is pretty much the same as sorting by the material.

So a sorted list may look like this:


Rt1
- Opaque
- Shader 1
*obj1
*obj2
- Shader 2
*obj3
- Transparent
- Shader 3
*obj4
*obj5
Rt2
- Opaque
- Shader 1
*obj 6
- Transparent
- Shader 3
*obj 7
*obj 8



//There are fancy bit hacking tricks to make this a single integer compare.
bool DrawCall::operator < (const DrawCall &right) const
{
return (RTID < right.RTID)
|| (Opaque && !right.Opaque)
|| (ShaderID < right.ShaderID)
|| (Opaque == Depth < right.Depth);
}

Quote:
Original post by RealMarkP
- How could a state sorting (or push/pop) render graph be incorporated?


Your states could be appended to the sort list i provided. You'd just give each property a particular sort order and include that in your operator < (). My renderer has one function SetRenderState(RenderState, bool) which is the only point of access for the renderstates. Inside here you could check if the state was already set (if it's a particularly expensive state to set). Although i think the api takes care of this for you now days. At least with the late model d3ds.

Share this post


Link to post
Share on other sites
RealMarkP    216
Quote:
Sorting usually goes by:

1.) Render target
2.) Opaque/Transparent
3.) Shader
4.) Texture

Good to know. I would never have though to sorting by Rendering Target. A side not one the Opaque/Transparent step. Figuring out Back to Front rendering might get a bit hairy in the Transparency section. I would think that when Items are added and they are transparent, it would get put into a sorted list of some sort. Data structure wise this might be easier then I previously thought.

Quote:
And i'm always curious where vertex buffer fits in. Sometimes i think it should be before the shader sort, and sometimes i think it's after texture, it depends on how you store stuff in the vbo. if the VB is all of one material then sorting it with material is pretty much the same as sorting by the material.

I would think a vertex buffer would be dead last, after the texture sort. Even then, they don't have to be sorted, just rendered when the above 4 steps have been sorted.

EDIT: New uml diagram.

[Edited by - RealMarkP on April 30, 2009 1:52:57 PM]

Share this post


Link to post
Share on other sites
bzroom    647
It just depends, what's going to take longer, copying a huge vertex buffer over and over, or switching materials over and over, it may come out benefitial to switch materials more often than VBs, only profiling would tell.

Also, even if they're at the end, they should be sorted, to minimize needless switching.

Ultimately (it's most intuitive), i put the VB at the end of the list.

If the depth is encoded in each drawcall when it's added then they can be sorted later with the main sorting routine. In my example I sorted opaque objects front to back while transparent objects are sorted back to to front.

[Edited by - bzroom on April 30, 2009 3:19:50 PM]

Share this post


Link to post
Share on other sites
RealMarkP    216
Thanks for the comments, they were very helpful.

Using my new design, I have decided to manage the scene in the following manner:

1. User populates scene with a bunch of objects, some static, some dynamic. The system plugs it into an Octree for culling and into a Transformation Graph for logical arrangement. It also puts an entry into the RenderingChain which sorts it by Rendering Target, Shaders, Opacity, and Textures.

2. When an object is transformed form one location to another, the first thing to kick in is the Transform Graph, which updates the locations of all child objects. Secodnly, the Octree is updated when those objects move, to put them into the correct spatial node.

3. The Octree kicks in and culls the objects based on collision with a Frustum. Turns a 'Visible' flag on when objects are inside the frustum.

4. The renderer runs through all objects in the scene (already sorted) and only renders the ones that are visible.

Comments?

Share this post


Link to post
Share on other sites
RealMarkP    216
Quote:
Original post by stupid_programmer
How do you handle meshes with multiple textures? Multiple VBs per mesh or something else?

Each renderable has a pointer to a shader, which it knows how to set up. Therefore if the shader does multitextureing, the renderable derivation will know how to plug multiple textures into it. Same goes for multiple vertex buffers. But you raise a good question, how does one sort textures when multiple textures are involved?

Share this post


Link to post
Share on other sites
Heh...I ask because I am curious myself. My current engine I got around it by just requiring that every game model only have one texture on it.

The way I thought about it is to have each texture assigned to a material that has render settings and needed shaders. Then all the tris assigned to that material go in their own VB. And a 'mesh' is just a collection of VBs. This way I think you could have multiple textures and have each piece go through the sorting.

Share this post


Link to post
Share on other sites
Aph3x    288
In your new UML diagram, I don't think a Model 'is a' SceneObject? It's not really a 'scene object' or 'cullable' until it's in the scene graph?
Shouldn't your concrete object 'have a' model instead? That works better in my mind...

For the rendering question raised by stupid, I've been thinking about this myself recently: when an object 'draws' itself it sends off its polys to a central renderer which stores them by pertinent hashed 'material' state (and can e.g. sort blended polys) then draws everything in this sorted state, minimising state changes and allowing separate materials (and :. textures) on a single mesh. Maybe put each material in a VB at this stage.

The only thing stopping me doing this so far is the lack of mechanism to flag my 3d model assets with per-poly materials in a satisfactory way (using Blender, which lacks nice user data specification).

Share this post


Link to post
Share on other sites
RealMarkP    216
Quote:
Original post by Aph3x
In your new UML diagram, I don't think a Model 'is a' SceneObject? It's not really a 'scene object' or 'cullable' until it's in the scene graph?
Shouldn't your concrete object 'have a' model instead? That works better in my mind...
Actually, I updated my design a bit more and Model is no longer derived from SceneObject. Rather, a new object will be derived from Model and from SceneObject. This keeps the Model clean from coupling as a data structure (Because the model does not contain any rendering specific Data structures, only serializable data - triangles, joint list, etc).

Quote:
Original post by stupid_programmer
The way I thought about it is to have each texture assigned to a material that has render settings and needed Shaders. Then all the tris assigned to that material go in their own VB. And a 'mesh' is just a collection of VBs. This way I think you could have multiple textures and have each piece go through the sorting.

Interesting idea. I believe the Irrlicht engine does it this way. Their Material class encompasses almost everything (render states, textures, texture ops, lighting, etc) but it doesn't encapsulate Shaders. I'm also debating if this is the best way to design something - Material based Renderer.

Share this post


Link to post
Share on other sites
bzroom    647
I wouldn't derive from mesh and scene object, though I know that's not really the scope of this thread. I'd suggestion composition. (i got a little carried away here)


struct Shader
{
apispecific program;
ShaderPropDefs properties;
};

struct Material
{
shared_ptr<Shader> shader;
ShaderProperties commonProperties;
};

struct MaterialInst
{
shared_ptr<Material> material;
ShaderProperties uniqueProperties;
};

struct Mesh
{
IBEntry indices;
VBEntry vertices;
};

struct BonePallet
{
std::vector<Transformable*> bones;
};

struct RenderableEntity
{
shared_ptr<Mesh> mesh;
shared_ptr<MaterialInst> material;
shared_ptr<BonePallet> bones; //material may expect these
shared_ptr<Cullable> culler;
shared_ptr<Transformable> transform;
};

struct Player
{
shared_ptr<Transformable> myTransform;
shared_ptr<MaterialInst> myMaterial;

RenderableEntity graphics;
NetworkedCharacter physics;
ScriptingAgent logic;
};


[Edited by - bzroom on May 4, 2009 6:59:39 PM]

Share this post


Link to post
Share on other sites
RealMarkP    216
After further reading, I'm thinking on this final sorting criteria (Most Expensive, to Least):

1. Render Target
2. Opaque or Transparent
3. Back-To-Front (Transparent), Front-To-Back (Opaque)
4. Shader Change
5. Texture Change (Different Format, Size)
6. Texture Change (Same Size & format)
7. Shader Constant Change (Non-Texture: VBuf, IBuf, Floats, etc)

The Front-To-Back/Back-To-Front sorting thing really has me stumped. For transparency it has to happen, but for opaque objects, maybe I can put that somewhere else (such as after shader or texture change).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this