Table of contents
The Compositor Framework
Here we will describe the Ogre in-core compositing system in Dagon. It is very roughly based on Manuel's postfilter framework introduced here. By using this system, you'll be able to implement postfilter effects in Ogre just like you think about compositing the passes.
- PostFilters have from hereon been renamed to Compositors. Seeing the system grow into much more than just simple postfiltering, I(Wumpus) decided on this renaming.
Compositor scripts
Compositors can be built from code or by writing .compositor scripts. Here are some examples.
Bloom:
/// Manuel's bloom /// Needs a scene-sized rtt, but does only one render of the scene compositor Bloom { technique { // Temporary textures texture scene target_width target_height PF_A8R8G8B8 texture rt0 128 128 PF_A8R8G8B8 texture rt1 128 128 PF_A8R8G8B8 target scene { // Render output from previous compositor (or original scene) input previous } target rt0 { // Start with clear texture input none // Vertical blur pass pass render_quad { // Renders a fullscreen quad with a material material PostFilters/Blur0 input 0 scene } } target rt1 { // Start with clear texture input none // Horizontal blur pass pass render_quad { // Renders a fullscreen quad with a material material PostFilters/Blur1 input 0 rt0 } } target_output { // Start with clear output input none // Draw a fullscreen quad pass render_quad { // Renders a fullscreen quad with a material material PostFilters/BloomBlend input 0 scene input 1 rt1 } } } }
Alternative bloom
Suggestion by Sinbad; this needs no screen sized RenderTexture and can selectively make object glare (but does render the scene twice)
/// Alternative bloom by Sinbad /// Needs only two 128x128 rtts, but does two renders of the scene compositor Bloom2 { technique { // Temporary textures texture rt0 128 128 PF_A8R8G8B8 texture rt1 128 128 PF_A8R8G8B8 target rt1 { // Render output from previous compositor (or original scene) input previous } target rt0 { // Start with clear texture input none // Vertical blur pass pass render_quad { // Renders a fullscreen quad with a material material PostFilters/Blur0 input 0 rt1 } } target rt1 { // Start with clear texture input none // Horizontal blur pass pass render_quad { // Renders a fullscreen quad with a material material PostFilters/Blur1 input 0 rt0 } } target_output { // Render output from previous pass (or original scene) input previous // Blend a fullscreen quad over the scene pass render_quad { // Renders a fullscreen quad with a material material PostFilters/BloomBlend input 0 rt1 } } } }
Motion Blur
/// Manuel's motion blur effect compositor "Motion Blur" { technique { // Temporary textures texture scene target_width target_height PF_A8R8G8B8 texture sum target_width target_height PF_A8R8G8B8 texture temp target_width target_height PF_A8R8G8B8 target scene { // Render output from previous compositor (or original scene) input previous } target sum { // Render this target pass only initially, on the first frame that // this effect was enabled. This makes sure the sum texture // does not start with randomness. only_initial on input previous } target temp { // Start with clear texture input none // Combine scene and sum texture pass render_quad { // Renders a fullscreen quad with a material material Ogre/Compositors/Combine input 0 scene input 1 sum } } target sum { // Start with clear texture input none // Copy temporary back to sum pass render_quad { // Renders a fullscreen quad with a material material Ogre/Compositors/Copyback input 0 temp } } target_output { // Start with clear output input none // Draw a fullscreen quad with the blur pass render_quad { // Renders a fullscreen quad with a material material Ogre/Compositors/MotionBlur input 0 sum } } } }
Black & White
/// Black and white effect compositor B&W { technique { // Temporary textures texture scene target_width target_height PF_A8R8G8B8 target scene { // Render output from previous compositor (or original scene) input previous } target_output { // Start with clear output input none // Draw a fullscreen quad with the blur pass render_quad { // Renders a fullscreen quad with a material material PostFilters/BlackAndWhite input 0 scene } } } }
Chaining postfilters
Chaining postfilters is as easy as adding multiple Compositors to one render target,
CompositorManager::getSingleton().addCompositor(mViewport, "Blur"); CompositorManager::getSingleton().addCompositor(mViewport, "B&W");
After adding them, compositors can be enabled and disabled individually, or removed again with removeCompositor. In case a postfilter is enabled and disabled frequently, one should use the enableCompositor and disableCompositor functionality as that keeps local resources like scratch textures around.
Script Manual
Here is the Compositor script manual released with Ogre 1.6
BNF grammer for script
This is the BNF grammer for the compositor script utilizing the Ogre simplified BNF compiler
// Top level rule <Script> ::= {<Compositor>} <Compositor> ::= 'compositor' <Label> '{' <Technique> '}' // Technique <Technique> ::= 'technique' '{' {<Texture>} {<Target>} <TargetOutput> '}' <Texture> ::= 'texture' <Label> <WidthOption> <HeightOption> <PixelFormat> <WidthOption> ::= 'target_width' | <#width> <HeightOption> ::= 'target_height' | <#height> <PixelFormat> ::= 'PF_A8R8G8B8' | 'PF_R8G8B8A8' | 'PF_R8G8B8' | 'PF_FLOAT16_RGBA' | 'PF_FLOAT16_RGB' | 'PF_FLOAT16_R' | 'PF_FLOAT32_RGBA' | 'PF_FLOAT32_RGB' | 'PF_FLOAT32_R' // Target <Target> ::= 'target ' <Label> '{' {<TargetOptions>} {<Pass>} '}' <TargetOptions> ::= <TargetInput> | <OnlyInitial> | <VisibilityMask> | <LodBias> | <MaterialScheme> <TargetInput> ::= 'input' <TargetInputOptions> <TargetInputOptions> ::= 'none' | 'previous' <OnlyInitial> ::= 'only_initial' <On_Off> <VisibilityMask> ::= 'visibility_mask' <#mask> <LodBias> ::= 'lod_bias' <#lodbias> <MaterialScheme> ::= 'material_scheme' <Label> <TargetOutput> ::= 'target_output' '{' [<TargetInput>] {<Pass>} '}' // Pass <Pass> ::= 'pass' <PassTypes> '{' {<PassOptions>} '}' <PassTypes> ::= 'render_quad' | 'clear' | 'stencil' | 'render_scene' <PassOptions> ::= <PassMaterial> | <PassInput> | <ClearSection> | <StencilSection> <PassMaterial> ::= 'material' <Label> <PassInput> ::= 'input' <#id> <Label> // clear <ClearSection> ::= -'clear' -'{' {<ClearOptions>} -'}' <ClearOptions> ::= <Buffers> | <ColourValue> | <DepthValue> | <StencilValue> <Buffers> ::= 'buffers' {<BufferTypes>} <BufferTypes> ::= <Colour> | <Depth> | <Stencil> <Colour> ::= 'colour' (?!<ValueChk>) <Depth> ::= 'depth' (?!<ValueChk>) <Stencil> ::= 'stencil' (?!<ValueChk>) <ValueChk> ::= '_value' <ColourValue> ::= 'colour_value' <#red> <#green> <#blue> <#alpha> <DepthValue> ::= 'depth_value' <#depth> <StencilValue> ::= 'stencil_value' <#val> // stencil <StencilSection> ::= -'stencil' -'{' {<StencilOptions>} -'}' <StencilOptions> ::= <Check> | <CompareFunction> | <RefVal> | <Mask> | <FailOp> | <DepthFailOp> | <PassOp> | <TwoSided> <Check> ::= 'check' <On_Off> <CompareFunction> ::= 'comp_func' <CompFunc> <CompFunc> ::= 'always_fail' | 'always_pass' | 'less_equal' | 'less' | 'equal' | 'not_equal' | 'equal' | 'greater_equal' | 'greater' <RefVal> ::= 'ref_value' <#val> <Mask> ::= 'mask' <#mask> <FailOp> ::= 'fail_op' <StencilOperation> <DepthFailOp> ::= 'depth_fail_op' <StencilOperation> <PassOp> ::= 'pass_op' <StencilOperation> <TwoSided> ::= 'two_sided' <On_Off> <StencilOperation> ::= 'keep' | 'zero' | 'replace' | 'increment_wrap' | 'increment' | 'decrement_wrap' | 'decrement' | 'invert' // common rules <On_Off> ::= 'on' | 'off' <Label> ::= <Unquoted_Label> | <Quoted_Label> <Quoted_Label> ::= -'\"' <Character> {<Alphanumeric_Space>} -'\"' <Unquoted_Label> ::= <Character> {<Alphanumeric>} <Alphanumeric_Space> ::= <Alphanumeric> | <Space> <Alphanumeric> ::= <Character> | <Number> <Character> ::= (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$#%!_*&\\/) <Number> ::= (0123456789) <Space> ::= ( )
Modifying a compositor material
Each compositor instance clones the original material for the compositor, so they can be modified independently for each viewport where the compositor is used. The drawback is that changes to the original material aren't transmitted into the cloned versions.
Thus, modifying the material used by a compositor instance requires a CompositorInstance::Listener specialization. This listener has two variation points:
- notifyMaterialSetup(): Called when the material is initialised/compiled.
- notifyMaterialRender(): Called when the material will be used by the render target.
The materials passed as argument to these methods are the clones used by the compositor instances. Changes done to them will take effect in each compositor referencing this listener.
The way to add a listener to a compositor instance is:
aCompositorInstance->addListener (new MyCompositorListener);
Compositors and camera switching
If you're using compositors and switching between different cameras regularly, you might notice that the other cameras stop working and only the camera that was active when you added the compositors is used - this is because the render targets' reference to the camera are not updated when you change the viewport's camera. To fix this, just disable all compositors before switching the camera and enable them again afterwards. This destroys and recreates the render targets, which is a bit inefficient but it's a good enough workaround.
See this thread for more information: http://www.ogre3d.org/forums/viewtopic.php?f=4&t=53330
This has been fixed in a patch for Ogre 1.7, so it only affects older versions and MOGRE.