Buffers and windows, encapsulated in the GraphicsBuffer and GraphicsWindow classes are almost interchangable in Panda. In fact most operations in the GraphicEngine class are defined on and return GraphicOutput objects, the class that both GraphicsBuffer and GraphicsWindow inherit from. Therefore, we will discuss the properties of GraphicOutput 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 length 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 whats in it 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')
| </td>
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')
| </td>
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 Conrol.
#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()
|
|