Where to include the render() function?

Started by
6 comments, last by induster 16 years, 2 months ago
Hi, I'm a week into directx and limited with c++ header organization. I have a directx class and a sphere class. Where is the normal placement of the render function? Right now I'm passing my sphere information into a directx::render() function to display the sphere. My question is should the render() stay in a directx class or be included in every object class that needs to be rendered?
Advertisement
People have argued it either way, so there are pro's and con's however you choose to look at it.

From an OOP perspective then render() should probably exist as a member function - a sphere knows how to render itself, whereas the 'owner' class shouldn't really know this information (ignoring the fact that a sphere is very simple).

The flipside is that passing a IDirect3DDevice9 pointer to your Sphere::Render() method can expose the sphere implementation to a lot of global states and starts to break down loose coupling as it could, potentially, interfere with other parts of the application. Remedying this could see the 'owner' assume more control over how the object is rendered which can start to go against my previous statement and break encapsulation.

It is common to optimize state changes for a D3D9 application and the context required for this tends to be at the global/manager level which would mean that this global rendering manager needs to have some control over the low-level implementation details of rendering each object. For example, it could better arrange rendering of 20 spheres due to knowing that you don't need redundant state changes yet each of those 20 instances shouldn't really know about each other and if written correctly would re-configure the device each time.

A possible way around this is to have some sort of 'display list' where each object can append commands to a buffer that your manager can then go and re-order as it sees fit.

It's a fun problem to solve [grin]

Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

Thanks for the reply :)

I decided to build a class to manage all the rendering. The more I imagine this I think each sphere should be able to render itself. Where it breaks down in my mind is when you'd want to render multiple spheres to the screen. If each one does it's own render sequence, I get flickering on the screen because it's wanting to do seperate windows over and over. How would you solve that issue?
I'd put the render() function in the sphere class. The renderer doesn't need (or want) to know how to render a sphere or any other object. All the renderer does is expose methods to draw different stuff - for example a DrawMesh() function.

It would be the sphere's responsibility to generate/load a mesh, and submit that mesh with the correct radius to the renderer. This way, the sphere knows nothing about the internals of the renderer, and the renderer knows nothing about the internals of the sphere. All that's needed is that the sphere keeps a reference or a pointer to the renderer, so that it can submit the necessary draw calls.
NextWar: The Quest for Earth available now for Windows Phone 7.
Quote:
I get flickering on the screen because it's wanting to do seperate windows over and over. How would you solve that issue?


Huh? You should do all your "drawning" then flip the screen. Not sure how you get flickering unless you have vsync off or something.

I don't pass in the IDirect3DDevice9 pointer but I do allow the object to query for it when its created using the engines internal messaging system.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

The flicker was from me drawing more than one scene in the same loop. Each object had it's own begin and end scene sequence. Would you mind expanding on how to query the device pointer when an object is created?
I would have 3 classes:

One is the Sphere class, it is concerned with all that is spherical. It has a method like getStateForRendering() which returns another class, call it a RenderOp.

A RenderOp is concerned with the storage of renderable data. It has attributes for pointing to vertices, indicies, textures, etc.

The Renderer is concerned with using data from RenderOps to draw the scene. A renderer might have a method like: void render(RenderOp& op).

A simple render sequence for spheres might look like this:
for (int i = 0; i < numSpheres; i++){    myRenderer.render( spheres.getStateForRendering() );}

So what's so good about that?

Well now you can add another class, call it a RenderQueue. This class is concerned with collecting RenderOps and sorting them to minimise the state-changes and optimise the ordering of RenderOps.
The Renderer's render method can now be changed to: render(RenderQueue& ops)

With this new class the render process is a little more sophisticated:
for (int i = 0; i < numVisibleSpheres; i++){    renderQueue.addRenderOp( spheres.getStateForRendering() );}renderQueue.sort();myRenderer.render( renderQueue );
Yeah man. That's what I'm talking about good job!

This topic is closed to new replies.

Advertisement