Panda3D Manual: The GraphicsOutput class
<<prev | top | next>> |
Buffers and windows, encapsulated in the `GraphicsBuffer` and `GraphicsWindow` classes are almost interchangable in Panda. In fact most operations in the `GraphicsEngine` class are defined on and return `GraphicsOutput` objects, the class that both `GraphicsBuffer` and `GraphicsWindow` inherit from. Therefore, we will discuss the properties of `GraphicsOutput` objects first. The first very important note is that none of these classes are not meant to be constructed directly, i.e.:
    myOutput=GraphicsOutput()
    myWindow=GraphicsWindow()
    myBuffer=GraphicsBuffer()
will not work. Refer to The Graphics Engine for how to create these objects. Furthermore, since `GraphicsOutput` is an abstract class, `GraphicsWindow` objects will be used in code examples. All `GraphicsOutput` objects have `getGsg()`, `getPipe()`, and `getName()` which return respectively their GraphicsStateGuardian, GraphicsPipe, and name. You can also get the width and height using `getXSize()` and `getYSize()`.
    from pandac.PandaModules import GraphicsWindow

    #assume we already have a window setup and in myWindow
    myWindowGsg=myWindow.getGsg()
    myWindowPipe=myWindow.getPipe()
    myWindowName=myWindow.getName()

    myWindowWidth=myWindow.getXSize()
    myWindowLength=myWindow.getYSize()
You can also save a screenshot from any `GraphicsOutput` by using `saveScreenShot(fileName)`, where `fileName` is the name of the picture(the format of the picture is specified by the extension of `filename`). Returns `True` upon succes and `False` otherwise. The picture is saved in the directory of the script you are running.
    from pandac.PandaModules import Filename
    myWindow.saveScreenShot(Filename('hello.bmp'))
This naturally flows into rendering into a texture. We'll start with copying a scene. If you want to get a texture that simply copies what's in its `GraphicsOutput` object, you must first make a call to `setupCopyTexture()`. You can then get the texture by using `getTexture()`. You can now apply the texture to a NodePath as you would a texture loaded from memory. Thanks to the magic of pointers, the texture automatically updates itself if the contents of its `GraphicsOutput` change. If you do not want this behaviour you should use `detachTexture()` when you no longer want the textute to be updated. However, since the first frame is always blank, the best way to use `detachTexture()` is in a do-later task or event.
    myWindow.setupCopyTexture()
    myTexture=myWindow.getTexture()

    #assume myModel is already setup
    myModel.setTexture(myTexture)

    #and if you want to stop the texture from updating itself
    def stopUpdating():
       global myWindow
       myWindow.detachTexture()
    taskMgr.doMethodLater(1,stopUpdating,'stops updating')
While this is helpful, you may want to render an entirely new scene into a `GraphicsOutput` and then place it on screen (i.e. you have a televsion in your main scene and want to generate the show on the spot). The first thing you do is create a `GraphicsOutput` to hold the scene. You do this by calling `makeTextureBuffer`. It makes a `GraphicsOutput` specifically for rendering a scene and then retrieving it by `getTexture()`.
    makeTextureBuffer(name, xSize, ySize)
The arguments `name`, `xSize`, and `ySize` mean the same things they do for makeWindow and makeBuffer.
    You then have to create a new camera for the new scene, using
    base.makeCamera(win, sort=0, scene=None,
      displayRegion=(0,1,0,1), aspectRatio=None, camName='cam')
Here's a break down of what the parameters mean:
`win` | The `GraphicsOutput` object that you want to make the camera for
`sort` | The sort value of the camera. Decides the order in which `DisplayRegion`s in the same window are drawn. See API for more information.
`scene` | Due to deprecation of other functions this parameter does not affect anything.
`displayRegion` | The area of the new `GraphicsOutput` that you want to cover in the form (left start point, right end point, bottom start point, top end point). (0,0) represent the bottom left of the screen and (1,1) represents the top right. Therefore (0,1,0,1) represents the entire area. Arguments must be between 0 and 1.
`aspectRatio` | The aspectRatio of the `GraphicsOutput`. When this is left to `None` `makeCamera` uses the aspectRatio of the default window.
`camName` | The name of the node that represents this camera in the scene graph
Cameras render whatever is connected to their ancestors in the scene graph. Therefore if you want a truly independent scene you have to start a new scene graph. Create a dummy NodePath and now `reparentTo` the new camera to this node. Now you can treat the new scene and the new camera like you would render and your scene gets drawn to your `GraphicsOuptut`. However, any state changes you make to the NodePath `camera` will no longer affect your new camera. Also, since the standard mouse controls work on the `camera` NodePath, these will not work either. You can alternatively use the Camera class method `setScene(scenePath)`, where `scenePath` is the top of the scene graph you want to draw. This preserves the standard heirarchy stated in Camera Control.
    # I use a GraphicsBuffer only because this is a process you
    # probably want the user to see
    myBuffer=myWindow.makeTextureBuffer("Another Scene", 800,600)

    # You must pass a string to the NodePath constructor or
    # attempts to set it as a parent will remove the child from the graph
    myNewScene=NodePath("myRender")
    myNewCamera=base.makeCamera(myBuffer)
    myNewCamera.reparentTo(myNewScene)
    #or myNewCamera.node().setScene(myNewScene)

    #You can now get a texture that represents anything
    # you do in this new scene (that is still automatically updated)
    myTexture=myBuffer.getTexture()
<<prev | top | next>> |