[1.11.2] Dynamic Resolution Topic is solved

Problems building or running the engine, queries about how to use features etc.
Post Reply
rpgplayerrobin
Goblin
Posts: 214
Joined: Wed Mar 18, 2009 3:03 am
x 83

[1.11.2] Dynamic Resolution

Post by rpgplayerrobin »

Ogre Version: 1.11.2
Operating System: Windows 10
Render System: Direct3D9

Hello!

I am trying to get dynamic resolution working, but it seems I have went into a dead end.

I have searched for an hour without seeing anyone attempting to do this in Ogre.

As far as I understand, there is a default scene compositor that renders everything to the backbuffer in the window (createOriginalScene / _getOriginalSceneCompositor), but it seems to be very troublesome to change that compositor.

If possible, I would want to replace the default scene compositor with another one, like:

Code: Select all

compositor DynamicResolution
{
	technique
	{
        	texture scene 1024 512 PF_R8G8B8

		target scene
        	{
            		input none

            		pass clear
			{
			}
			pass render_scene
			{
			}
        	}

        	target_output
        	{
            		input none

            		pass render_quad
            		{
                		material DynamicResolution
                		input 0 scene
            		}
       		}
	}
}
But it seems to be very hard to actually switch this out... How do I actually do this?

Is there an easier way of doing all this?
I altered the resolution of the viewport, but that only changes where it actually renders on the backbuffer, which does me no good...

paroj
OGRE Team Member
OGRE Team Member
Posts: 1352
Joined: Sun Mar 30, 2014 2:51 pm
x 588
Contact:

Re: [1.11.2] Dynamic Resolution

Post by paroj »

whats wrong with

Code: Select all

Ogre::CompositorManager::getSingleton().setCompositorEnabled(viewport, "DynamicResolution", true);

rpgplayerrobin
Goblin
Posts: 214
Joined: Wed Mar 18, 2009 3:03 am
x 83

Re: [1.11.2] Dynamic Resolution

Post by rpgplayerrobin »

The problem is that the original scene will still be rendered, right? That code will not disable the default compositor I guess.
I want the original render to render at a lower resolution.

Having a dynamic resolution is meant to bring the FPS up in intensive situations, so having the exact same performance (or even worse) by just enabling it on top on the other compositors is something I do not want.

paroj
OGRE Team Member
OGRE Team Member
Posts: 1352
Joined: Sun Mar 30, 2014 2:51 pm
x 588
Contact:

Re: [1.11.2] Dynamic Resolution

Post by paroj »

rpgplayerrobin wrote:
Mon Feb 22, 2021 1:10 pm
The problem is that the original scene will still be rendered, right?
no. the "original scene" is only used for "input previous" of the first compositor in a chain.

rpgplayerrobin
Goblin
Posts: 214
Joined: Wed Mar 18, 2009 3:03 am
x 83

Re: [1.11.2] Dynamic Resolution

Post by rpgplayerrobin »

I don't see how that is right... The compositor chain has a default compositor created by "createOriginalScene", which creates "mOriginalScene".
That is always used.

I tried the code you showed me, but the FPS stayed the same (or even got worse).
However, when I alter the default compositor (created by "createOriginalScene") I do get much higher FPS.

To be clear, I want to alter the FIRST render, not create a new compositor, but alter the first render itself.
Otherwise dynamic resolution (to save performance) would never work.

paroj
OGRE Team Member
OGRE Team Member
Posts: 1352
Joined: Sun Mar 30, 2014 2:51 pm
x 588
Contact:

Re: [1.11.2] Dynamic Resolution

Post by paroj »

rpgplayerrobin wrote:
Mon Feb 22, 2021 1:44 pm
That is always used.
sounds like a bug. It should not be triggered if we dont need the results.

Anyway.. try this as a workaround

Code: Select all


		target scene
        	{
            		input previous
        	}

rpgplayerrobin
Goblin
Posts: 214
Joined: Wed Mar 18, 2009 3:03 am
x 83

Re: [1.11.2] Dynamic Resolution

Post by rpgplayerrobin »

I tried it your way now, and it did increase FPS, but not by that much at all for some reason, only by around 10% more FPS when I lowered it to 128 x 64. I did it like this:

Code: Select all

compositor DynamicResolution
{
	technique
	{
        	texture scene 128 64 PF_R8G8B8

		target scene
        	{
			input previous
        	}

        	target_output
        	{
            		input none

            		pass render_quad
            		{
                		material DynamicResolution
                		input 0 scene
            		}
        	}
	}
}

And by doing this in the code once:

CompositorManager::getSingleton().addCompositor(app->m_Camera->getViewport(), "DynamicResolution");
CompositorManager::getSingleton().setCompositorEnabled(app->m_Camera->getViewport(), "DynamicResolution", true);

But it seems I found another rather OK way of doing all of this. It works, but it is a bit of a hack.
When I do 128 x 64 here, the FPS is increased by around 40%, so it seems this code is better than trying it with a new compositor than altering the existing one.
Here is the code:

Code: Select all

// Constructor for the CDynamicResolutionManager
CDynamicResolutionManager::CDynamicResolutionManager()
{
	// Reset the last render scale value
	m_lastRenderScaleValue = 100;

	// Set that we are using the default compositor
	m_isUsingDefaultCompositor = true;
}

// Destructor for the CDynamicResolutionManager
CDynamicResolutionManager::~CDynamicResolutionManager()
{
}

// Setups the compositor
void CDynamicResolutionManager::SetupCompositor()
{
	// Get the compositor chain from the camera and check if it is valid
	CompositorChain* tmpCompositorChain = CompositorManager::getSingleton().getCompositorChain(app->m_Camera->getViewport());
	if (tmpCompositorChain)
	{
		// Get the compositor instance and check if it is valid
		CompositorInstance* tmpCompositorInstance = tmpCompositorChain->_getOriginalSceneCompositor();
		if (tmpCompositorInstance)
		{
			// Get the compositor technique and check if it is valid
			CompositionTechnique* tmpCompositorTechnique = tmpCompositorInstance->getTechnique();
			if (tmpCompositorTechnique)
			{
				// Get the material scheme and visibility mask from the camera
				CString tmpMaterialScheme = app->m_Camera->getViewport()->getMaterialScheme();
				uint tmpVisibilityMask = app->m_Camera->getViewport()->getVisibilityMask();

				// Clear the compositor
				tmpCompositorTechnique->removeAllTargetPasses();
				tmpCompositorTechnique->removeAllTextureDefinitions();
				CompositionTargetPass* tmpOutputTargetPass = tmpCompositorTechnique->getOutputTargetPass();
				if (tmpOutputTargetPass)
					tmpOutputTargetPass->removeAllPasses();

				// Check if we should use the default compositor
				if (m_isUsingDefaultCompositor)
				{
					/*
						target_output
						{
							pass clear
							{
								/// Clear frame
							}
							pass render_scene
							{
								visibility_mask FFFFFFFF
								render_queues SKIES_EARLY SKIES_LATE
							}
						}
					*/

					CompositionTargetPass* tmpCompositionTargetPass = tmpCompositorTechnique->getOutputTargetPass();
					tmpCompositionTargetPass->setVisibilityMask(0xFFFFFFFF);

					CompositionPass* tmpCompositionPass = tmpCompositionTargetPass->createPass();
					tmpCompositionPass->setType(CompositionPass::PT_CLEAR);

					tmpCompositionPass = tmpCompositionTargetPass->createPass();
					tmpCompositionPass->setType(CompositionPass::PT_RENDERSCENE);
					tmpCompositionPass->setFirstRenderQueue(RENDER_QUEUE_BACKGROUND);
					tmpCompositionPass->setLastRenderQueue(RENDER_QUEUE_SKIES_LATE);
				}
				else
				{
					/*
						texture scene 1024 512 PF_R8G8B8

						target scene
						{
							input none

							pass clear
							{
							}
							pass render_scene
							{
							}
						}

						target_output
						{
							input none

							pass render_quad
							{
								material DynamicResolution
								input 0 scene
							}
						}
					*/

					CompositionTechnique::TextureDefinition* tmpTextureDefinition = tmpCompositorTechnique->createTextureDefinition("scene");
					tmpTextureDefinition->width = 10;
					tmpTextureDefinition->height = 10;
					tmpTextureDefinition->formatList.push_back(Ogre::PF_R8G8B8);

					CompositionTargetPass* tmpCompositionTargetPass = tmpCompositorTechnique->createTargetPass();
					tmpCompositionTargetPass->setInputMode(CompositionTargetPass::IM_NONE);
					tmpCompositionTargetPass->setOutputName("scene");

					CompositionPass* tmpCompositionPass = tmpCompositionTargetPass->createPass();
					tmpCompositionPass->setType(CompositionPass::PT_CLEAR);

					tmpCompositionPass = tmpCompositionTargetPass->createPass();
					tmpCompositionPass->setType(CompositionPass::PT_RENDERSCENE);
					tmpCompositionPass->setFirstRenderQueue(RENDER_QUEUE_BACKGROUND);
					tmpCompositionPass->setLastRenderQueue(RENDER_QUEUE_SKIES_LATE);



					tmpOutputTargetPass->setInputMode(CompositionTargetPass::IM_NONE);

					tmpCompositionPass = tmpOutputTargetPass->createPass();
					tmpCompositionPass->setType(CompositionPass::PT_RENDERQUAD);
					tmpCompositionPass->setMaterialName("DynamicResolution");
					tmpCompositionPass->setInput(0, "scene");
				}

				// Update the material schemes and visibility masks
				if (tmpOutputTargetPass)
				{
					tmpOutputTargetPass->setMaterialScheme(tmpMaterialScheme);
					tmpOutputTargetPass->setVisibilityMask(tmpVisibilityMask);
				}
				CompositionTechnique::TargetPasses tmpTargetPasses = tmpCompositorInstance->getTechnique()->getTargetPasses();
				for (size_t n = 0; n < tmpTargetPasses.size(); n++)
				{
					tmpTargetPasses[n]->setMaterialScheme(tmpMaterialScheme);
					tmpTargetPasses[n]->setVisibilityMask(tmpVisibilityMask);
				}

				// Make sure the textures are destroyed (they are created later when setting the real resolution)
				tmpCompositorInstance->setAlive(false);

				// Compile the compositor chain
				//tmpCompositorChain->_compile();
			}
		}
	}
}

// Updates the CDynamicResolutionManager
void CDynamicResolutionManager::Update()
{
	// Check if the render scale value has changed
	int tmpCurrentRenderScaleValue = 100;
	if (app->m_Keyboard->isKeyDown(OIS::KC_1)) tmpCurrentRenderScaleValue = 90;
	if (app->m_Keyboard->isKeyDown(OIS::KC_2)) tmpCurrentRenderScaleValue = 80;
	if (app->m_Keyboard->isKeyDown(OIS::KC_3)) tmpCurrentRenderScaleValue = 70;
	if (app->m_Keyboard->isKeyDown(OIS::KC_4)) tmpCurrentRenderScaleValue = 60;
	if (app->m_Keyboard->isKeyDown(OIS::KC_5)) tmpCurrentRenderScaleValue = 50;
	if (app->m_Keyboard->isKeyDown(OIS::KC_6)) tmpCurrentRenderScaleValue = 40;
	if (app->m_Keyboard->isKeyDown(OIS::KC_7)) tmpCurrentRenderScaleValue = 30;
	if (app->m_Keyboard->isKeyDown(OIS::KC_8)) tmpCurrentRenderScaleValue = 20;
	if (app->m_Keyboard->isKeyDown(OIS::KC_9)) tmpCurrentRenderScaleValue = 10;
	if(m_lastRenderScaleValue != tmpCurrentRenderScaleValue)
	{
		// Set the new last render scale value value
		m_lastRenderScaleValue = tmpCurrentRenderScaleValue;

		// Check if we have changed the compositor target
		bool tmpUseDefaultCompositor = m_lastRenderScaleValue == 100;
		if (tmpUseDefaultCompositor != m_isUsingDefaultCompositor)
		{
			// Setup the compositor
			m_isUsingDefaultCompositor = tmpUseDefaultCompositor;
			SetupCompositor();
		}

		// Check if we are not using the default compositor
		if (!m_isUsingDefaultCompositor)
		{
			// Get the compositor chain from the camera and check if it is valid
			CompositorChain* tmpCompositorChain = CompositorManager::getSingleton().getCompositorChain(app->m_Camera->getViewport());
			if (tmpCompositorChain)
			{
				// Get the compositor instance and check if it is valid
				CompositorInstance* tmpCompositorInstance = tmpCompositorChain->_getOriginalSceneCompositor();
				if (tmpCompositorInstance)
				{
					// Get the compositor technique and check if it is valid
					CompositionTechnique* tmpCompositorTechnique = tmpCompositorInstance->getTechnique();
					if (tmpCompositorTechnique)
					{
						// Get the scene texture definition and check if it is valid
						CompositionTechnique::TextureDefinition* tmpTextureDefinition = tmpCompositorTechnique->getTextureDefinition("scene");
						if (tmpTextureDefinition)
						{
							// Update the compositor render scale
							tmpTextureDefinition->width = size_t(float(app->m_Window->getWidth()) * (float(m_lastRenderScaleValue) * 0.01f));
							tmpTextureDefinition->height = size_t(float(app->m_Window->getHeight()) * (float(m_lastRenderScaleValue) * 0.01f));

							// Adjust the pixels to become as close to the wanted aspect ratio of the window
							const int tmpMinMaxValue = 10;
							if (tmpTextureDefinition->width > tmpMinMaxValue &&
								tmpTextureDefinition->height > tmpMinMaxValue)
							{
								float tmpWantedAspectRatio = float(app->m_Window->getWidth()) / float(app->m_Window->getHeight());
								float tmpBeforeAspectRatio = float(tmpTextureDefinition->width) / float(tmpTextureDefinition->height);
								float tmpClosest = FLT_MAX;
								int tmpClosestX = 0;
								int tmpClosestY = 0;
								for (int x = -tmpMinMaxValue; x <= tmpMinMaxValue; x++)
								{
									for (int y = -tmpMinMaxValue; y <= tmpMinMaxValue; y++)
									{
										float tmpCurrentAspectRatio = float(tmpTextureDefinition->width + x) / float(tmpTextureDefinition->height + y);
										float tmpDistanceCurrent = abs(tmpWantedAspectRatio - tmpCurrentAspectRatio);
										if (tmpDistanceCurrent < tmpClosest)
										{
											tmpClosest = tmpDistanceCurrent;
											tmpClosestX = x;
											tmpClosestY = y;
										}
									}
								}
								if (tmpClosest != FLT_MAX)
								{
									tmpTextureDefinition->width += tmpClosestX;
									tmpTextureDefinition->height += tmpClosestY;
								}
							}

							// Make sure the textures are created
							tmpCompositorInstance->setAlive(false);
							tmpCompositorInstance->setAlive(true);
						}
					}
				}
			}
		}
	}
}
Holding the 1-9 keys will show that it works to do dynamic resolution this way, which is pretty nice.
Now just to actually do an automatic system for this to keep a wanted FPS.

The "DynamicResolution" material is just a basic material that looks like this:

Code: Select all

material DynamicResolution
{
	technique
	{
		pass
		{
			lighting off
			cull_hardware none
			cull_software none
			depth_check off
			polygon_mode_overrideable false

			texture_unit
			{
				filtering none
			}
		}
	}
}

paroj
OGRE Team Member
OGRE Team Member
Posts: 1352
Joined: Sun Mar 30, 2014 2:51 pm
x 588
Contact:

Re: [1.11.2] Dynamic Resolution

Post by paroj »

I would of course prefer, if you could find the root-cause in Ogre so we can fix this for everybody instead of everybody having to apply this workaround.

rpgplayerrobin
Goblin
Posts: 214
Joined: Wed Mar 18, 2009 3:03 am
x 83

Re: [1.11.2] Dynamic Resolution

Post by rpgplayerrobin »

It seems there is no bug, doing it correctly ( :oops: ) in the code with a compositor seems to be equal to altering the original (createOriginalScene) compositor.

I found that it matters where I use the CompositorManager::getSingleton().addCompositor.
When I wrote that using it as a real compositor only increased FPS by 10%, that was because it was not added as the first compositor (another compositor was added before this one).
When I add it as the first compositor, I do get the same results as when I altered the "createOriginalScene" compositor.

So it seems to only be an application-specific issue.

Though I do not understand how that compositor can make the original (createOriginalScene) compositor not have any effect, but as you said, it is only used for "input previous", so I guess it looks on my real compositor and sees that while only rendering it at the scale I want it rendered at, and ignoring the first full-window render that it would have used normally.

Below is an adjusted version (so it should work for anyone) of my "minimum FPS with dynamic resolution" feature.
Just supply the "m_dynamicResolution" with a minimum FPS value (0 is disabled and is default in the code).



Compositor:

Code: Select all

compositor DynamicResolution
{
	technique
	{
        	texture scene 1 1 PF_R8G8B8

		target scene
       		{
			input previous
        	}

        	target_output
       		{
            		input none

            		pass render_quad
            		{
                		material DynamicResolution
                		input 0 scene
            		}
        	}
	}
}


Material:

Code: Select all

material DynamicResolution
{
	technique
	{
		pass
		{
			lighting off
			cull_hardware none
			cull_software none
			depth_check off
            		polygon_mode_overrideable false

			texture_unit
			{
  				filtering none
			}
        	}
    	}
}


C++:

Code: Select all

class CDynamicResolution
{
public:
	float m_lastRenderScaleValue;
	clock_t m_lastTime;
	int m_updateCounter;
	bool m_active;
	bool m_compositorAdded;
	int m_dynamicResolution;
	Camera* m_camera;
	RenderWindow* m_window;

	// Constructor for the CDynamicResolution
	CDynamicResolution(Camera* camera, RenderWindow* window)
	{
		// Get the camera
		m_camera = camera;

		// Get the window
		m_window = window;

		// Reset the last render scale value
		m_lastRenderScaleValue = 1.0f;

		// Reset the last time
		m_lastTime = clock();

		// Reset the update counter
		m_updateCounter = 0;

		// Set that we are not active
		m_active = false;

		// Add the compositor to the main camera
		m_compositorAdded = CompositorManager::getSingleton().addCompositor(m_camera->getViewport(), "DynamicResolution", 0) != NULL;

		// Reset the dynamic resolution option
		m_dynamicResolution = 0;
	}

	// Destructor for the CDynamicResolution
	~CDynamicResolution()
	{
		// Check if the current validated effect is a valid compositor
		if (m_compositorAdded && CompositorManager::getSingleton().getByName("DynamicResolution"))
			// Remove the current compositor
			CompositorManager::getSingleton().removeCompositor(m_camera->getViewport(), "DynamicResolution");
	}

	// Updates the CDynamicResolutionManager
	void Update()
	{
		// Check if we are using the dynamic resolution option
		if (m_dynamicResolution > 0)
			// Set that we are active
			m_active = true;

		// Check if we are not active
		if (!m_active)
			// Return the function, we are done
			return;

		// Add one to the number of updates
		m_updateCounter++;

		// Check if enough time has elapsed
		int tmpFPS = 0;
		clock_t tmpCurrentTime = clock();
		const clock_t tmpWaitTime = 100;
		if (tmpCurrentTime - m_lastTime > tmpWaitTime)
		{
			// Calculate the FPS
			tmpFPS = int(float(m_updateCounter) / (float(tmpWaitTime) * 0.001f));

			// Reset the last time
			m_lastTime = tmpCurrentTime;

			// Reset the update counter
			m_updateCounter = 0;
		}
		else
			// Return the function, we are done
			return;

		// Set the current render scale value
		float tmpCurrentRenderScaleValue = m_lastRenderScaleValue;

		// Check if we are using dynamic resolution
		if (m_dynamicResolution > 0)
		{
			// Check if the FPS is far off from the wanted FPS
			float tmpPercentageOff = float(min(tmpFPS, m_dynamicResolution)) / float(max(tmpFPS, m_dynamicResolution));
			if (tmpPercentageOff < 0.8f) // 47 / 60 = 0.78, so this will then alter the render scale
			{
				// Check if the FPS is lower than the wanted FPS
				if (tmpFPS < m_dynamicResolution)
					// Make the render scale lower
					tmpCurrentRenderScaleValue = m_lastRenderScaleValue * 0.8f;
				else
					// Make the render scale higher
					tmpCurrentRenderScaleValue = m_lastRenderScaleValue * 1.1f;
			}
		}
		else
			// Set the render scale value to its maximum value
			tmpCurrentRenderScaleValue = 1.0f;

		// Limit the render scale
		tmpCurrentRenderScaleValue = max(tmpCurrentRenderScaleValue, 0.2f);
		tmpCurrentRenderScaleValue = min(tmpCurrentRenderScaleValue, 1.0f);

		// Check if the render scale value has changed
		if (m_lastRenderScaleValue != tmpCurrentRenderScaleValue)
		{
			// Set the new last render scale value value
			bool tmpOldUseCompositor = m_lastRenderScaleValue != 1.0f;
			m_lastRenderScaleValue = tmpCurrentRenderScaleValue;

			// Check if we have changed the compositor target
			bool tmpUseCompositor = m_lastRenderScaleValue != 1.0f;
			if (tmpUseCompositor != tmpOldUseCompositor)
				// Enable/disable the compositor
				CompositorManager::getSingleton().setCompositorEnabled(m_camera->getViewport(), "DynamicResolution", tmpUseCompositor);

			// Check if we are using the compositor
			if (tmpUseCompositor)
			{
				// Get the compositor chain from the camera and check if it is valid
				CompositorChain* tmpCompositorChain = CompositorManager::getSingleton().getCompositorChain(m_camera->getViewport());
				if (tmpCompositorChain)
				{
					// Get the compositor instance and check if it is valid
					CompositorInstance* tmpCompositorInstance = tmpCompositorChain->getCompositor("DynamicResolution");
					if (tmpCompositorInstance)
					{
						// Get the compositor technique and check if it is valid
						CompositionTechnique* tmpCompositorTechnique = tmpCompositorInstance->getTechnique();
						if (tmpCompositorTechnique)
						{
							// Get the scene texture definition and check if it is valid
							CompositionTechnique::TextureDefinition* tmpTextureDefinition = tmpCompositorTechnique->getTextureDefinition("scene");
							if (tmpTextureDefinition)
							{
								// Update the compositor render scale
								tmpTextureDefinition->width = size_t(float(m_window->getWidth()) * m_lastRenderScaleValue);
								tmpTextureDefinition->height = size_t(float(m_window->getHeight()) * m_lastRenderScaleValue);

								// Adjust the pixels to become as close to the wanted aspect ratio of the window
								const int tmpMinMaxValue = 10;
								if (tmpTextureDefinition->width > tmpMinMaxValue &&
									tmpTextureDefinition->height > tmpMinMaxValue)
								{
									//float tmpBeforeAspectRatio = float(tmpTextureDefinition->width) / float(tmpTextureDefinition->height);
									float tmpWantedAspectRatio = float(m_window->getWidth()) / float(m_window->getHeight());
									float tmpClosest = FLT_MAX;
									int tmpClosestX = 0;
									int tmpClosestY = 0;
									for (int x = -tmpMinMaxValue; x <= tmpMinMaxValue; x++)
									{
										for (int y = -tmpMinMaxValue; y <= tmpMinMaxValue; y++)
										{
											float tmpCurrentAspectRatio = float(tmpTextureDefinition->width + x) / float(tmpTextureDefinition->height + y);
											float tmpDistanceCurrent = abs(tmpWantedAspectRatio - tmpCurrentAspectRatio);
											if (tmpDistanceCurrent < tmpClosest)
											{
												tmpClosest = tmpDistanceCurrent;
												tmpClosestX = x;
												tmpClosestY = y;
											}
										}
									}
									if (tmpClosest != FLT_MAX)
									{
										tmpTextureDefinition->width += tmpClosestX;
										tmpTextureDefinition->height += tmpClosestY;
									}
								}

								// Make sure the textures are created
								tmpCompositorInstance->setAlive(false);
								tmpCompositorInstance->setAlive(true);
								tmpCompositorInstance->setEnabled(true);
							}
						}
					}
				}
			}
			else
				// Set that we are not active
				m_active = false;
		}
	}
};

paroj
OGRE Team Member
OGRE Team Member
Posts: 1352
Joined: Sun Mar 30, 2014 2:51 pm
x 588
Contact:

Re: [1.11.2] Dynamic Resolution

Post by paroj »

rpgplayerrobin wrote:
Wed Feb 24, 2021 1:55 am
I found that it matters where I use the CompositorManager::getSingleton().addCompositor.
yeah, thats a shorthand for getCompositorChain().addCompositor(), which probably explains what is going on.
rpgplayerrobin wrote:
Wed Feb 24, 2021 1:55 am
Though I do not understand how that compositor can make the original (createOriginalScene) compositor not have any effect, but as you said, it is only used for "input previous", so I guess it looks on my real compositor and sees that while only rendering it at the scale I want it rendered at, and ignoring the first full-window render that it would have used normally.
once you enable compositors, you are in full control. If you only have an empty target_output pass, ogre will not render anything. The only exception is "input previous", which is treated as a shorthand for render_scene at position 0.

Post Reply