Custom compositor meshes

Discussion area about developing with Ogre2 branches (2.1, 2.2 and beyond)
Post Reply
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7147
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 16

Custom compositor meshes

Post by Kojack » Sun Jul 20, 2014 7:16 am

I've been reading through the code to see how the new compositor system works.
For latest oculus rift support, we need to render a render texture through a custom mesh shape (that is updated every frame, using uv coords to do the eye distortion instead of a shader) instead of a full screen quad. From what I can see, there's 4 pass types: clear, quad, scene and stencil.
It looks like it should be pretty easy to make a custom mesh pass based on the quad pass code. But it doesn't seem possible to inject a user made pass type into the compositor, it has explicit knowledge of the four pass types.

So it seems like the best way to go is add a new pass type and add support for it to the compositor code. Is that accurate? Or is injecting a new type possible?
0 x

User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7147
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 16

Re: Custom compositor meshes

Post by Kojack » Sun Jul 20, 2014 3:31 pm

Seems I can inject a user defined compositor pass def (target's addPass can't be used, but access to the internal pass list is possible via getCompositorPassesNonConst()). But CompositorNode::createPasses() will then throw an exception if the pass type doesn't match one of the 4.

So I guess modifying ogre's source to add a 5th type is the only way, unless I make a whole scenemanager just for the single mesh and use PASS_SCENE. But that seems wasteful (scene passes have a lot of unneeded stuff, like shadows, cameras, etc. I just need a flat 2d renderop onto a black background).

(No time to actually try this for a couple of days, real life in the way)

Hmm, the constructor for CompositorManager2 makes a default compositor target with 3 passes: clear, quad and scene. Does that mean it's actually clearing the screen, then rendering a full screen quad over the screen, then rendering the scene over the top of that?
0 x

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4078
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 232
Contact:

Re: Custom compositor meshes

Post by dark_sylinc » Sun Aug 03, 2014 8:41 pm

To your original question: You can't inject your own passes. YET.
But supporting such thing should be relatively trivial.

I avoided such thing until the Compositor was more mature, which it is now. I would just have to think of the interface (i.e. make it simple!)
Kojack wrote:I make a whole scenemanager just for the single mesh and use PASS_SCENE. But that seems wasteful (scene passes have a lot of unneeded stuff, like shadows, cameras, etc. I just need a flat 2d renderop onto a black background).
Actually... if you put your mesh in its own render queue alone; and the other compositor passes never render that pass; that could work nicely.
One big reason the new compo was created is that the old one had terribly heavy weight passes even if there was one renderqueue and one object to render. The passes from the new Compo are very lightweight; things like shadows won't be processed at all if you don't add a shadow node that PASS_SCENE; there is no additional camera information to process except frustum culling, and frustum culling for just one object is very cheap.

May be if you are going to do this multiple times, then it's better to have your own custom pass; but if it's the final one, a simple PASS_SCENE rendering an isolated render_queue will just work.
Kojack wrote:Hmm, the constructor for CompositorManager2 makes a default compositor target with 3 passes: clear, quad and scene. Does that mean it's actually clearing the screen, then rendering a full screen quad over the screen, then rendering the scene over the top of that?
**Hides in shame**
Yes, your interpretation is correct. But that piece of code should be removed, it was just a test workspace I created back when I was testing the Compositor. I don't even know if it works now.
Initially I thought a default one could be created but it was a bad idea, and createBasicWorkspaceDef appeared instead. But I forgot to remove the code in the constructor...

Cheers
Matías
0 x

scrawl
OGRE Expert User
OGRE Expert User
Posts: 1119
Joined: Sat Jan 01, 2011 7:57 pm
x 2

Re: Custom compositor meshes

Post by scrawl » Sun Sep 21, 2014 9:03 am

Bump. I would also like to see custom compositor passes supported. I attempted porting MyGUI to Ogre 2.0, but the old render method (RenderQueueListener) no longer works. It'd be great if I could register a custom pass for rendering the GUI efficiently.
I tried adding the feature myself, but I'm really not sure where to start. It looks like most parts of the compositor weren't written with custom passes in mind. Uses of the CompositorPassType enum are all over the place.
0 x

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4078
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 232
Contact:

Re: Custom compositor meshes

Post by dark_sylinc » Sun Sep 21, 2014 7:30 pm

Bumping one and half month later isn't going to make it faster.

In order to provide custom implementations, new entries would be needed in CompositorPassType (i.e. PASS_CUSTOM0, PASS_CUSTOM1, PASS_CUSTOM2 & PASS_CUSTOM3; I don't think more are needed)
Then a custom pass provider would need to be registered.

The custom pass provider would do two things:
1. Create the PassDef. This happens in CompositorTargetDef::addPass, so the function would look something like this:

Code: Select all

CompositorPassDef* CompositorTargetDef::addPass( CompositorPassType passType )
    {
        CompositorPassDef *retVal = 0;
        switch( passType )
        {
        case PASS_CLEAR:
            retVal = OGRE_NEW CompositorPassClearDef( mRtIndex );
            break;
        case PASS_QUAD:
            retVal = OGRE_NEW CompositorPassQuadDef( mParentNodeDef, mRtIndex );
            break;
        case PASS_SCENE:
            retVal = OGRE_NEW CompositorPassSceneDef( mRtIndex );
            break;
        case PASS_STENCIL:
            retVal = OGRE_NEW CompositorPassStencilDef( mRtIndex );
            break;
        case PASS_CUSTOM0:
        case PASS_CUSTOM1:
        case PASS_CUSTOM2:
        case PASS_CUSTOM3:
            retVal = provider->createPassDef( passType, /* more additional data here. May be just pass 'this'? */ );
            break;
        default:
            break;
        }

        mCompositorPasses.push_back( retVal );
        
        return retVal;
    }
2. Create the instantiation (the Pass). This happens in CompositorNode::createPasses, so the function would look something like this:

Code: Select all

void CompositorNode::createPasses(void)
{
    CompositorTargetDefVec::const_iterator itor = mDefinition->mTargetPasses.begin();
    CompositorTargetDefVec::const_iterator end  = mDefinition->mTargetPasses.end();

    while( itor != end )
    {
        /* ...unrelated code... */

        const CompositorPassDefVec &passes = itor->getCompositorPasses();
        CompositorPassDefVec::const_iterator itPass = passes.begin();
        CompositorPassDefVec::const_iterator enPass = passes.end();

        while( itPass != enPass )
        {
            CompositorPass *newPass = 0;
            switch( (*itPass)->getType() )
            {
            case PASS_CLEAR:
                newPass = OGRE_NEW CompositorPassClear(
                                        static_cast<CompositorPassClearDef*>(*itPass),
                                        mWorkspace->getSceneManager(), *channel, this );
                break;
            case PASS_QUAD:
                newPass = OGRE_NEW CompositorPassQuad(
                                        static_cast<CompositorPassQuadDef*>(*itPass),
                                        mWorkspace->getDefaultCamera(), this, *channel,
                                        mRenderSystem->getHorizontalTexelOffset(),
                                        mRenderSystem->getVerticalTexelOffset() );
                break;
            case PASS_SCENE:
                newPass = OGRE_NEW CompositorPassScene(
                                        static_cast<CompositorPassSceneDef*>(*itPass),
                                        mWorkspace->getDefaultCamera(), *channel, this );
                postInitializePassScene( static_cast<CompositorPassScene*>( newPass ) );
                break;
            case PASS_STENCIL:
                newPass = OGRE_NEW CompositorPassStencil(
                                        static_cast<CompositorPassStencilDef*>(*itPass),
                                        *channel, this, mRenderSystem );
                break;
            case PASS_CUSTOM0:
            case PASS_CUSTOM1:
            case PASS_CUSTOM2:
            case PASS_CUSTOM3:
                newPass = provider->createPass( *itPass, /* ... more parameters here ... */ );
                break;
            default:
                OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED,
                            "Pass type not implemented or not recognized",
                            "CompositorNode::initializePasses" );
                break;
            }

            mPasses.push_back( newPass );
            ++itPass;
        }

        ++itor;
    }
}
Then there are the little details: alter the script compiler to register custom keywords that can translate to PASS_CUSTOM0, ... PASS_CUSTOMN (or just hardcode the keywords "custom0" ... "customN" ), how to register the provider (probably goes into the CompositorManager2), traverse the parents to get the implementation provider, what information and how is passed to the creation methods so that it's flexible, write a sample to show how to provide a custom implementation (you need to write the provider, write a class that derives from CompositorPassDef, and write a class that derives from CompositorPass), etc.
But the key parts are in CompositorTargetDef::addPass & CompositorNode::createPasses.
0 x

scrawl
OGRE Expert User
OGRE Expert User
Posts: 1119
Joined: Sat Jan 01, 2011 7:57 pm
x 2

Re: Custom compositor meshes

Post by scrawl » Sun Sep 21, 2014 8:08 pm

Sounds good, but why restrict to a fixed number of custom types? A better way would be to define *one* PASS_USER value in the enum, set to a high value like 1000 (so that it won't ever collide with new pass types added to Ogre), and allow any value >= 1000 as a custom pass type identifier.
And regarding the script interface, why undescriptive names like "custom1" "custom2"? The pass provider class can supply a name that will be used by the script parser to identify this pass type.

A minor nitpick about your example code, it's probably a good idea to have the built-in pass types also registered through the same system that allows custom pass types. That would simplify the CompositorManager code a great deal, and can more easily handle fail situations like the user trying to register a custom pass with a name or ID that's already taken by a built-in pass type.
0 x

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4078
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 232
Contact:

Re: Custom compositor meshes

Post by dark_sylinc » Sun Sep 21, 2014 8:27 pm

scrawl wrote:And regarding the script interface, why undescriptive names like "custom1" "custom2"? The pass provider class can supply a name that will be used by the script parser to identify this pass type.
"Alter the script compiler to register custom keywords that can translate to PASS_CUSTOM0, ... PASS_CUSTOMN (or just hardcode the keywords "custom0" ... "customN" )"
That's what I said. I was talking out loud the alernatives.
i.e. in the script the keyword "MyFunnyGuiPassName" ---> gets converted to PASS_CUSTOM1.
scrawl wrote:Sounds good, but why restrict to a fixed number of custom types? A better way would be to define *one* PASS_USER value in the enum, set to a high value like 1000 (so that it won't ever collide with new pass types added to Ogre), and allow any value >= 1000 as a custom pass type identifier.
Because declaring the variable as an enum allows the debugger to tells us which type of pass this is, which is very handy when troubleshooting complex compositors.
But more importantly, there aren't reasons to have many custom passes, if you need many; then there's a high chance you're doing it the wrong way and you'd rather rethink what you're doing (i.e. in 2.0 Final Gui rendering is much better handled by putting all the GUI stuff in its own queue, and using a scene pass with a custom Hlms implementation; instead of implementing a custom compo pass).
If you, really insisit that you need so many, why do you need Ogre? You're basically overriding its default rendering pipeline and turning it into a low level rendering system. The need for a few custom passes is valid; but there can't be the need for so many that the flexibility of having any random number surpasses the benefits of using an enum (having a fixed, limited number of options, i.e. it can't "blow", nice debugging output).

If more Ogre implementations are added, there's a high chance you will need (or at least want to) recompile your application rather than try to mix old DLLs with new ones, so there's little or no benefit from registering a custom pass as "1001" than "PASS_CUSTOM0".
0 x

scrawl
OGRE Expert User
OGRE Expert User
Posts: 1119
Joined: Sat Jan 01, 2011 7:57 pm
x 2

Re: Custom compositor meshes

Post by scrawl » Sun Sep 21, 2014 8:38 pm

Well, no, I personally don't need more than 4 pass types. However, the question shouldn't be "why support it?" but rather, "why not support it, when there's no additional effort involved?"
See Zero one infinity rule.
Because declaring the variable as an enum allows the debugger to tells us which type of pass this is, which is very handy when troubleshooting complex compositors.
Why do you need the type enum to tell what type the pass is? The debugger can show type information about objects, no enum is needed for that. Or are there important debugging cases where the type enum is used, but not in connection with any live pass objects?
I can start working on the custom pass support once we get this question sorted.
in 2.0 Final Gui rendering is much better handled by putting all the GUI stuff in its own queue, and using a scene pass
Yes, the state blocks concept will be very useful for this. Anyway, for the time being this feature isn't ready yet, so I have to look for alternatives for now.
i.e. in the script the keyword "MyFunnyGuiPassName" ---> gets converted to PASS_CUSTOM1.
Ah, my bad. Misread that! :)
0 x

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4078
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 232
Contact:

Re: Custom compositor meshes

Post by dark_sylinc » Mon Sep 22, 2014 9:59 pm

scrawl wrote:Why do you need the type enum to tell what type the pass is? The debugger can show type information about objects, no enum is needed for that. Or are there important debugging cases where the type enum is used, but not in connection with any live pass objects?
I can start working on the custom pass support once we get this question sorted.
Well, when you ask the Compo to create the node definition, the definition isn't live yet, and the enum is used passed to the creation function.
So, suppose your create the compo from code, and wonder yourself why it isn't rendering, and then you see PASS_CLEAR around your code when you know you meant PASS_SCENE, it can help spot the mistake.
Whereas seeing "1" instead of "2" doesn't really much say anything. Enough time debugging OpenGL shows why this is annoying.
Another imporant place I see is that the CompositorPassDef implementation must tell the base class what type of pass we are (i.e. CompositorPassClearDef sets mType to PASS_CLEAR). Unfortunately C++ doesn't allow some sort of static reflection to sort this out automatically; so we do it manually. And we can make mistakes.
If you see that CompositorPassMyImplDef::mType = PASS_WRONG_TYPE, it can be easier to spot IMO.

Another option I see is a union. See the type in debugger, but use the uint32 instead in code.
This isn't THAT much of a big deal, but I just don't want silly customization features to blow on us later.
0 x

scrawl
OGRE Expert User
OGRE Expert User
Posts: 1119
Joined: Sat Jan 01, 2011 7:57 pm
x 2

Re: Custom compositor meshes

Post by scrawl » Wed Sep 24, 2014 11:10 pm

Still not sold on the idea. I don't feel like using "debug-friendlyness" as an argument for a system design decision.
Need some more time to think about it. Maybe there's a totally different third option that I'm missing.
0 x

al2950
OGRE Expert User
OGRE Expert User
Posts: 1200
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 76

Re: Custom compositor meshes

Post by al2950 » Fri Oct 17, 2014 12:03 pm

I thought I would chip in here as I have (*EDIT*)now spent some time playing with 2.0 :). I dont really see the need to support n custom passes, in fact any custom passes. We do need an extra pass called PASS_MESH or something which supports rendering a mesh instead of a quad. I have to admit I have not looked at converting MYGUI yet, but I dont think another pass type should be needed, if we allowed people to create custom passes for stuff like that I think things might get out of hand quickly! MYGUI should use PASS_SCENE with a specific render queue. Again I apologise as I have not looked at MYGUI in 2.0 yet, so I might be missing something fairly critical. :oops:
0 x

scrawl
OGRE Expert User
OGRE Expert User
Posts: 1119
Joined: Sat Jan 01, 2011 7:57 pm
x 2

Re: Custom compositor meshes

Post by scrawl » Fri Oct 17, 2014 8:40 pm

MYGUI should use PASS_SCENE with a specific render queue. Again I apologise as I have not looked at MYGUI in 2.0 yet, so I might be missing something fairly critical. :oops:
MyGUI uses immediate-mode rendering, no entities/materials etc for performance reasons. This is much faster because there is no overhead from a scene graph and less overhead from render system state tracking.
0 x

al2950
OGRE Expert User
OGRE Expert User
Posts: 1200
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 76

Re: Custom compositor meshes

Post by al2950 » Mon Oct 20, 2014 8:48 am

Ah I get you now, I actually have a few 3rd party libs that inject render commands directly, did not realise it would not be simple to add them back in 2.0. For what its worth I am with Scrawl here when it comes to specifying a custom pass.
0 x

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4078
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 232
Contact:

Re: Custom compositor meshes

Post by dark_sylinc » Fri Oct 24, 2014 1:08 am

Due to a client project, I had to add custom passes.

It's in commit 6c979c003fe0d042fcd2f9aa3ceb2d758b8ea7df.

Scrawl will bark at me because it ended up doing the PASS_CUSTOM0 through PASS_CUSTOM3 idiom.
I just realized that this can easily solved by passing two parameters, PASS_CUSTOM and a second arbitrary ID argument that the provider is left to interpret as they want.

Edit: Ooops, forgot to update the script compiler. Will do that asap.
0 x

User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 4078
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 232
Contact:

Re: Custom compositor meshes

Post by dark_sylinc » Sat Oct 25, 2014 2:27 am

Updated the script compiler interface.
Removed PASS_CUSTOM0 - PASS_CUSTOM3 tokens for PASS_CUSTOM and a customId string (IdString).

Enjoy!
0 x

scrawl
OGRE Expert User
OGRE Expert User
Posts: 1119
Joined: Sat Jan 01, 2011 7:57 pm
x 2

Re: Custom compositor meshes

Post by scrawl » Thu Oct 30, 2014 2:37 am

Thank you! Works like a charm.
0 x

Post Reply