Compositor system

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


Post Reply
Transporter
Minaton
Posts: 933
Joined: Mon Mar 05, 2012 11:37 am
Location: Germany
x 110

Compositor system

Post by Transporter »

Hi,

I'm confused of the compositor system. Could someone please provide a small sample how to create a user defined compositor by code? I've seen the sample code but I don't get it how to activate it.

I have an DX9 project which I like to move to Ogre 2.0. Of course I could clone and modify the DX9 render system, but this is not an option because the plan is to remove DX9. the program uses a generated shader (__szEffect)

Code: Select all

uniform extern texture textureA;
uniform extern texture textureB;
uniform extern texture textureC;
uniform extern bool bBorder;

sampler samplerA = sampler_state
{
	Texture = <textureA>;
	MipFilter = LINEAR;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	AddressV = BORDER;
	AddressU = BORDER;
	BorderColor = float4(0,0,0,0);
};

sampler samplerB = sampler_state
{
	Texture = <textureB>;
	MipFilter = LINEAR;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	AddressV = MIRROR;
	AddressU = MIRROR;
	BorderColor = float4(0,0,0,0);
};

sampler samplerC = sampler_state
{
	Texture = <textureC>;
	MipFilter = LINEAR;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	AddressV = BORDER;
	AddressU = BORDER;
	BorderColor = float4(0,0,0,0);
};


struct VS_IN
{
	float4			pos : POSITION; 
	float2			tex : TEXCOORD0;
};

struct VS_OUT
{
	float4			pos : POSITION; 
	float2			tex : TEXCOORD0;
};

VS_OUT VS( VS_IN vIn )
{
	VS_OUT vOut;
	vOut.pos = vIn.pos;
	vOut.tex = vIn.tex;
	return vOut;
}

float4 PS( VS_OUT vIn ) : COLOR
{
	float4 tex = tex2D( samplerB, vIn.tex );
	float4 ppp = tex2D( samplerC, vIn.tex );
	if( bBorder )
	{
		tex.x*= 1.02;  
		tex.x-= 0.01;
		tex.y*= 1.02;  
		tex.y-= 0.01;
	}
	float4 vOut = tex2D( samplerA, tex.xy );
	vOut.rgb*= ppp.rgb;
	vOut.rgb*= ppp.a;
	vOut.a = 1;
	return vOut;
}

technique renderBC
{
	pass P0
	{
		VertexShader = compile vs_2_0 VS();
		PixelShader = compile ps_2_0 PS();
	}
}
which is compiled at runtime

Code: Select all

	ID3DXBuffer* err = NULL;

	// load and compile effect
	HRESULT hr = D3DXCreateEffect(  pDevice,  
							__szEffect,
							sizeof( __szEffect),
							NULL,
							NULL,
							0,
							NULL,
							&renderWindowResources->effect,
							&err);

	if( FAILED( hr ) )
	{
		THROW_EXCEPT((char*)err->GetBufferPointer(), "D3D9::acquire");
	}

	SAFE_RELEASE( err );
The effect is used in the main render loop

Code: Select all

	DX9PipelineState state( mDevice );
	hr = pDevice->SetRenderTarget( 0, renderWindowResources->backBufferReal );
	hr = pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
	hr = pDevice->BeginScene();
	hr = pDevice->SetViewport( &renderWindowResources->viewPort );
	hr = renderWindowResources->effect->SetTechnique( renderWindowResources->effect->GetTechniqueByName( "renderBC" ) );
	hr = renderWindowResources->effect->SetTexture( "textureA", renderWindowResources->backBufferTex );
	hr = renderWindowResources->effect->SetTexture( "textureB", renderWindowResources->texture1 );
	hr = renderWindowResources->effect->SetTexture( "textureC", renderWindowResources->texture2 );
	hr = renderWindowResources->effect->SetBool ( "bBorder", false );

	UINT uPasses;
	renderWindowResources->effect->Begin( &uPasses, 0 );
	    
	for( UINT uPass = 0; uPass < uPasses; ++uPass )
	{
		renderWindowResources->effect->BeginPass( uPass );

		pDevice->SetFVF( D3DFVF_CUSTOMVERTEXRHW );
		pDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP,  2, __vertices, sizeof(__vertices[0]) );

		renderWindowResources->effect->EndPass();
	}
	renderWindowResources->effect->End();
			
	hr = pDevice->EndScene();
I think this is like an ogre compositor, correct?

I could create the two images required for the original shader and I can compile the shader like this:

Code: Select all

	Ogre::HighLevelGpuProgramPtr ps = Ogre::HighLevelGpuProgramManager::getSingletonPtr()->createProgram("special_ps", "General", "hlsl", Ogre::GPT_FRAGMENT_PROGRAM);
	ps->setSource("float4 PS() : COLOR\n"
"{\n"
"    return float4(0.5, 0.075, 0.075, 1.0);\n"
"}");
	ps->load();
How can I create and activate a compositor? I use the default construction:

Code: Select all

	mRoot->initialiseCompositor();
	Ogre::CompositorManager2* compMan = mRoot->getCompositorManager2();
	const Ogre::String workspaceName = "default scene workspace";
	const Ogre::IdString workspaceNameHash = workspaceName;
	compMan->createBasicWorkspaceDef(workspaceName, Ogre::ColourValue::Black);
	compMan->addWorkspace(mSceneMgr, mWindow, mCamera, workspaceNameHash, true);
THX,
Transporter
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5586
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1413
Contact:

Re: Compositor system

Post by dark_sylinc »

I'm a bit confused about your question. What is it that you don't understand? And what do you want to achieve (it looks like a quad pass postprocess effect to me).

In the Compositor sample, there's "Sample_Compositor::createEffects" which does the same the script performs but in C++ code.
Transporter
Minaton
Posts: 933
Joined: Mon Mar 05, 2012 11:37 am
Location: Germany
x 110

Re: Compositor system

Post by Transporter »

Code: Select all

void TutorialApplication::createScene(void)
{
	// Set the scene's ambient light
	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5f, 0.5f, 0.5f));
 
	// Create an Entity
	Ogre::Entity* ogreHead = mSceneMgr->createEntity("ogrehead.mesh");
 
	// Create a SceneNode and attach the Entity to it
	Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	headNode->attachObject(ogreHead);
 
	// Create a Light and set its position
	Ogre::Light* light = mSceneMgr->createLight();
	Ogre::SceneNode* lightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	lightNode->attachObject(light);
	lightNode->setPosition(20.0f, 80.0f, 50.0f);

	Ogre::LogManager::getSingletonPtr()->logMessage("Create shader ...");

	// Create vertex shader
	Ogre::HighLevelGpuProgramPtr vs = Ogre::HighLevelGpuProgramManager::getSingletonPtr()->createProgram("special_vs", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "hlsl", Ogre::GPT_VERTEX_PROGRAM);
	vs->setSource("struct VS_IN\n"
"{\n"
"	float4			pos : POSITION;\n"
"	float2			tex : TEXCOORD0;\n"
"};\n"
"\n"
"struct VS_OUT\n"
"{\n"
"	float4			pos : POSITION;\n"
"	float2			tex : TEXCOORD0;\n"
"};\n"
"\n"
"VS_OUT VS( VS_IN vIn )\n"
"{\n"
"	VS_OUT vOut;\n"
"	vOut.pos = vIn.pos;\n"
"	vOut.tex = vIn.tex;\n"
"	return vOut;\n"
"}\n");
	vs->setParameter("target", "vs_2_0");
	vs->setParameter("entry_point", "VS");
	vs->load();

	// Create pixel shader
	Ogre::HighLevelGpuProgramPtr ps = Ogre::HighLevelGpuProgramManager::getSingletonPtr()->createProgram("special_ps", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "hlsl", Ogre::GPT_FRAGMENT_PROGRAM);
	ps->setSource("uniform extern texture textureA;\n"
"uniform extern texture textureB;\n"
"uniform extern texture textureC;\n"
"\n"
"sampler samplerA = sampler_state\n"
"{\n"
"	Texture = <textureA>;\n"
"	MipFilter = LINEAR;\n"
"	MinFilter = LINEAR;\n"
"	MagFilter = LINEAR;\n"
"	AddressV = BORDER;\n"
"	AddressU = BORDER;\n"
"	BorderColor = float4(0,0,0,0);\n"
"};\n"
"\n"
"sampler samplerB = sampler_state\n"
"{\n"
"	Texture = <textureB>;\n"
"	MipFilter = LINEAR;\n"
"	MinFilter = LINEAR;\n"
"	MagFilter = LINEAR;\n"
"	AddressV = MIRROR;\n"
"	AddressU = MIRROR;\n"
"	BorderColor = float4(0,0,0,0);\n"
"};\n"
"\n"
"sampler samplerC = sampler_state\n"
"{\n"
"	Texture = <textureC>;\n"
"	MipFilter = LINEAR;\n"
"	MinFilter = LINEAR;\n"
"	MagFilter = LINEAR;\n"
"	AddressV = BORDER;\n"
"	AddressU = BORDER;\n"
"	BorderColor = float4(0,0,0,0);\n"
"};\n"
"\n"
"struct VS_OUT\n"
"{\n"
"	float4			pos : POSITION;\n"
"	float2			tex : TEXCOORD0;\n"
"};\n"
"\n"
"float4 PS( VS_OUT vIn ) : COLOR\n"
"{\n"
"	float4 tex = tex2D( samplerB, vIn.tex );\n"
"	float4 ppp = tex2D( samplerC, vIn.tex );\n"
"	float4 vOut = tex2D( samplerA, tex.xy );\n"
"	vOut.rgb*= ppp.rgb;\n"
"	vOut.rgb*= ppp.a;\n"
"	vOut.a = 1;\n"
"	return vOut;\n"
"}\n");
	ps->setParameter("target", "ps_2_x");
	ps->setParameter("entry_point", "PS");
	ps->load();

	calculateTextures();

	// Create material
	Ogre::LogManager::getSingletonPtr()->logMessage("Create material ...");
	Ogre::MaterialPtr compMat = Ogre::MaterialManager::getSingletonPtr()->create("special", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	Ogre::Technique* technique = compMat->createTechnique();
	Ogre::Pass* pass = technique->createPass();
	pass->setDepthCheckEnabled(false);
	pass->setPolygonModeOverrideable(false);
	Ogre::TextureUnitState* textureUnitStateB = pass->createTextureUnitState("textureB");
	textureUnitStateB->setTextureCoordSet(0);
	textureUnitStateB->setTexture(textureB);
	Ogre::TextureUnitState* textureUnitStateC = pass->createTextureUnitState("textureC");
	textureUnitStateC->setTextureCoordSet(0);
	textureUnitStateC->setTexture(textureC);
	pass->setVertexProgram("special_vs");
	pass->setFragmentProgram("special_ps");
	//pass->getFragmentProgramParameters()->setNamedConstant("bBorder", 0);

	Ogre::LogManager::getSingletonPtr()->logMessage("Create compositor ...");

	// Create compositor
	Ogre::CompositorManager2* compositorManager = mRoot->getCompositorManager2();
	Ogre::CompositorNodeDef* compDef = compositorManager->addNodeDefinition("Special");

	compDef->addTextureSourceName("rt_input", 0, Ogre::TextureDefinitionBase::TEXTURE_INPUT);
	compDef->addTextureSourceName("rt_output", 1, Ogre::TextureDefinitionBase::TEXTURE_INPUT);
	compDef->mCustomIdentifier = "Postprocess/Special";
	/*compDef->setNumLocalTextureDefinitions(3);
	{
		//Ogre::TextureDefinitionBase::TextureDefinition* texDefA = compDef->addTextureDefinition("textureA");
		//texDefA->width = mWindow->getWidth();
		//texDefA->height = mWindow->getHeight();
		//texDefA->formatList.push_back(Ogre::PF_R8G8B8);

		Ogre::TextureDefinitionBase::TextureDefinition* texDefB = compDef->addTextureDefinition("textureB");
		texDefB->width = mWindow->getWidth();
		texDefB->height = mWindow->getHeight();
		texDefB->formatList.push_back(Ogre::PF_R8G8B8);

		Ogre::TextureDefinitionBase::TextureDefinition* texDefC = compDef->addTextureDefinition("textureC");
		texDefC->width = mWindow->getWidth();
		texDefC->height = mWindow->getHeight();
		texDefC->formatList.push_back(Ogre::PF_R8G8B8);
	}*/

	compDef->setNumTargetPass(1);
	{
		Ogre::CompositorTargetDef* targetDef = compDef->addTargetPass("rt_output");
		{
			Ogre::CompositorPassQuadDef* passQuad;
			passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
			passQuad->mMaterialName = "special";
			passQuad->addQuadTextureSource(0, "rt_input", 0);
		}
	}

	compDef->setNumOutputChannels(2);
	compDef->mapOutputChannel(0, "rt_output");
	compDef->mapOutputChannel(1, "rt_input");

	// Activate compositor ????

	Ogre::LogManager::getSingletonPtr()->logMessage("Render.");
}
I tried to create a simple demo application, but I can't finish it yet. The shader works with three textures (textureA, textureB and textureC). The first texture is the backbuffer image in the DX9 code how can I set this in a compositor? The second and third textures will be calculated by the function calculateTextures. So I've created a compositor, but how can I activate it after the creation of the default workspace?
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5586
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1413
Contact:

Re: Compositor system

Post by dark_sylinc »

This is the modified version:

Code: Select all

	{
		//This node will render the whole scene to an RTT
		Ogre::CompositorNodeDef* nodeDef = compositorManager->addNodeDefinition("Main Render");
		//Change the default settings of texDef if you want.
		TextureDefinitionBase::TextureDefinition *texDef = nodeDef->addTextureDefinition( "rtt" );


		nodeDef->setNumTargetPass( 1 );
		CompositorTargetDef *targetDef = nodeDef->addTargetPass( "rtt" );

		targetDef->setNumPasses( 2 );

		//If you want to modify the parameters, take the returned pointer and cast it
		//to CompositorPassClearDef and CompositorPassSceneDef respectively.
		targetDef->addPass( PASS_CLEAR ); //Clear the scene
		targetDef->addPass( PASS_SCENE ); //Render the scene

		//This node outputs rtt
		nodeDef->mapOutputChannel( 0, "rtt" );
	}

	//Now your "Special" rendering node.
	Ogre::CompositorNodeDef* nodeDef = compositorManager->addNodeDefinition("Special");

	//I assume you already, manually set "textureB" and "textureC" to the material's texture units
	nodeDef->addTextureSourceName("textureA", 0, Ogre::TextureDefinitionBase::TEXTURE_INPUT);
	nodeDef->addTextureSourceName("rt_output", 1, Ogre::TextureDefinitionBase::TEXTURE_INPUT);
	nodeDef->mCustomIdentifier = "Postprocess/Special";
	/*nodeDef->setNumLocalTextureDefinitions(3);
	{
		//Ogre::TextureDefinitionBase::TextureDefinition* texDefA = nodeDef->addTextureDefinition("textureA");
		//texDefA->width = mWindow->getWidth();
		//texDefA->height = mWindow->getHeight();
		//texDefA->formatList.push_back(Ogre::PF_R8G8B8);

		Ogre::TextureDefinitionBase::TextureDefinition* texDefB = nodeDef->addTextureDefinition("textureB");
		texDefB->width = mWindow->getWidth();
		texDefB->height = mWindow->getHeight();
		texDefB->formatList.push_back(Ogre::PF_R8G8B8);

		Ogre::TextureDefinitionBase::TextureDefinition* texDefC = nodeDef->addTextureDefinition("textureC");
		texDefC->width = mWindow->getWidth();
		texDefC->height = mWindow->getHeight();
		texDefC->formatList.push_back(Ogre::PF_R8G8B8);
	}*/

	nodeDef->setNumTargetPass( 1 );
	{
		Ogre::CompositorTargetDef* targetDef = nodeDef->addTargetPass( "rt_output" );
		targetDef->setNumPasses( 1 );
		{
			Ogre::CompositorPassQuadDef* passQuad;
			passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
			passQuad->mMaterialName = "special";
			passQuad->addQuadTextureSource( 0, "textureA", 0 );
		}
	}

	nodeDef->setNumOutputChannels(1);
	nodeDef->mapOutputChannel(0, "rt_output");

	CompositorWorkspaceDef *def = compositorManager->addWorkspaceDefinition( "MyWorkspace" );
	//Connect Main Render's RTT to Special's textureA
	def->connect( "Main Render", 0, "Special", 0 );
	//Send the render window to Special's rt_output
	def->connectOutput( "Special", 1 );

	// Activate compositor
	compositorManager->addWorkspace( sceneManager, renderWindow, defaultCam, "MyWorkspace", true );

	Ogre::LogManager::getSingletonPtr()->logMessage("Render.");
Transporter wrote:So I've created a compositor, but how can I activate it after the creation of the default workspace?
Well, workspaces and nodes are immutable. So you can't change after creation.
One safe, easy bet is to destroy the workspace, call workspaceDef->clearAll() and recreate it.

However that may force resources to be recreated, and if you have to toggle the compos frequently, it will be slow.
In "Sample_Compositor::checkBoxToggled" there are shown two examples of how to fix the problem.

I'm in a hurry now, so gotta go.
Cheers
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5586
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1413
Contact:

Re: Compositor system

Post by dark_sylinc »

I'm back again. Sorry for that cryptic ending.

Compositors are, in theory, immutable. Which means that once you've created the definition, you create the instance and can't change the definition anymore (while instances exist).

However, in practice there are lots of parts that you can modify without side effects.

For example, clear colour (aka the background colour) can be changed at any point in the definition and it will take effect immediately.

You can disable a node and it will stop executing. However, disabling a node means its output won't be updated. And sometimes this becomes an issue: if Node10 takes rtA and rtB as input, copies rtB into rtA, then outputs rtA, disabling NodeA means rtB is never copied into rtA; and thus Node11 will receive rtA's contents.... which don't contain the desired results!

The Compositor example follow the following connection, where connections are interleaved:
  • Node0 renders scene into texture A, clears B and outputs textures A and B
  • Node1 receives texture A and B; postprocess B into A, then outputs B and A
  • Node2 receives texture B and A, postprocess A into B, then outputs A and B
  • Node3 receives texture A and B, postprocess B into A, then outputs B and A
  • Node4 receives texture B and A, postprocess A into B, then outputs A and B
  • and so on...
To enabled/disable nodes, the compositor sample creates a workspace definition with ALL of the postprocess effects, and each time a postprocess effect is toggled, all connections are reset (using CompositorWorkspaceDef::clearAllInterNodeConnections), and we connect only the nodes that we are actually using, and disable the rest. This is what method 2 performs.
Method 1 only adds/removes the node in the middle, but now has to deal with the aftermath from the neighbouring nodes of the node that was added/remove.

This way we can safely modify the workspace definition while there are instances active.
There is no "one true" way to achieve this, as there are many ways to achieve the same. If there's only one effect that you want to toggle on and off, you may prefer to create two workspaces, and disable one and leave the other one enabled.
There may be other ways to reach the solution. The new compositor is a node-based compositor. And how you wire the nodes is completely up to you. There's a lot of flexibility, a lot of power, a lot of efficiency, but also more responsability (Spiderman's Uncle Ben speech!)

Games rarely need to toggle postprocessing effects, thus can bake the definition, and create the instance. If the user changes the graphics settings, the instance is destroyed, a new definition is baked and instantiated.

The other extreme is live editing of nodes where everything may change dynamically, and thus the Compositor sample shows how to this without having to recreate the workspace and destroy and recreate lots of GPU resources (which is a slow operation); although sometimes depending on the setting being changed (i.e. adding more passes to a node) needs to recreate a few resources that might be unavoidable.
Transporter
Minaton
Posts: 933
Joined: Mon Mar 05, 2012 11:37 am
Location: Germany
x 110

Re: Compositor system

Post by Transporter »

Thanks a lot for your detailed explanation! Your help is awesome!

In my case I don't have to toggle the effect. If you use a heat vision in a game you might be switching more effects.

There is a command line switch to turn it on or off. I removed the default compositor creation and try to create only a new one:

Code: Select all

void TutorialApplication::createScene(void)
{
	// Set the scene's ambient light
	mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5f, 0.5f, 0.5f));
 
	// Create an Entity
	Ogre::Entity* ogreHead = mSceneMgr->createEntity("ogrehead.mesh");
 
	// Create a SceneNode and attach the Entity to it
	Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	headNode->attachObject(ogreHead);
 
	// Create a Light and set its position
	Ogre::Light* light = mSceneMgr->createLight();
	Ogre::SceneNode* lightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	lightNode->attachObject(light);
	lightNode->setPosition(20.0f, 80.0f, 50.0f);

	Ogre::LogManager::getSingletonPtr()->logMessage("Create shader ...");

	// Create vertex shader
	Ogre::HighLevelGpuProgramPtr vs = Ogre::HighLevelGpuProgramManager::getSingletonPtr()->createProgram("special_vs", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "hlsl", Ogre::GPT_VERTEX_PROGRAM);
	vs->setSource("struct VS_IN\n"
"{\n"
"	float4			pos : POSITION;\n"
"	float2			tex : TEXCOORD0;\n"
"};\n"
"\n"
"struct VS_OUT\n"
"{\n"
"	float4			pos : POSITION;\n"
"	float2			tex : TEXCOORD0;\n"
"};\n"
"\n"
"VS_OUT VS( VS_IN vIn )\n"
"{\n"
"	VS_OUT vOut;\n"
"	vOut.pos = vIn.pos;\n"
"	vOut.tex = vIn.tex;\n"
"	return vOut;\n"
"}\n");
	vs->setParameter("target", "vs_2_0");
	vs->setParameter("entry_point", "VS");
	vs->load();

	// Create pixel shader
	Ogre::HighLevelGpuProgramPtr ps = Ogre::HighLevelGpuProgramManager::getSingletonPtr()->createProgram("special_ps", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "hlsl", Ogre::GPT_FRAGMENT_PROGRAM);
	ps->setSource("uniform extern texture textureA;\n"
"uniform extern texture textureB;\n"
"uniform extern texture textureC;\n"
"\n"
"sampler samplerA = sampler_state\n"
"{\n"
"	Texture = <textureA>;\n"
"	MipFilter = LINEAR;\n"
"	MinFilter = LINEAR;\n"
"	MagFilter = LINEAR;\n"
"	AddressV = BORDER;\n"
"	AddressU = BORDER;\n"
"	BorderColor = float4(0,0,0,0);\n"
"};\n"
"\n"
"sampler samplerB = sampler_state\n"
"{\n"
"	Texture = <textureB>;\n"
"	MipFilter = LINEAR;\n"
"	MinFilter = LINEAR;\n"
"	MagFilter = LINEAR;\n"
"	AddressV = MIRROR;\n"
"	AddressU = MIRROR;\n"
"	BorderColor = float4(0,0,0,0);\n"
"};\n"
"\n"
"sampler samplerC = sampler_state\n"
"{\n"
"	Texture = <textureC>;\n"
"	MipFilter = LINEAR;\n"
"	MinFilter = LINEAR;\n"
"	MagFilter = LINEAR;\n"
"	AddressV = BORDER;\n"
"	AddressU = BORDER;\n"
"	BorderColor = float4(0,0,0,0);\n"
"};\n"
"\n"
"struct VS_OUT\n"
"{\n"
"	float4			pos : POSITION;\n"
"	float2			tex : TEXCOORD0;\n"
"};\n"
"\n"
"float4 PS( VS_OUT vIn ) : COLOR\n"
"{\n"
"	float4 tex = tex2D( samplerB, vIn.tex );\n"
"	float4 ppp = tex2D( samplerC, vIn.tex );\n"
"	float4 vOut = tex2D( samplerA, tex.xy );\n"
"	vOut.rgb*= ppp.rgb;\n"
"	vOut.rgb*= ppp.a;\n"
"	vOut.a = 1;\n"
"	return vOut;\n"
"}\n");
	ps->setParameter("target", "ps_2_0");
	ps->setParameter("entry_point", "PS");
	ps->load();

	calculateTextures();

	// Create material
	Ogre::LogManager::getSingletonPtr()->logMessage("Create material ...");
	Ogre::MaterialPtr compMat = Ogre::MaterialManager::getSingletonPtr()->create("special", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	Ogre::Technique* technique = compMat->createTechnique();
	Ogre::Pass* pass = technique->createPass();
	pass->setDepthCheckEnabled(false);
	pass->setPolygonModeOverrideable(false);
	Ogre::TextureUnitState* textureUnitStateB = pass->createTextureUnitState("textureB");
	textureUnitStateB->setTextureCoordSet(0);
	textureUnitStateB->setTexture(textureB);
	Ogre::TextureUnitState* textureUnitStateC = pass->createTextureUnitState("textureC");
	textureUnitStateC->setTextureCoordSet(0);
	textureUnitStateC->setTexture(textureC);
	pass->setVertexProgram("special_vs");
	pass->setFragmentProgram("special_ps");
	//pass->getFragmentProgramParameters()->setNamedConstant("bBorder", 0);

	Ogre::LogManager::getSingletonPtr()->logMessage("Create compositor ...");

	// Create compositor
	Ogre::CompositorManager2* compositorManager = mRoot->getCompositorManager2();

	//This node will render the whole scene to an RTT
	Ogre::CompositorNodeDef* nodeDef = compositorManager->addNodeDefinition("Main Render");
	//Change the default settings of texDef if you want.
	Ogre::TextureDefinitionBase::TextureDefinition* texDef = nodeDef->addTextureDefinition("rtt");
	nodeDef->setNumTargetPass(1);
	Ogre::CompositorTargetDef* targetDef = nodeDef->addTargetPass("rtt");
	targetDef->setNumPasses(2);

	//If you want to modify the parameters, take the returned pointer and cast it
	//to CompositorPassClearDef and CompositorPassSceneDef respectively.
	targetDef->addPass(Ogre::PASS_CLEAR); //Clear the scene
	targetDef->addPass(Ogre::PASS_SCENE); //Render the scene

	//This node outputs rtt
	nodeDef->mapOutputChannel(0, "rtt");

	//Now your "Special" rendering node.
	Ogre::CompositorNodeDef* compDef = compositorManager->addNodeDefinition("Special");

	//I assume you already, manually set "textureB" and "textureC" to the material's texture units
	compDef->addTextureSourceName("textureA", 0, Ogre::TextureDefinitionBase::TEXTURE_INPUT);
	compDef->addTextureSourceName("rt_output", 1, Ogre::TextureDefinitionBase::TEXTURE_INPUT);
	compDef->mCustomIdentifier = "Postprocess/Special";

	compDef->setNumTargetPass(1);
	{
		Ogre::CompositorTargetDef* targetDef = compDef->addTargetPass("rt_output");
		{
			Ogre::CompositorPassQuadDef* passQuad;
			passQuad = static_cast<Ogre::CompositorPassQuadDef*>(targetDef->addPass(Ogre::PASS_QUAD));
			passQuad->mMaterialName = "special";
			passQuad->addQuadTextureSource(0, "textureA", 0);
		}
	}

	compDef->setNumOutputChannels(1);
	compDef->mapOutputChannel(0, "rt_output");

	Ogre::CompositorWorkspaceDef* def = compositorManager->addWorkspaceDefinition("MyWorkspace");

	//Connect Main Render's RTT to Special's textureA
	def->connect("Main Render", 0, "Special", 0);

	//Send the render window to Special's rt_output
	def->connectOutput("Special", 1);

	// Activate compositor
	compositorManager->addWorkspace(mSceneMgr, mWindow, mCamera, "MyWorkspace", true);

	Ogre::LogManager::getSingletonPtr()->logMessage("Render.");
}
I use http://www.ogre3d.org/forums/viewtopic. ... 69#p509034 and override createCompositor with

Code: Select all

void TutorialApplication::createCompositor(void)
{
	mRoot->initialiseCompositor();
}
This is working well until mRoot->startRendering():
09:52:22: OGRE EXCEPTION(3:RenderingAPIException): Failed to set viewport. in D3D9RenderSystem::_setViewport at ..\..\..\RenderSystems\Direct3D9\src\OgreD3D9RenderSystem.cpp (line 3168)
Transporter
Minaton
Posts: 933
Joined: Mon Mar 05, 2012 11:37 am
Location: Germany
x 110

Re: Compositor system

Post by Transporter »

The application is crashing on calling mCompositorManager2->_update(). Any idea what's wrong?

Code: Select all

    bool Root::_updateAllRenderTargets(void)
    {
        // update all targets but don't swap buffers
        //mActiveRenderer->_updateAllRenderTargets(false);
        mCompositorManager2->_update();
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5586
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1413
Contact:

Re: Compositor system

Post by dark_sylinc »

I found the issues:

1. We forgot to specify the Pixel Format for the local defined texture (which is illegal). I'll add a warning or something when this happens.
This means:

Code: Select all

Ogre::TextureDefinitionBase::TextureDefinition* texDef = nodeDef->addTextureDefinition("rtt");
Becomes:

Code: Select all

Ogre::TextureDefinitionBase::TextureDefinition* texDef = nodeDef->addTextureDefinition("rtt");
texDef->formatList.push_back( Ogre::PF_BYTE_BGRA ); //Or any other format you want
2. Apparently creating a material already has a technique and a pass created for you (don't ask me why is that). So creating another technique gets you a Material with two techniques. But the first one gets used.
So:

Code: Select all

Ogre::Technique* technique = compMat->createTechnique();
Ogre::Pass* pass = technique->createPass();
Becomes:

Code: Select all

Ogre::Technique* technique = compMat->getTechnique( 0 );
Ogre::Pass* pass = technique->createPass( 0 );
3. You need to create a texture unit state for textureA to be inserted. The compo won't do that for you.
So:

Code: Select all

Ogre::TextureUnitState* textureUnitStateB = pass->createTextureUnitState("textureB");
textureUnitStateB->setTextureCoordSet(0);
textureUnitStateB->setTexture(textureB);
Ogre::TextureUnitState* textureUnitStateC = pass->createTextureUnitState("textureC");
textureUnitStateC->setTextureCoordSet(0);
textureUnitStateC->setTexture(textureC);
Becomes:

Code: Select all

Ogre::TextureUnitState* textureUnitStateA = pass->createTextureUnitState(); //"textureA"
textureUnitStateA->setTextureCoordSet(0);
Ogre::TextureUnitState* textureUnitStateB = pass->createTextureUnitState("textureB");
textureUnitStateB->setTextureCoordSet(0);
textureUnitStateB->setTexture(textureB);
Ogre::TextureUnitState* textureUnitStateC = pass->createTextureUnitState("textureC");
textureUnitStateC->setTextureCoordSet(0);
textureUnitStateC->setTexture(textureC);
4. You need to multiply the input position in the vertex shader by the viewProj matrix. As a quick workaround to get it to work, you can write "vOut.pos.z = 0;" right after "vOut.pos = vIn.pos;"; otherwise z = -1 and will be culled away in D3D9.

After doing those 4 steps, I got the Ogre head on screen :)

Cheers
Matias

Edit: Here's your modified file.
Transporter
Minaton
Posts: 933
Joined: Mon Mar 05, 2012 11:37 am
Location: Germany
x 110

Re: Compositor system

Post by Transporter »

I'm sorry to warm up this thread again, but I've read the Ogre 2.0 RC1 announcement. 2.0 will be deprecated to move the resources to 2.1 development. My problem is how to change the compositor/shaders to OpenGL. DX9 dropped and DX11 not working, so I have to change to OpenGL. But I'm not familiar with GLSL. I give up after a few hours trying to solve it:
vertex shader:

Code: Select all

void main() {
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
	gl_Position.z = 0;
}
fragment shader:

Code: Select all

uniform sampler2D textureA;
uniform sampler2D textureB;
uniform sampler2D textureC;

void main() {
	vec4 tex = texture(textureB, gl_FragCoord);
	vec4 ppp = texture(textureC, gl_FragCoord);
	vec2 xy = vec2(tex.x, tex.y);
	vec4 vIn = texture(textureA, xy);
	vec4 vOut = vec4(vIn.r * ppp.r, vIn.g * ppp.g, vIn.b * ppp.b, 1.0);
	gl_FragColor = vec4(vOut.r * ppp.a, vOut.g * ppp.a, vOut.b * ppp.a, 1.0);
}
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 538

Re: Compositor system

Post by Kojack »

What's the intended effect here? I tried the shader in rendermonkey, it ran, but was just a black window.
gl_FragCoord is a 4d value with x,y pixel coordinates, z is depth and w is 1/w.
If you use gl_FragCoord for a texture coordinate, it gives values in the range 0,0 to window width, window height (not 1,1). So in a window that's 1024 across, you are repeating the texture 1024 times. You need to divide gl_FragCoord by the window dimensions to get a distribution of 0,0 to 1,1 that texture lookup will like.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5586
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1413
Contact:

Re: Compositor system

Post by dark_sylinc »

Transporter wrote:I'm sorry to warm up this thread again, but I've read the Ogre 2.0 RC1 announcement. 2.0 will be deprecated to move the resources to 2.1 development. My problem is how to change the compositor/shaders to OpenGL. DX9 dropped and DX11 not working, so I have to change to OpenGL. But I'm not familiar with GLSL. I give up after a few hours trying to solve it:
vertex shader.
I'm a bit confused: DX9 is dropped on 2.1. On 2.0 you can and should use DX9 or the older OpenGL RS.
Take in mind old GL's glsl syntax is different from the GL3+'s.

Are you using GL3+ on 2.1, or GL on 2.0?
Transporter
Minaton
Posts: 933
Joined: Mon Mar 05, 2012 11:37 am
Location: Germany
x 110

Re: Compositor system

Post by Transporter »

Thanks for your help!
Kojack wrote:What's the intended effect here? I tried the shader in rendermonkey, it ran, but was just a black window.
gl_FragCoord is a 4d value with x,y pixel coordinates, z is depth and w is 1/w.
If you use gl_FragCoord for a texture coordinate, it gives values in the range 0,0 to window width, window height (not 1,1). So in a window that's 1024 across, you are repeating the texture 1024 times. You need to divide gl_FragCoord by the window dimensions to get a distribution of 0,0 to 1,1 that texture lookup will like.
Thanks a lot! I'll try it ;-)

Code: Select all

uniform sampler2D textureA;
uniform sampler2D textureB;
uniform sampler2D textureC;

void main() {
   vec2 coord = vec2(gl_FragCoord.x / 1920, 1 - gl_FragCoord.y / 1080);
   vec4 tex = texture(textureB, coord);
   vec4 ppp = texture(textureC, coord);
   vec2 xy = vec2(tex.x, tex.y);
   vec4 vIn = texture(textureA, xy);
   vec4 vOut = vec4(vIn.r * ppp.r, vIn.g * ppp.g, vIn.b * ppp.b, 1.0);
   gl_FragColor = vec4(vOut.r * ppp.a, vOut.g * ppp.a, vOut.b * ppp.a, 1.0);
}
As in http://www.ogre3d.org/forums/viewtopic.php?f=2&t=73197 I also added

Code: Select all

	Ogre::GpuProgramParametersSharedPtr pParams = pass->getFragmentProgramParameters();
	pParams->setNamedConstant("textureA", 0);
	pParams->setNamedConstant("textureB", 1);
	pParams->setNamedConstant("textureC", 2);
to the material
I have a picture now,
Wrong GL
Wrong GL
but it's not correct. It should look like
Working DX9
Working DX9
dark_sylinc wrote:Are you using GL3+ on 2.1, or GL on 2.0?
I'm running 2.0 at the moment, so I have to use GL. Because Ogitor is switching to 2.1, I'll switch to 2.1 and use Gl3+, too. I don't like it but I think I have to create the shaders for all render systems to be safe that the program is running with 2.0 and 2.1 in various cases.
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5586
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1413
Contact:

Re: Compositor system

Post by dark_sylinc »

Transporter wrote:
dark_sylinc wrote:Are you using GL3+ on 2.1, or GL on 2.0?
I'm running 2.0 at the moment, so I have to use GL. Because Ogitor is switching to 2.1, I'll switch to 2.1 and use Gl3+, too. I don't like it but I think I have to create the shaders for all render systems to be safe that the program is running with 2.0 and 2.1 in various cases.
OK I see. Well, then I'll have to explain a few things.
Just because both have 'GL' on it doesn't really mean they're the same thing.

Old GL uses old glsl syntaxes (glsl, glsl130, glsl140). New GL3+ uses the new syntaxes (glsl330, glsl400 glsl410 glsl420 glsl430 glsl440). Technically glsl150 also belongs to GL3+ but I recommend against it.
The GL3+ render system allows you to use the older syntaxes, but IMHO that is asking for trouble with the GL driver when compiling; as no implementation is really maintaining those syntaxes anymore. I do not know if the old GL RS allows you to use glsl330 and up. May be you're lucky.

The syntaxes are quite similar but not the same. For example your sample code is mixing a lot of stuff.
Your vertex shader contains "gl_ModelViewProjectionMatrix" which is available <= glsl150; but not in the later versions.
Your pixel shader uses "texture" to sample textures in glsl330 and afterwards. Whereas <= glsl150 you need to use texture2D, textureCube, texture3D, texture1D, etc. Someone figgured out in >= glsl330 that the sampler type could be automatically inferred from the sampler's declaration.

For example < glsl330 you have to use "attribute" (inputs to vertex shaders) and "varying" (outputs from vs, and inputs to pixel shaders), in >= glsl330 you have to use "in" and "out".

Basically, >= glsl330 equals a sane nice language on par to hlsl. < glsl330 is a bloody mess.

Mixing stuff from multiple languages is a very bad idea. Some GL drivers will silently allow it, others will warn you, and others will outrightly refuse to compile.

So if you thought using glsl in 2.0 will save you from any hassle when moving to 2.1; you're wrong. In fact, I might dare say it's easier to port from hlsl to glsl330 than from older glsl to glsl330.
Perhaps you're lucky and glsl330 does indeed work in the old gl RS.

I highly recommend you keep an eye on the glsl documentation for each language: Tip: By writing "#version 330" at the top of the shader, you're telling the compiler you want glsl330
scrawl
OGRE Expert User
OGRE Expert User
Posts: 1119
Joined: Sat Jan 01, 2011 7:57 pm
x 220

Re: Compositor system

Post by scrawl »

I do not know if the old GL RS allows you to use glsl330 and up.
Yes it does.
Post Reply