[2.1] Compositor texture ping pong

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


Post Reply
xrgo
OGRE Expert User
OGRE Expert User
Posts: 1148
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 168

[2.1] Compositor texture ping pong

Post by xrgo »

Hello! probably a very noob question, its something really simple but I cant make it work =(

I need to make a "brush" so I can paint on a texture, everything in shader code (no pass scenes, just pass quads).
I have this "brush" texture that paints the texture as I send the coordinates to the shader. the problem is that I need to sample in the shader the same texture that I am writing on so I can make my brush strokes persistent.
I think that's called ping pong, but I am having trouble to set that up in compositor scripts.

does anyone have a sample script that can share?
thanks in advance!
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1279
Contact:

Re: [2.1] Compositor texture ping pong

Post by dark_sylinc »

Postprocessing sample does this.

There are many effects that need to do ping pong (e.g. Radial Blur)

It has two textures and alternates/swaps the Inputs & Outputs between the nodes in order to make the ping pong, thus Output 0 from Node A becomes Input 1 (source) for Node B and Output 1 becomes Input 0 (target); and the final output is always in Output 0

In a graphical way:


Alternatively, Bloom performs this ping pong within the same node on "rt0" and "rt1" which are both 1/4th of the RTT resolution, and alternate between rendering to rt0 and rt1.

Depending on what you need to do, you may have to use a pass_quad to copy rt0(input) -> rt1(target), and then render with your intended shader to rt0(target) by sourcing from rt1(input).
This would be the case if your shader performs alpha blending:

Code: Select all

compositor_node MagicShaderNode
{
	in 0 rt_input
	in 1 rt_output
	
	custom_id Ogre/Postprocess

	//Copy rt_input -> rt_output so that both RTTs contain exactly the same
	target rt_output
	{
		pass render_quad
		{
			load { all dont_care }
			material Ogre/Copy/4xFP32
			input 0 rt_input
		}
	}
	
	target rt_input
	{
		pass render_quad
		{
			material Postprocess/YourMagicShaderWithAlphaBlending
			input 0 rt_output
		}
	}

	//Do NOT swap, because we've performed two passes and now rt_input
	//contains the last render and should be the output of this node
	out 0 rt_input
	out 1 rt_output
}
xrgo
OGRE Expert User
OGRE Expert User
Posts: 1148
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 168

Re: [2.1] Compositor texture ping pong

Post by xrgo »

thank you!
I actually didn't find the file Postprocessing.compositor until just now, I thought it was all done in code since it wasn't in the scripts\Compositors folder...
So I managed to copy the Bloom script part, so I have something like this:

Code: Select all

compositor_node WeldDisplaceRenderingNode
{
	in 0 rt_input
	in 1 rt_output

	texture rt0 target_width target_height PF_FLOAT16_R

	target rt0
	{
		pass render_quad
		{
			material Ogre/Copy/4xFP32
			input 0 rt_input
		}
	}

	target rt_output
	{
		pass render_quad
		{
			material DisplaceMat
			input 0 rt_input
			input 1 rt0
		}
	}

	out 0 rt_output
	out 1 rt_input

}


compositor_node FinalComposition
{
	in 0 rt_output
	in 1 rtN

	target rt_output
	{
		pass clear
		{
			colour_value	1 0 0 1
			buffers			colour
			discard_only	true
		}

		pass render_quad
	  {
			material Ogre/Copy/4xFP32
	    input 0 rtN
		}
	}
}

workspace WeldDisplaceRenderingWorkspace
{
	connect PostprocessingSampleStdRenderer WeldDisplaceRenderingNode
	connect_output FinalComposition 0
	connect WeldDisplaceRenderingNode 0 FinalComposition 1
}
the "DisplaceMat" has this shader (for testing)

Code: Select all

#version 330

layout(location = 0, index = 0) out vec4 outColour;

in block
{
	vec2 uv0;
} inPs;

uniform sampler2D RT;
uniform sampler2D Blur1;

uniform sampler2D brushSampler;

uniform vec2 brushPos;

void main()
{

		vec4 brush = texture( brushSampler, inPs.uv0*10 + brushPos );
		vec4 sharp	= texture( RT, inPs.uv0 );
		vec4 blur	= texture( Blur1, inPs.uv0 );

		outColour = blur + sharp + brush;
}
but I have no "PostprocessingSampleStdRenderer" analog since I render everything via shader, I tried something like this:

Code: Select all

compositor_node PostprocessingSampleStdRenderer
{
	texture rt0 target_width target_height PF_FLOAT16_R
	texture rt1 target_width target_height PF_FLOAT16_R

	target rt0
	{
		pass clear
		{
			buffers			depth
		}
	}

	target rt1
	{
		pass clear
		{
			buffers			depth
		}
	}

	out 0 rt0
	out 1 rt1
}
but its not working (the brush just moves, its not persistent)
still not sure where the ping pong part is xD
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5299
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1279
Contact:

Re: [2.1] Compositor texture ping pong

Post by dark_sylinc »

I don't know what you're trying to do.

This:

Code: Select all

compositor_node WeldDisplaceRenderingNode
{
	...
	target rt0
	{
		pass render_quad
		{
			material Ogre/Copy/4xFP32
			input 0 rt_input
		}
	}

	target rt_output
	{
		pass render_quad
		{
			material DisplaceMat
			input 0 rt_input
			input 1 rt0
		}
	}
	...
}
Is the same as this:

Code: Select all

compositor_node WeldDisplaceRenderingNode
{
	...
	target rt0
	{
		pass render_quad
		{
			material Ogre/Copy/4xFP32
			input 0 rt_input
		}
	}

	target rt_output
	{
		pass render_quad
		{
			material DisplaceMat
			input 0 rt_input
			input 1 rt_input //<---
		}
	}
	...
}
And with the definition of PostprocessingSampleStdRenderer you posted, you're not ping ponging anything. rt0 & rt1 are both uninitialized and most likely Windows is initializing them for you to black (you should NOT rely on this behavior) so you're just rendering what's in brushSampler:

Code: Select all

outColour = blur = 0 + sharp = 0 + brush;
//Thus:
outColour = brush;
To fix the uninitialization, perform a clear and use num_initial 1 to just do it on the first frame.

I suspect you want some form of accumulation of results, like Motion Blur (this one is created from C++ to show how to do it from C++...). If that's the case you should do this:

Code: Select all

compositor_node WeldDisplaceRenderingNode
{
	...
	target rt0
	{
		pass render_quad
		{
			material Ogre/Copy/4xFP32
			input 0 rt_input
		}
	}

	target rt_output
	{
		pass render_quad
		{
			material DisplaceMat
			input 0 rt_input
			input 1 rt0
		}
	}
	
	//Copy rt_output -> rt_input AFTER you've executed your shader, so the results are carried over for the next frame.
	target rt_input
	{
		pass render_quad
		{
			material Ogre/Copy/4xFP32
			input 0 rt_output
		}
	}
	...
}
HDR may be a good example of this:
HdrRenderingNode creates oldLumRt which contains the Luminance from last frame, and clears oldLumRt only on the first frame to set an initial value
HdrPostprocessingNode computes auto-exposure on lumRt0 by averaging the current luminance and the one stored from previous frame in lumRt1 (lumRt1 is oldLumRt). After that, it copies lumRt0 -> lumRt1 so that it can carry over the value to the next frame.

In pseudo code:

Code: Select all

float oldLumRt = 1.0f;
while( true )
{
    float lumRt = calculateLuminance();
    lumRt = (lumRt + oldLumRt) * 0.5f;
    oldLumRt = lumRt; //Carry over to the next frame.
}
This is the same, but in the compositor.
xrgo
OGRE Expert User
OGRE Expert User
Posts: 1148
Joined: Sat Jul 06, 2013 10:59 pm
Location: Chile
x 168

Re: [2.1] Compositor texture ping pong

Post by xrgo »

thanks again!
dark_sylinc wrote: Wed Oct 24, 2018 12:03 am And with the definition of PostprocessingSampleStdRenderer you posted, you're not ping ponging anything
yeah.. that's what I was aiming for, because I dint know this:
dark_sylinc wrote: Wed Oct 24, 2018 12:03 am To fix the uninitialization, perform a clear and use num_initial 1 to just do it on the first frame.
dark_sylinc wrote: Wed Oct 24, 2018 12:03 am I suspect you want some form of accumulation of results, like Motion Blur (this one is created from C++ to show how to do it from C++...). If that's the case you should do this:
This makes it work!!

I understand what I was missing now
thank you so much!! and sorry for the noob question, not so "OGRE Expert User" by my side :lol:
Post Reply