newspeoplefor developersdocumentationdownloads

Render Context
[Scene System]

This document explains what render contexts are, and how to use them.

Stateless

All visual nodes, derived from nSceneNode, are designed to be stateless, so that they can be attached to the scene graph multiple times within a frame. Some visual nodes, like the particle and character nodes, require persistant data between frames. Within core Nebula, this persistant data is usually stored in a server object, and the render context is used to identify which instance of a visual node that data is for.

An example. We have a hierarchy of visual nodes that represent an animated figure, and wish to render a group of these figures. The hierarchy of visual nodes will be attached to the scene graph multiple times, once for each figure we want to render. A different render context should be created for each figure, which allows the character server to store the state information for each figure. Every time the figure is attached to the scene graph, the render context should be passed in the Attach() function. When we're done with a figure the render context can be destroyed, and the character server can delete the data.

Usage

For each game entity, the application should assign a unique render context, then call nSceneNode::RenderContextCreated. This only needs to be done for the root of a tree of visual nodes. So in the example above, if the figure nodes are stored in /lib/visuals/figure1, then only call this function on that visual node, not on any children of that node.

Generally this can be done in your game entity class. Every game entity that has a visual representation (tree of visual nodes) should call nSceneNode::RenderContextCreated on the root of it's visual node tree when the game entity is created/initialised. The same render context should be passed in to nSceneServer::Attach(), every time the root node is attached. Then call nSceneNode::RenderContextDestroyed when the game entity is deleted or not in use. The simplest way to assign the render context is to have a 'global' variable that is increased for each game entity.

This code shows how render context can be initialized and updated.

First, application specific variables which are created by nVariableServer are added to render context. Also a scene node which is the root node of node hierarchy should be specified to the render context. Then the render context is created by calling the root node's RenderContextCreated()

Note:
A scene node is not directly attached to scene server but render context is. Then a scene server will call nSceneNode::Attach for all of it's child nodes and scene nodes are added to group array which is internal data storage of scene server. Thess nodes which are in group array is split by it's attribute (e.g. by it has geomtery or light and so on) before it is rendered.
    // Initialize the render context
    nFloat4 wind = { 1.0f, 0.0f, 0.0f, 0.5f };
    nVariable::Handle timeHandle = varServer->GetVariableHandleByName("time");
    nVariable::Handle oneHandle  = varServer->GetVariableHandleByName("one");
    nVariable::Handle windHandle = varServer->GetVariableHandleByName("wind");
    renderContext.AddVariable(nVariable(timeHandle, 0.5f));
    renderContext.AddVariable(nVariable(oneHandle, 1.0f));
    renderContext.AddVariable(nVariable(windHandle, wind));
    
    // Specify the root node to render context.
    // Note that render context can be only specified on the root node of 
    // scene nodes
    renderContext.SetRootNode(rootNode.get());
    rootNode->RenderContextCreated(&renderContext);

Render context is updated whenever a scene is rendered then passed to scene server.

    // Update render context
    renderContext.GetVariable(timeHandle)->SetFloat((float)time);
    renderContext.SetFrameId(frameId++);
    ...
    // Attach render context to scene server.
    if (sceneServer->BeginScene(viewMatrix))
    {
        sceneServer->Attach(&renderContext);
        sceneServer->EndScene();
        ...
    } 

By render context, various application data type can be specified on visual node and passed to scene server. A frame id, transform matrix and so on are that. This is helpful to decouple visual node and scene server but also use one visual node multiple times. Also this is useful to handle shader variables. Variables which should be passed to shader system are processed in nSceneNode::RenderShader override member function before it is rendered.

See also:
nRenderContext, nVariable for what render context it is and nSwingShapeNode::RenderShader for knowing that how render context can be used for shader variables.

Copyright © 1999-2005 by the contributing authors. Ideas, requests, problems: Send feedback.