MULTIPASS OVERVIEW Multipass rendering technically refers to any process in which the scene, or parts of the scene, are rendered more than once, and the results combined in some way to produce the output image. There are a number of ways to do this in Panda. Instancing, for instance, is technically a form of multipass rendering, since the instanced object is rendered multiple times, each in a different position and/or state. For instance, highlighting an object in pview with the 'h' key uses this weak form of multipass rendering to draw a red wireframe image around the highlighted object. This document doesn't deal with this or other simple forms of multipass rendering within a single scene graph; instead, it focuses on the specific form of multipass rendering in which a scene graph is rendered offscreen into a texture, and that texture is then applied to the primary scene in some meaningful way. OFFSCREEN BUFFERS To support offscreen rendering, Panda provies the GraphicsBuffer class, which works exactly like GraphicsWindow except it corresponds to some part of the framebuffer which is not presented in a window. In fact, both classes inherit from a common base class, GraphicsOutput, on which most of the interfaces for rendering are defined. There are a number of ways to make a GraphicsBuffer. At the lowest level, you can simply call GraphicsEngine::make_buffer(), passing in the required dimensions of your buffer, similar to the way you might call GraphicsEngine::make_window(). To create a buffer specifically for rendering into a texture for multipass, it's best to use the GraphicsOutput::make_texture_buffer() interface, for instance from your main window: GraphicsOutput *new_buffer = win->make_texture_buffer(); This will create a buffer suitable for rendering offscreen into a texture. It will make a number of appropriate preparations for you; for instance, it will ensure that the new buffer uses the same GSG as the source window; it will set up the new buffer for rendering to a texture, and it will order the new buffer within the GraphicsEngine so that its scene will be rendered before the scene in the main window. (And furthermore, the return value might not actually be a GraphicsBuffer pointer, particularly on platforms that don't support offscreen rendering. In this case, it will return a ParasiteBuffer, which actually renders into the main window's back buffer before the window is cleared to draw the main frame. But for the most part you can ignore this detail.) Once you have the buffer pointer, you can set up its scene just as you would any Panda window. In particular, you must create at least one display region, to which you bind a camera and a lens, and then you must assign a scene to the camera (that is, the root of some scene graph, e.g. "render"). GraphicsLayer *layer = buffer->get_channel(0)->make_layer(); DisplayRegion *dr = layer->make_display_region(); PT(Camera) camera = new Camera("camera"); camera->set_lens(new PerspectiveLens()); camera->set_scene(render); NodePath camera_np = render.attach_new_node(camera); dr->set_camera(camera_np); You can also create any number of additional layers and/or display regions, as you choose; and you may set up the camera with any camera mask, initial state, or lens properties you require. There's no need for the camera to be assigned to "render", specifically; it can render any scene you wish, including a sub-node within your render scene graph. The buffer created from make_texture_buffer() will have an associated Texture object, which will contain the output of the render and is suitable for applying to the scene in your main window. (To satisfy the power-of-2 requirements for texture sizes on many graphics cards, you should ensure that your size parameters to make_texture_buffer() specified a power-of-2 size.) You can extract this Texture and set various properties on it, then apply it to geometry: Texture *tex = buffer->get_texture(); tex->set_minfilter(SamplerState::FT_linear_mipmap_linear); screen.set_texture(tex); PER-CAMERA SCENE GRAPH PROPERTIES When there are multiple cameras viewing the same scene, you may need to adjust the camera properties differently on the different cameras if you don't want all the cameras to draw the scene in exactly the same way. Of course, each Camera is a separate node, and may be positioned or rotated differently from all the other Cameras, or they may be set up to share a common parent so that they always move together. You can use the camera mask to hide and show nodes on a per-camera basis. Each camera has a 32-bit DrawMask associated with it, which is initially set to all bits on, but you can assign an arbitrary bit mask to each camera in use on a particular scene--typically you will assign each camera a unique single bit. When you use NodePath::hide() and show() interfaces, you may specify an optional DrawMask value, which indicates the set of cameras for which you are hiding or showing the node (the default is all bits on, which means for all cameras). You can associate an initial state with the camera. This state is applied to all nodes in the scene graph as if it were set on the root node. This can be used to render the entire scene in a modified state (for instance, with textures disabled, or in wireframe mode). If you need more exotic control of the scene graph, such that particular nodes are rendered in a certain state with one camera but in a different state with another camera, you can use the tag_state interface on camera. This uses the PandaNode tag system to associate tag values with state definitions. The idea is to specify a tag_key string on the camera, and one or more tag_value strings, each with an associated RenderState pointer. Then you may call node->set_tag(tag_key, tag_value) on any abitrary set of nodes; when these nodes are encountered in the scene graph during rendering, it will be as if they have the associated state set on them.