WxPython + pyogre Performance Issue

Khemka86

07-12-2009 08:50:06

Hie all,

I am working on wxpython + pyogre, it seems that when i am using wx.frame and doing rendering using ogre the fps is reduced to 10 times .
I have tested the same code using sampleFramework.py through which fps is 10times higher.

So ,this is really a serious problem for lovers of WxPython + pyogre.
I am using wx.timers to ask ogre to render a frame. Is timers are creating problem?

Also, i am using some key navigation events which is also delaying .
there is a time delay of 40 ms between two consecutive keyevents (key is pressed)
I am unable to detect ,why is this performance hampered?

Pls reply..

Thnx in advance

Vinay K

dermont

08-12-2009 13:28:15

Instead of a timer, maybe handle wx.EVT_IDLE and render the frame in your OnIdle function:
http://www.ogre3d.org/forums/viewtopic.php?f=1&t=50502

dermont

15-12-2009 12:05:04

Here's an example on Linux using shared context. I'm not a WX/wxpython user so if anyone wants to tidy it up feel free:


#!/usr/bin/python
import wx
import wx.glcanvas
import sys
import os
sys.path.insert(0,'..')
import PythonOgreConfig
import ogre.renderer.OGRE as ogre


class wxOgreCanvas(wx.glcanvas.GLCanvas):
"""A simple class for using Ogre with wxPython."""

def __init__(self, parent,sharedContext):
## Open GL attributes
attribList = [
wx.glcanvas.WX_GL_MIN_RED, 8,
wx.glcanvas.WX_GL_MIN_GREEN, 8,
wx.glcanvas.WX_GL_MIN_BLUE, 8,
#glcanvas.WX_GL_STENCIL_SIZE, 8,
wx.glcanvas.WX_GL_DOUBLEBUFFER,
wx.glcanvas.WX_GL_DEPTH_SIZE, 24
]

#wx.glcanvas.GLCanvas.__init__(self, parent, wx.ID_ANY, attribList=attribList,
# pos=wx.DefaultPosition,size=wx.DefaultSize, style=wx.FULL_REPAINT_ON_RESIZE)

canvas = wx.glcanvas.GLCanvasWithContext(parent, sharedContext,wx.ID_ANY, attribList=attribList, pos=wx.DefaultPosition,size=wx.DefaultSize, style=wx.FULL_REPAINT_ON_RESIZE)
self.PostCreate(canvas)

self.mRenderWindow = None
self.mSceneManager = None
self.mCamera = None
self.mViewport = None
self.mAnimState = None
self.bInitiliased = False
self.mPrimaryWindow = False
self.renderFrame=True

# Set the event handlers.
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackGround) ## stop flickering windows ??
self.Bind(wx.EVT_SIZE, self.OnResize)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_IDLE, self.OnIdle)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
self.Bind(wx.EVT_CHAR, self.OnKeyDown)
self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
self.Bind(wx.EVT_KILL_FOCUS, self.OnLoseFocus)

# set canvas attributes
self.SetMinSize(wx.Size(300,300));
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)

def canRender(self):
return not self.mRenderWindow is None

def Initialise(self):
"""Create Ogre RenderWindow and Scene."""

mRoot = ogre.Root.getSingletonPtr()
ClientSize = self.GetClientSize()
self.SetCurrent()

# create render window based on shared context
suffix = str(self.GetId())
params = ogre.NameValuePairList()
params["currentGLContext"] = "true";
self.mRenderWindow = mRoot.createRenderWindow("OGRE Render Window" + suffix, ClientSize.x, ClientSize.y, False, params)
self.mSceneManager = mRoot.createSceneManager(ogre.ST_GENERIC, "OgreTest" + suffix)
self.mCamera = self.mSceneManager.createCamera("TestCam" + suffix)

# Camera
self.mCamera.setPosition(ogre.Vector3(0, 0, 500))
self.mCamera.lookAt(ogre.Vector3(0, 0, -300))
self.mCamera.setAutoAspectRatio(False)
self.mCamera.setNearClipDistance(5)

# Set the viewport
self.mViewport = self.mRenderWindow.addViewport(self.mCamera)

# Set up viewport/window
self.setBackgroundColour(ogre.ColourValue(0.4, 0.4, 0.4))
self.resizeRenderWindow( ClientSize.x, ClientSize.y)

# resources only initialised once
if (self.mPrimaryWindow):
ogre.ResourceGroupManager.getSingleton().initialiseAllResourceGroups()

self.mSceneManager.setAmbientLight(ogre.ColourValue(1.0, 1.0, 1.0))

# Create entity and attach it to a scene node
ent = self.mSceneManager.createEntity("Robot" + suffix, "robot.mesh")
node = self.mSceneManager.getRootSceneNode().createChildSceneNode("RobotNode" + suffix)
node.attachObject(ent)
self.mAnimState = ent.getAnimationState("Walk")
self.mAnimState.setEnabled(True)
self.mAnimState.setLoop(True)

def resizeRenderWindow(self, width, height):
"""Resize Ogre Render Window."""
if self.canRender():
self.mRenderWindow.resize(width, height)
self.mRenderWindow.windowMovedOrResized()
if ( (height>0) and (width>0) ):
self.mCamera.setAspectRatio(float(width) / float(height))
self.mViewport._updateDimensions()

def setBackgroundColour(self, col):
if self.mViewport:
self.mViewport.setBackgroundColour(col)

def updateAnimation(self):
"""Update Scene Animation."""
self.mAnimState.addTime(self.mRenderWindow.getBestFPS()/10000.0)

def updateRenderWindow(self, bSwapBuffers):
"""Render Ogre Frame."""
if self.canRender() and self.renderFrame:
self.SetCurrent()
self.renderFrame = False
self.SetCurrent()
mRoot = ogre.Root.getSingleton()
mRoot._fireFrameStarted()
self.mRenderWindow.update(bSwapBuffers)
mRoot._fireFrameRenderingQueued() ## needed for anim
mRoot._fireFrameEnded()
self.renderFrame = True

def OnEraseBackGround(self, event):
"""Stub to avoid flashing on Windows."""
pass

def OnIdle(self, event):
"""Update Ogre RenderWindow/ Animation etc."""

# todo implement simple timer, no guarentee when OnIdle may be called
# so will lead to jerky animation
if self.canRender():
self.updateAnimation()
self.updateRenderWindow(False)
self.SwapBuffers()
event.RequestMore(True)

def OnKeyDown( self, event ):
"""Simple Key Event Handling."""
keycode = event.GetKeyCode()
key=''
if keycode < 255:
key = chr(keycode)

if ( keycode == wx.WXK_RIGHT or key == 'A' ):
self.mCamera.moveRelative(ogre.Vector3(-2,0,0))
elif ( keycode == wx.WXK_LEFT or key == 'D' ):
self.mCamera.moveRelative(ogre.Vector3(2,0,0))
elif ( keycode == wx.WXK_DOWN or key == 'W'):
self.mCamera.moveRelative(ogre.Vector3(0,0,2))
elif ( keycode == wx.WXK_UP or key == 'S'):
self.mCamera.moveRelative(ogre.Vector3(0,0,-2))
event.Skip()
self.Refresh(False)

def OnLoseFocus(self, event):
self.setBackgroundColour(ogre.ColourValue(0.4, 0.4, 0.4))
event.Skip()

def OnPaint(self, event):
"""Paint Event, create Ogre RenderWindow on first paint to ensure valid context for Ogre to share."""
##wxAutoBufferedPaintDC dc(this);
self.SetCurrent()
if not self.bInitiliased:
mRoot = ogre.Root.getSingletonPtr()
# first render window
if (mRoot.getRenderSystem() is None):
self.mPrimaryWindow = True
else:
self.mPrimaryWindow = False

## create ogre render system if not already created, creation defered to ensure Ogre
##can (automatically) obtain and share the GLCanvas's Display pointer.
if (self.mPrimaryWindow):
rsys = mRoot.getRenderSystemByName("OpenGL Rendering Subsystem")
# Some standard rendering system configurations
rsys.setConfigOption("Full Screen", "No")
rsys.setConfigOption("VSync", "No")
#rsys.setConfigOption("Display Frequency", "60 MHz")
rsys.setConfigOption("FSAA", "0")
rsys.setConfigOption("RTT Preferred Mode", "FBO")
rsys.setConfigOption("sRGB Gamma Conversion", "No")
mRoot.setRenderSystem(rsys)
##mRoot.restoreConfig();
mRoot.initialise(False)
self.Initialise()
self.bInitiliased = True

def OnResize(self, evt):
"""Resize Event Handling."""
self.resizeRenderWindow( evt.GetSize().x, evt.GetSize().y)
self.Refresh(False)
evt.Skip()

def OnSetFocus(self, event):
self.setBackgroundColour(ogre.ColourValue(0.6, 0.6, 0.6))
event.Skip()

class OgreFrame( wx.Frame):
def __init__(self, parent, title, pos=wx.DefaultPosition, size=wx.DefaultSize):
wx.Frame.__init__(self,parent, wx.ID_ANY, title, pos)
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)

self.menuFile = wx.Menu()
item = self.menuFile.Append( wx.ID_EXIT, "E&xit" )
self.menuBar = wx.MenuBar()
self.menuBar.Append( self.menuFile, "&File" )
self.SetMenuBar( self.menuBar )
self.Bind(wx.EVT_MENU, self.OnExit, item )

self.CreateStatusBar()
self.SetStatusText( "Welcome to wxWindows!" )
self.SetMinSize(wx.Size(300,300))

self.sizer = wx.GridSizer(2,2,hgap=5, vgap=5)
self.SetAutoLayout(True)
self.mOgreCanvas = wxOgreCanvas(self, None)
self.Show() # need this here to obtain initial context
self.mOgreCanvas2 = wxOgreCanvas(self, self.mOgreCanvas.GetContext())
self.mOgreCanvas3 = wxOgreCanvas(self, self.mOgreCanvas.GetContext())
self.mOgreCanvas4 = wxOgreCanvas(self, self.mOgreCanvas.GetContext())
self.sizer.Add(self.mOgreCanvas2, 0, wx.ALL|wx.EXPAND)
self.sizer.Add(self.mOgreCanvas, 1, wx.ALL|wx.EXPAND)
self.sizer.Add(self.mOgreCanvas3, 2, wx.ALL|wx.EXPAND)
self.sizer.Add(self.mOgreCanvas4, 3, wx.ALL|wx.EXPAND)
self.SetSizerAndFit(self.sizer)
self.Layout()

def OnExit(self, event):
self.Close(True)

class MainApp( wx.App):
def __init__(self):
wx.App.__init__(self)
self.mFrame = None

plugin_path = os.path.join(os.getcwd(),'..','plugins.cfg.posix')
if not os.path.exists(plugin_path):
sys.stderr.write("\n"
"** Warning: Unable to locate a suitable plugins.cfg file.\n"
"** Warning: Please check your ogre installation and copy a\n"
"** Warning: working plugins.cfg file to the current directory.\n\n")
#raise ogre.Exception(0, "can't locate a suitable 'plugins' file", "")
exit(1)

self.root = ogre.Root(plugin_path, "ogre.config", "ogre.log")
config = ogre.ConfigFile()
config.load('../resources.cfg')
seci = config.getSectionIterator()
while seci.hasMoreElements():
SectionName = seci.peekNextKey()
Section = seci.getNext()
for item in Section:
ogre.ResourceGroupManager.getSingleton().\
addResourceLocation(item.value, item.key, SectionName)

def OnCleanUp(self):
if not self.root is None:
del self.root

def OnInit(self):
self.mFrame = OgreFrame(None, "Ogre Render Test")
self.SetTopWindow(self.mFrame)
return True

def main():
app = MainApp()
app.MainLoop()
app.OnCleanUp()
app.Destroy()

if __name__ == "__main__":
main()