Sign in to follow this  
ATC

Constructing Render Operations (...and "InstanceOps"?)

Recommended Posts

ATC    551
Hey guys,

Things are going quite well for me and my engine. It's now actually [i]rendering [/i]for the first time and spitting out its first-ever pixels (for this actual project/solution, which is the first commercial version WIP, that is...the numerous prototypes over the past 4+ years have done a lot of things of course). But I'm wondering how I might improve things. FYI, I'm adhereing to the data-driven design philosophy introduced to me by swiftcoder, Radikalizm and a few other senior Gamedev members. More information about the engine and the struggle leading up to this point can be found [URL="http://www.gamedev.net/topic/630881-platform-agnostic-renderer/"]here[/URL] in my thread called "Platform-agnostic renderer".

As this is a platform and API-agnostic engine, I'm having to make [i]very [/i]difficult design decisions on how things are glued together and how things work. I'm at the point of making another such decision: the best way to generate "RenderOps" from 3D objects and the best way to implement instancing. Keep in mind we're not talking about how to draw instanced geometry in DirectX/OGL or anything such... I [i]know [/i]how to do that and that information can be found in SDK documentation and online tutorials as well. We're talking about the design/structure of things to keep the engine tidy, efficient, loose coupling between components and, maybe most importantly, platform and API agnostic... This is an architectural discussion rather than a technical discussion, in other words...

Anyway, the way things are now we have, in essence, an abstract renderer interface/object which accepts render operations (aka "RenderOp" class instances) to get the necessary data to draw geometry. In pseudo-code:

[source lang="csharp"]public class RenderOp
{
public IMesh MeshData { get; set;}

public Material Material { get; set;}

// also contains transformation/other data
};

public class Renderer
{
public abstract void Draw( RenderOp op );

// this is simplified for sake of example
};
[/source]

So the first question is: what is the best way to generate RenderOps to actually [i]send[/i] to the renderer? For instance, should some sort of "SceneManager" class be responsible for stripping the data out of all drawable objects and passing it along to the Renderer? Should drawable objects implement some interface like "IDrawable" with a "Draw" method, and send their RenderOps to the Renderer (seems less than ideal to me). What other ways might this be done? The SceneManager idea seems to be the most sound to me, as it can implement sorting, culling and all sorts of other things and keep objects and the renderer completely decoupled.

The next question is how to handle instancing. The idea ocurred to me that I could possibly use the same concept of a "RenderOp" and create a new type called "InstanceOp". But if I do that, how might things be "glued together"? Should an InstanceOp be an optional field within a RenderOp? Should the two be two totally separate things; might they inherit from the same interface/abstract base, and let Renderer handle them for what they are (e.g., if(op is RenderOp) or if(op is InstanceOp)... then take appropriate action)?

Hopefully my questions make sense. If they do I would greatly appreciate some suggestions on how to piece this together!

Regards,

ATC

Share this post


Link to post
Share on other sites
zacaj    667
In my engine, all objects implement IDrawable and provide a draw method, which will add RenderOps to a stack, which the Renderer then culls, sorts (using a method similar to http://realtimecollisiondetection.net/blog/?p=86), and calls draws the RenderOps. I decided rather than having RenderOp provide multiple implementations I would just provide a single class for all rendering options (not many, currently just a drawElements and a drawArrays, signified by whether the indices member is filled), which the Renderer then takes care of rendering.

I haven't gotten to instancing yet, but my plan is to have the sort step recognize RenderOps with the same mesh/texture and have it automatically instance them together

Share this post


Link to post
Share on other sites
ATC    551
[quote name='zacaj' timestamp='1348516333' post='4983333']
I haven't gotten to instancing yet, but my plan is to have the sort step recognize RenderOps with the same mesh/texture and have it automatically instance them together
[/quote]

That sounds like a clever idea... I hope the real-world performance is worth it after the penalty of searching/sorting. I'll look into that.

Still, there is much to consider and think about... I'm thinking the SceneManager architecture will probably work best for me; I could even use a hybird of a Scene Manager with IDrawable objects, I think. Edited by ATC

Share this post


Link to post
Share on other sites
zacaj    667
[quote name='ATC' timestamp='1348518873' post='4983347']
[quote name='zacaj' timestamp='1348516333' post='4983333']
I haven't gotten to instancing yet, but my plan is to have the sort step recognize RenderOps with the same mesh/texture and have it automatically instance them together
[/quote]

That sounds like a clever idea... I hope the real-world performance is worth it after the penalty of searching/sorting. I'll look into that.
[/quote]
It seems fairly trivial to me. If you're sorting your RenderOps using some other method (like the one I linked) adding a sort by mesh stage isn't very complicated, and at that point you just need to do a check if the next RenderOp has the same mesh as the current one.

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