Scenegraph Generation

When exporting to Shockwave 3D§, each type of scene asset is placed in a separate table in the Shockwave 3D database, where it is referenced by name or by index. These tables can be built gradually as the authoring tool's scenegraph is traversed, or populated in a single up-front operation.

For example, you can populate the Shockwave 3D database with all the materials used by a scene before you traverse the scenegraph, and then add all models in the scene to the database, pointing those models to the materials they use. Alternatively, you can collect all information as you go, creating the materials used by an object at the same time that you create the object in Shockwave 3D. In this second case, be sure to query Shockwave 3D first to make sure the material doesn't already exist in the database. If it does, point your newly converted model to the existing copy of the material.

To illustrate how data is put into the Shockwave 3D database, consider the simple case of adding a node to the scenegraph palette, a high-level data structure that defines the scene hierarchy. Some elements in the scenegraph palette are high-level containers that point to many other collections of Shockwave 3D data (for example, model resources point to materials, mesh geometry, and motions), while others simply help define the scene hierarchy and use no additional resources (for example, group nodes).

Sample Code: Group Node Creation

The most basic example of adding an element into the Shockwave 3D database is the creation of a group node. Group nodes are simply parent "handles" that let you manipulate their children (scene elements consisting of models, lights, and cameras) in a single, bulk operation.

The process of putting a group node into Shockwave 3D involves three general steps:

1. Create the group node and point it to its parent.

2. Add the group node to the scene hierarchy palette by name.

3. Define the node's local transformation matrix.

Note that the following code assumes that you have already initialized the Shockwave 3D database with a call to S3DSceneGraphUtils::Init():


IFXRESULT CIFXMAXSceneGraphConverter::AddGroupToScene(INode *pCurrMAXNode, 
IFXNode *pParentRushNode,
IFXNode **ppNewRushNode)
{
IFXRESULT ifxResult = IFX_OK;
IFXUnknown *pGroup = NULL;
IFXNode *pIFXGroupNode;
U32 uGroupNodeId;
CIFXString *pMAXNodeName;
I32 CurrentMAXNodeType = 0;



if (!pCurrMAXNode || !pParentRushNode)
ifxResult = IFX_E_INVALID_POINTER;
        if ( IFXSUCCESS(ifxResult) )
ifxResult = m_MAXNodeUtils.GetMAXNodeType( pCurrentMAXNode,
&CurrentMAXNodeType );


if ( IFXSUCCESS(ifxResult) && (MAX_GROUPNODE != CurrentMAXNodeType))
ifxResult = IFX_E_INVALID_POINTER;
  //----
// Create an IFXNode to hold this group and point it to its parent
//----
         if ( IFXSUCCESS(ifxResult) )
ifxResult = IFXCreateComponent( CID_IFXGroup, IID_IFXUnknown,
(void**)&pGroup );

if ( IFXSUCCESS(ifxResult) )
ifxResult = pGroup->QueryInterface( IID_IFXNode, (void**)&pIFXGroupNode );

if ( IFXSUCCESS(ifxResult) )
ifxResult = pIFXGroupNode->Initialize( m_pSceneGraph );

if ( IFXSUCCESS(ifxResult) )
ifxResult = pIFXGroupNode->SetParent( pParentRushNode );
//----
// Add the group to the node hierarchy palette (of type IFXPalette)
//----
// Get the name of this 3D Studio MAX§ group node
 

if ( IFXSUCCESS(ifxResult) )
{

      TCHAR nodeName[ PATH_SIZE ];
_stprintf( nodeName, "%s", pMAXNode->GetName() );
      *pMAXNodeName = new CIFXString( nodeName )
}


// Create a named entry in the node hierarchy palette for this
// group.
       if ( IFXSUCCESS(ifxResult) )
ifxResult = m_pNodePalette->Add( pMAXNodeName, &uGroupNodeId );

IFXDELETE( pMAXNodeName );
// Point the palette to the group node, using the ID returned by the
// last call.
   if ( IFXSUCCESS(ifxResult) )
ifxResult = m_pNodePalette->SetResourcePtr( uGroupNodeId,
(IFXUnknown*)pIFXGroupNode );
//----
// Set the local transformation matrix for the group node
// Ideally this would be in a subroutine, but you need to
// see it here.
//----
if ( IFXSUCCESS(ifxResult) )
{
// get the MAX node's world space matrix
Matrix3 MAXWSMatrix = pMAXNode->GetNodeTM( 0 );
BOOL bHasBipedRoot = FALSE;
if ( IFXSUCCESS(ifxResult) )
ifxResult = m_MAXNodeUtils.WillContainBipedRoot( pMAXNode &bHasBipedRoot );


// Don't apply scaling to biped structures - those scale themselves.
if (IFXSUCCESS(ifxResult) && (bHasBipedRoot))
MAXWSMatrix = MAXMathUtils::RemoveMatrixScaling( MAXWSMatrix );
// convert the MAX node's world space matrix to an IFXSGMatrix
Point3 row[4];
for ( I32 i = 0; i < 4; i++ )
row[i] = MAXWSMatrix.GetRow( i );
IFXSGVector r[4];
for ( i = 0; i < 4; i++ )
r[i] = IFXSGVector( row[i].x, row[i].y, row[i].z, 0 );
IFXSGMatrix IFXWSMatrix( r[0], r[1], r[2], r[3] ); 
// get the world space matrix of the parent IFX node
IFXSGMatrix* pIFXParentWSMatrix;
result = pParentRushNode->GetWorldMatrixRef( &pIFXParentWSMatrix );
// define IFX node's transform with respect to its parent world matrix
IFXSGMatrix IFXLocalMatrix;
if ( IFXSUCCESS(ifxResult) )
IFXLocalMatrix = ( pIFXParentWSMatrix->inverse() ) * IFXWSMatrix;
if ( IFXSUCCESS(ifxResult) )
ifxResult = pIFXGroupNode->SetMatrix( &IFXLocalMatrix );
// set world space matrix of current IFX node
IFXSGMatrix* pIFXWSMatrixRef;
if ( IFXSUCCESS(ifxResult) )
ifxResult = pIFXGroupNode->GetWorldMatrixRef( &pIFXWSMatrixRef );
if ( IFXSUCCESS(ifxResult) )
*pIFXWSMatrixRef = IFXWSMatrix;
}
 
//----
// set user properties
//----
if ( IFXSUCCESS(result) )
ifxResult = ExportUserProperties( pMAXNode, pIFXGroupNode );
//----
// Pass back the pointer to the IFXNode for the group in the scenegraph database
//----
if ( IFXSUCCESS(ifxResult) )
*ppNewRushNode = pIFXGroupNode;
else
*ppNewRushNode = NULL;
// Clean up.
if (pGroup)
IFXRELEASE(pGroup);

if (pIFXGroupNode)
IFXRELEASE(pIFXGroupNode);

return ifxResult;

}

Sample Code: Creating a Light Resource

Creating more complex entities involves additional steps, which create resources and add the entity to the appropriate palette. For example, creating a light involves all of the above code, plus code to create and populate a light resource object that holds information about the light (such as its brightness and type), and code to add the light to the light resource palette.

The Light Resource is created as follows:

IFXLightResource* pIFXLightResource;

if ( IFXSUCCESS(ifxResult) )
ifxResult = IFXCreateComponent( CID_IFXLightResource, IID_IFXLightResource,
(void**)&pIFXLightResource );

if ( IFXSUCCESS(ifxResult) )
ifxResult = pIFXLightResource->Initialize( m_pSceneGraph );

Now set the light's properties, including its type and color:

ifxResult = pLightResource->SetType( IFXLightType );

if ( IFXSUCCESS(ifxResult) )
ifxResult = pLightResource->SetColor(IFXSGVector(LightInfo.color.r, LightInfo.color.g, LightInfo.color.b) );

Once all the data for the light is entered, the light resource is added to the light resource palette, and the IFXNode for the light (found in the scene hierarchy palette) is informed of the light resource through its index in the light resource palette.

if ( IFXSUCCESS(ifxResult) )
ifxResult = m_pLightPalette->Add( cMAXNodeName, &uLightNodeId );

if ( IFXSUCCESS(ifxResult) )
ifxResult = m_pLightPalette->SetResourcePtr( uLightNodeId, pResource );

// Point our light's IFX node to its new resources.

if ( IFXSUCCESS(ifxResult) )
ifxResult = pNode->QueryInterface( IID_IFXLight, (void**)&pLightNode );

if ( IFXSUCCESS(ifxResult) )
ifxResult = pLightNode->SetLightResourceID( uLightNodeId );

if (pIFXLightResource)
IfxRelease(pIFXLightResource);

if (pLightNode)
IfxRelease(pLightNode);

 

 

§See asterisked (*) statement at Legal Information © 2001 Intel Corporation.