Ogre Version: 13.5.2
Operating System: Linux (Manjaro)
Render System: OpenGL 3+ Rendering Subsystem
I've been trying to create two render windows, each with their own camera and viewport. Unfortunately I haven't had any luck, and no matter what I try nothing gets rendered to the 2nd window.
To keep it simple I've modified BasicTutorial2 (the ninja), and created 2x render windows using the OgreBites::ApplicationContext framework.
From studying the ApplicationContext source code, I believe it supports multiple window creation and uses SDL external windows. (I've also tried without the framework and have the same problem.)
Several older posts indicate that if using multiple render windows, you should use a custom render loop instead of using Root::startRendering(). The OGRE source code seems to iterate through all render targets, so I couldn't see why a custom render loop is necessary. Anyway I changed to a custom render loop, updating each render window and still nothing on the second window.
When I changed to a custom render loop I noticed something unusual. The second render window (mWindowB), is actually rendering on the first/primary window. I can tell this because the first window flickers alternating between the 2 camera views as each window updates in the render loop. Furthermore, if I don't use mWindowA at all, mWindowB still renders on the first/primary window instead of the second window!
Could anyone please let me know why 2 render windows isn't working? Thanks
Screenshot:
Code:
Code: Select all
#include <exception>
#include <iostream>
#include "Ogre.h"
#include "OgreApplicationContext.h"
#include "OgreInput.h"
#include "OgreRTShaderSystem.h"
#include "OgreCameraMan.h"
#include "OgreWindowEventUtilities.h"
using namespace Ogre;
using namespace OgreBites;
class TutorialApplication
: public ApplicationContext
, public InputListener
{
public:
TutorialApplication();
virtual ~TutorialApplication();
void setup();
bool keyPressed(const KeyboardEvent& evt);
Root* mRoot;
RenderWindow* mWindowA;
RenderWindow* mWindowB;
bool mShouldQuit;
};
TutorialApplication::TutorialApplication()
: ApplicationContext("OgreTutorialApp")
{
mShouldQuit = false;
}
TutorialApplication::~TutorialApplication()
{
}
void TutorialApplication::setup()
{
ApplicationContext::setup();
addInputListener(this);
mRoot = getRoot();
SceneManager* scnMgr = mRoot->createSceneManager();
//Get first render window already created by the framework.
//Note: I set vsync to false in the dialog.
mWindowA = getRenderWindow();
//Create second render window using the framework (not directly with Root::createRenderWindow).
NativeWindowPair natWinPairB = createWindow("Render Window B", 300, 300);
mWindowB = natWinPairB.render;
mWindowB->setActive(true);
mWindowB->setVisible(true);
addInputListener(natWinPairB.native, this);
RTShader::ShaderGenerator* shadergen = RTShader::ShaderGenerator::getSingletonPtr();
shadergen->addSceneManager(scnMgr);
//Create cameras for each render window
SceneNode* camNodeA = scnMgr->getRootSceneNode()->createChildSceneNode();
SceneNode* camNodeB = scnMgr->getRootSceneNode()->createChildSceneNode();
Camera* camA = scnMgr->createCamera("myCam A");
Camera* camB = scnMgr->createCamera("myCam B");
camNodeA->setPosition(200, 300, 400);
camNodeB->setPosition(-200, 300, 400);
camNodeA->lookAt(Vector3(0, 0, 0), Node::TransformSpace::TS_WORLD);
camNodeB->lookAt(Vector3(0, 0, 0), Node::TransformSpace::TS_WORLD);
camA->setNearClipDistance(5);
camB->setNearClipDistance(5);
camNodeA->attachObject(camA);
camNodeB->attachObject(camB);
//Create viewports for each render window
Viewport* vpA = mWindowA->addViewport(camA);
Viewport* vpB = mWindowB->addViewport(camB);
vpA->setBackgroundColour(ColourValue(0, 0, 0));
vpB->setBackgroundColour(ColourValue(0, 0, 0));
camA->setAspectRatio(Real(vpA->getActualWidth()) / Real(vpA->getActualHeight()));
camB->setAspectRatio(Real(vpB->getActualWidth()) / Real(vpB->getActualHeight()));
//Setup scene
scnMgr->setAmbientLight(ColourValue(0, 0, 0));
scnMgr->setShadowTechnique(ShadowTechnique::SHADOWTYPE_STENCIL_ADDITIVE);
Entity* ninjaEntity = scnMgr->createEntity("ninja.mesh");
ninjaEntity->setCastShadows(true);
scnMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ninjaEntity);
Plane plane(Vector3::UNIT_Y, 0);
MeshManager::getSingleton().createPlane(
"ground", RGN_DEFAULT,
plane,
1500, 1500, 20, 20,
true,
1, 5, 5,
Vector3::UNIT_Z);
Entity* groundEntity = scnMgr->createEntity("ground");
scnMgr->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity);
groundEntity->setCastShadows(false);
groundEntity->setMaterialName("Examples/Rockwall");
Light* spotLight = scnMgr->createLight("SpotLight");
spotLight->setDiffuseColour(0, 0, 1.0);
spotLight->setSpecularColour(0, 0, 1.0);
spotLight->setType(Light::LT_SPOTLIGHT);
SceneNode* spotLightNode = scnMgr->getRootSceneNode()->createChildSceneNode();
spotLightNode->attachObject(spotLight);
spotLightNode->setDirection(-1, -1, 0);
spotLightNode->setPosition(Vector3(200, 200, 0));
spotLight->setSpotlightRange(Degree(35), Degree(50));
Light* directionalLight = scnMgr->createLight("DirectionalLight");
directionalLight->setType(Light::LT_DIRECTIONAL);
directionalLight->setDiffuseColour(ColourValue(0.4, 0, 0));
directionalLight->setSpecularColour(ColourValue(0.4, 0, 0));
SceneNode* directionalLightNode = scnMgr->getRootSceneNode()->createChildSceneNode();
directionalLightNode->attachObject(directionalLight);
directionalLightNode->setDirection(Vector3(0, -1, 1));
Light* pointLight = scnMgr->createLight("PointLight");
pointLight->setType(Light::LT_POINT);
pointLight->setDiffuseColour(0.3, 0.3, 0.3);
pointLight->setSpecularColour(0.3, 0.3, 0.3);
SceneNode* pointLightNode = scnMgr->getRootSceneNode()->createChildSceneNode();
pointLightNode->attachObject(pointLight);
pointLightNode->setPosition(Vector3(0, 150, 250));
}
bool TutorialApplication::keyPressed(const KeyboardEvent& evt)
{
if (evt.keysym.sym == SDLK_ESCAPE)
{
mShouldQuit = true;
getRoot()->queueEndRendering();
}
return true;
}
int main(int argc, char **argv)
{
try
{
TutorialApplication app;
app.initApp();
//app.getRoot()->startRendering();
//Custom render loop as follows:
app.mWindowA->setAutoUpdated(false);
app.mWindowB->setAutoUpdated(false);
app.mRoot->clearEventTimes();
while(!app.mShouldQuit)
{
app.mWindowA->update(false);
app.mWindowA->swapBuffers();
app.mWindowB->update(false);
app.mWindowB->swapBuffers();
app.mRoot->renderOneFrame();
OgreBites::WindowEventUtilities::messagePump();
}
app.closeApp();
}
catch (const std::exception& e)
{
std::cerr << "Error occurred during execution: " << e.what() << '\n';
return 1;
}
return 0;
}
Partial log output:
Code: Select all
RenderSystem::_createRenderWindow "OgreTutorialApp", 640x480 windowed miscParams: FSAA=0 displayFrequency=N/A
externalWindowHandle=96468994 gamma=No sdlwin=94434177551072 vsync=No vsyncInterval=1
RenderSystem::_createRenderWindow "Render Window B", 300x300 windowed miscParams: FSAA=0 currentGLContext=true displayFrequency=N/A
externalWindowHandle=96468996 gamma=No sdlwin=94434201478160 vsync=No vsyncInterval=1