Rendering passes

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
mandrav
Posts: 117
Joined: Sat Aug 27, 2005 8:29 pm
Contact:

Rendering passes

Post by mandrav »

Hi all,

I 'm currently adding some new functionality in Irrlicht, namely multiple rendering passes.
NOT of the kind E_SCENE_NODE_RENDER_PASS, which IMHO should be renamed to E_SCENE_NODE_RENDER_GROUP anyway (since it defines a rendering group, not a pass).

I 'm talking about multiple rendering passes and the ability for the user to use as many as needed.
Here's some sample code of how this would go:

Code: Select all

enum E_SCENE_RENDER_PASS 
{
    ESRP_DEFAULT = 0, // this is the first render pass (Irrlicht's current single pass)
    ESRP_PASS_1, // this is the next user-pass
    ESRP_PASS_2,
    ESRP_PASS_3,
    ...
    ESRP_PASS_15,

    ESRP_PASS_LAST, // just for counting; would someone need more than 16 passes?!?
    ESRP_ALL // special flag meaning "all passes" (invalid in ISceneManager::registerNodeForRendering())
};
Then, a couple of ISceneManager functions will have to be updated:

Code: Select all

// Scene nodes can call this more than once, to register themselves for different passes
virtual void ISceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDER_GROUP group = ESNRG_AUTOMATIC, E_SCENE_RENDER_PASS pass = ESRP_DEFAULT) = 0;

// The main loop, can choose whether to render all passes, or one of them
virtual void ISceneManager::drawAll(E_SCENE_RENDER_PASS pass = ESRP_ALL) = 0;
One ISceneNode function needs to be updated too so that the scene node knows which pass it is currently to render:

Code: Select all

virtual void render(E_SCENE_RENDER_PASS pass) = 0;
Finally, IShaderConstantSetCallBack update:

Code: Select all

virtual void IShaderConstantSetCallBack::OnSetConstants(IMaterialRendererServices* services, E_SCENE_RENDER_PASS pass, s32 userData) = 0;
Note that a render pass will "run" only if at least one scene node has registered for it.

So, if there's any interest for this, I can provide a patch for the SVN version. Also, please discuss about renaming E_SCENE_NODE_RENDER_PASS to E_SCENE_NODE_RENDER_GROUP.

Yiannis.
AlexL
Posts: 184
Joined: Tue Mar 02, 2004 6:06 pm
Location: Washington State

Post by AlexL »

I would be very interested in this either getting into the repository or you releasing a patch here on the forums to be applied to the source. Either way, great work from the sounds of it and I hope to see something soon :D
mandrav
Posts: 117
Joined: Sat Aug 27, 2005 8:29 pm
Contact:

Post by mandrav »

AlexL wrote:I would be very interested in this either getting into the repository or you releasing a patch here on the forums to be applied to the source. Either way, great work from the sounds of it and I hope to see something soon :D
Well, I have already finished it and in a much cleaner (a.k.a. less intrusive) way.
But I 've seen no interest so I just silenced :idea: .
sRc
Posts: 431
Joined: Thu Jul 28, 2005 1:44 am
Location: Salt Lake City, Utah
Contact:

Post by sRc »

well despite the fact that nobody posted in this topic the short time since you created it ( :lol: ) multiple rendering passes I think are talked about quite often around here. i'd use it, but i cant do any real shader work until i get my video card replaced

so if you got a complete implementation, post it up so we can get it integrated!
Last edited by sRc on Tue Aug 29, 2006 1:52 pm, edited 1 time in total.
The Bard sRc

Blog | Twitter
hybrid
Admin
Posts: 14144
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

At least it would help in the discussion :idea:
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

Post by IPv6 »

Hello! may i ask one question - can you explaing how they can be used? is it all about shaders only?

i wonder is this the same as to call beginScene-drawAll-endScene twice with modifying some vars that will be used by shader to render scene again in different way. or this is a question to use results (rendered picture) of the first pass in the second (offside question - may be endScene destroying something)? or something else? i`m just a noob looking for simple explanation for advantages of this technique from someone expirienced...
Ico
Posts: 289
Joined: Tue Aug 22, 2006 11:35 pm

Post by Ico »

Imagine a side scrolling game (or another 3d world).

You render your background first, apply blur to it.
Render the next background plane, apply blur again, etc.

On the end you can achieve some nice effects.

Another use (without shaders):

Draw your user interface using 3D elements (remember the 3D overlays/"order lines" in Homeworld (2)?) without having to worry that any other 3D object will cut trough your UI. :)

Or:
In a top down game: Load 1 MeshNode (for example a rocket), then render everything "below" the rockets in one render pass. then loop trough all rocket positions, move the rocket node and render it. At last render everything "above" the rockets. Again you don't have to worry about your "planes" (a rocket that should be below a spaceship). If you don't like rockets, replace them with stars, debris, flowers, decals or whatever you want. ;)
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

Post by IPv6 »

hm.. but can this be archived at current infrastructure? by registering node (custom of course) in several rendering steps -SOLID/SHADOW/etc, i know that this is not designed for this though
Ico
Posts: 289
Joined: Tue Aug 22, 2006 11:35 pm

Post by Ico »

I think that could get a little bit messy when you want to render something that drops shadows. :) And I think you won't be able to apply different shaders like mentioned above (at least it should be harder to be done).
IPv6
Posts: 188
Joined: Tue Aug 08, 2006 11:58 am

Post by IPv6 »

Aha! Thanks a lot for the explanations! :)
krama757
Posts: 451
Joined: Sun Nov 06, 2005 12:07 am

Post by krama757 »

I would love it if you released a patch with this. I've been trying to get some nice shader based grass into the engine along with HDR effects and Realistic Water in for a while now. But without multiple rendering runs its useless.

*Makes Puppy dog eyes* Please please release it? :)
mandrav
Posts: 117
Joined: Sat Aug 27, 2005 8:29 pm
Contact:

Post by mandrav »

Hey! I was away for a day, I come back and there's actually a discussion going on! Nice 8) .

Here's what I 've done:

I added the new enum I talked about: E_SCENE_RENDER_PASS.

I have added 2 new functions in ISceneManager:

Code: Select all

//! Returns the current rendering pass.
virtual E_SCENE_RENDER_PASS getSceneRenderPass() const = 0;

//! Returns the total number of render passes of the last frame.
virtual u32 getSceneRenderPassesCount() const = 0;
And 2 functions in ISceneNode:

Code: Select all

//! Registers the node for a render pass.
//! All nodes, by default, are registered for the first pass (ESRP_DEFAULT).
//! Here you can register the node for additional render passes.
//! \note You can't register for the special pass values: ESRP_ALL, ESRP_NONE and ESRP_LAST.
//! \param pass: The render pass to register for.
virtual void registerRenderPass(E_SCENE_RENDER_PASS pass);

//! Unregisters the node from a render pass.
//! You can't unregister the node if it's only registered to a single pass.
//! \note Unregistering from the special ESRP_ALL pass, unregisters from all
//! passes, and registers for ESRP_DEFAULT. Sort of a reset...
//! \param pass: The render pass to unregister from.
virtual void unregisterRenderPass(E_SCENE_RENDER_PASS pass)
What does this allow you to do now?
Well, in its current state, not much :( . But this will improve ;).

As you see, you can register a node for multiple passes by using something like this:

Code: Select all

ISceneNode* myNode = smgr->add.....Node(...);
// every scene node is automatically registered for the ESRP_DEFAULT render pass.
// to add it to a new render pass:
myNode->registerRenderPass(ESRP_PASS_1);
// and if you don't want it to render in the default pass:
myNode->unregisterRenderPass(ESRP_DEFAULT);
If all you want to do is change the ordering that scene nodes are rendered, this should do it.
But if you want to use a different material (a.k.a. rendering properties) for different passes, then you can only make it work with custom scene nodes. In YourCustomSceneNode::render() function, you would call driver->setMaterial() using a different material each time. To get the current render pass, use smgr->getSceneRenderPass().

I have a couple of ideas to further enhance this, but they 're not that trivial to implement and I wouldn't do it, unless the Irrlicht team agreed with it (too much work to do for me alone).

The most "correct" way would be to register a material for each pass, for each node. Then, for example, the above code could change to this:

Code: Select all

ISceneNode* myNode = smgr->add.....Node(...);
IMaterial* myMaterial1 = ...;
IMaterial* myMaterial2 = ...;

// to add it to a new render pass using myMaterial1:
myNode->registerRenderPass(ESRP_PASS_1, myMaterial1);
// to add it to a new render pass using myMaterial2:
myNode->registerRenderPass(ESRP_PASS_2, myMaterial2);
See where I 'm going? This would allow us to alter the rendering of the builtin scene nodes too :).
But this would mean to update all existing builtin scene nodes to use the material of the current render pass. Not *that* much of work, but my intention is not to create a huge patch that will never be accepted for inclusion to the core. I don't want to fork Irrlicht ;).

Another benefit, which requires the renderpass-material assignment described above, is that it decouples us from the texture units limits. Let me explain:
Until Irrlicht 1.0, it allowed up to 2 texture units per-material. Ewww!
Now, 4 texture units per-material are allowed. This is an improvement, but still a limitation.
I have created a shader to render a splatting terrain but this limit allows me to use only three different textures for the whole terrain (the fourth is used as alpha map).
Wouldn't it be nice if Irrlicht would allow me to assign 16 :!: textures per-material? BUT HOW? you may wonder...
Simple: Irrlicht would see that we have exceeded the texture units count our graphics card supports and would clone the material 3 times, assigning 4 textures to each material and automatically adding this scene node to 3 additional render passes using the 3 new materials. And this would be a runtime decision, mind you. Meaning that if the user's card supports 8 texture units, Irrlicht would clone the material once and split the texture to 2 8-texture batches and render the scene node in 2 passes.

Or it could be done by incorporating render pass "knowledge" inside SMaterial. So the driver, when applying the material, would see what textures to fetch for the current pass.


Well, enough rant for one post. Let's see how this goes :).
krama757
Posts: 451
Joined: Sun Nov 06, 2005 12:07 am

Post by krama757 »

So really how you would do this is to have a scene node and just render a different material each time?

Would shaders have to affect the different materials each time also? Or is that shader dependent?
mandrav
Posts: 117
Joined: Sat Aug 27, 2005 8:29 pm
Contact:

Post by mandrav »

krama757 wrote:So really how you would do this is to have a scene node and just render a different material each time?

Would shaders have to affect the different materials each time also? Or is that shader dependent?
Depends on what you want to do and what your shader does.
If all you want is multiple render passes but change some shader constants per pass, this works with the patch I have already created.
But if you want to, say, use different textures for the second pass, it wouldn't work without setting a different material first.
krama757
Posts: 451
Joined: Sun Nov 06, 2005 12:07 am

Post by krama757 »

Ah okay then. Have you already uploaded the patch for the community to test somewhere? I would be very interested in trying it out.

Not to rush your great work or anything :)
Post Reply