Using references (mental ray)
Reference parameter enables a shader to receive a list of objects from the scene that it can then grab data off of (such as translation, visibility flags, or geometry) to use insider the shader.
A reference parameter uses the reference widget for picking objects in the UI and the commands AddObjectsToShader (http://softimage.wiki.avid.com/sdkdocs/AddObjectsToShader.htm) and RemoveObjectsFromShader (http://softimage.wiki.avid.com/sdkdocs/RemoveObjectsFromShader.htm) to modify the same list from scripting.
| Table of contents |
Using it in a SPDL
A reference parameter can be specified in a SPDL like this:
Parameter "object_list"
{
GUID = "{7636CC21-51CE-11D4-AEE8-0090275AE282}";
Type = Reference;
}
To ensure that the reference widget is being used, the parameter's UI definition in the Defaults section of the SPDL should be defined like this:
Defaults
{
object_list
{
UIType = "ReferenceWidget.ReferenceWidget.1";
}
}
The ReferenceWidget widget takes a couple of optional parameters which are described below.
Single- or multi-selection
The optional parameter "mode" can be used to set the reference widget to multi- or single-selection by setting it to the string "multi" or "single", respectively. By default the widget is in multi-selection mode.
Here's an example of how to set the reference widget to a single selection mode:
Defaults
{
object_list
{
UIType = "ReferenceWidget.ReferenceWidget.1"
{
"mode" = "single";
}
}
}
| Note that there's no semi-colon after the closing brace of the parameter block
|
Object filter
There's another optional parameter, "filter", that can be used to control which objects should be included in the picking list. It takes a single GUID. Unfortunately it is, for some reason lost in the mist of time, based on interface ID, rather than object IDs. A list of common interface IDs to filter in common object types is listed below.
Here's an example of how to set the reference widget to filter for objects only:
Defaults
{
object_list
{
UIType = "ReferenceWidget.ReferenceWidget.1"
{
"filter" = "{6B579D20-3DC5-11D0-9449-00AA006D3165}";
}
}
}
Here's a list of common object types in XSI and their corresponding interface IDs:
| Type | Interface ID |
|---|---|
| Any 3DObject | {6B579D20-3DC5-11D0-9449-00AA006D3165} |
| Null | {7DD91AA4-89D8-11D0-A75C-00AA00BB6238} |
| Camera | {1152E9B0-545E-11D0-8466-00A024C7919C} |
| Light | {E9F25E60-520D-11d0-8298-00A0243E366B} |
Hierarchy mode
It has a single optional UI flag which controls whether the each object reference is a reference to only the object picked or the object and its children. By default, only the object itself is given. To get the object hierarchy instead, the reference parameter can be declared thus:
Parameter "object_list"
{
GUID = "{7636CC21-51CE-11D4-AEE8-0090275AE282}";
Type = Reference;
UI "hierarchy" = true;
}
Using object lists in a mental ray shader
Using the object list in mental ray is relatively straightforward. The only thing that needs to be taken care of is the object hiearchy received, which depends on whether the parameter is set to receive only a single object or the object including children.
Below is an example hierarchy of objects in XSI and the corresponding hierarchy as it appears in mental ray:
|
|
Blue triangles are miInstance objects, yellow circles are miGroup objects, and the green boxes are geometry representations, the type of which depends on how they're generated.
|
If the reference parameter is set to receive only the object, the object tag received will point to the miInstance shaded in blue. If it is set to receive the hierarchy, the object tag received will point to the miInstance shaded in red.
| In all cases is it the
miInstance that immediately instantiates geometry in the diagram above that holds the transform and visibility flags. The label can be found on the geometry itself. |
Code example
The example doesn't include the main body of the shader, only the _init section.
#include <shader.h>
#include <geoshader.h>
typedef struct
{
int i_object;
int n_object;
miTag object[ 1 ];
int i_hierarchy;
int n_hierarchy;
miTag hierarchy[ 1 ];
} reference_test_t;
miUint get_instance_label( miTag object_inst )
{
miTag object_geo;
miUint object_label = 0;
mi_query( miQ_INST_ITEM, NULL, object_inst, (void *)&object_geo );
if( mi_db_type( object_geo ) == miSCENE_GROUP )
{
// Polymeshes and hair split objects up into a group of instances of
// geometry.
mi_query( miQ_GROUP_LABEL, NULL, object_geo, (void *)&object_label );
}
else if( mi_db_type( object_geo ) == miSCENE_OBJECT )
{
// NURBS don't.
mi_query( miQ_OBJ_LABEL, NULL, object_geo, (void *)&object_label );
}
else
{
mi_warning( "Unknown geometry type on object '%s'", mi_api_tag_lookup( object_inst ) );
}
return( object_label );
}
extern "C" DLLEXPORT void
reference_test_init
(
miState *state,
reference_test_t *params,
miBoolean *inst_init_req
)
{
if( params == NULL )
{
*inst_init_req = miTRUE;
return;
}
int i;
// Loop over the non-hiearchy object list first.
mi_info( "Single objects:\n" );
for( i = 0; i < params->n_object; i++ )
{
miTag object_inst = params->object[ params->i_object + i ];
mi_info( " Object %d is '%s' with label %d\n",
i + 1,
mi_api_tag_lookup( object_inst ),
get_instance_label( object_inst ) );
}
// Only list object referred to and its immediate children.
// Recursive enumeration is left as an exercise for the reader.
mi_info( "Object hierarchy:\n" );
for( i = 0; i < params->n_hierarchy; i++ )
{
miTag hierarchy_inst = params->hierarchy[ params->i_hierarchy + i ];
// Get to the group that holds the children and the object itself.
// The object itself is *always* the first one in the list.
miTag group_tag;
int group_nkids;
mi_query( miQ_INST_ITEM, NULL, hierarchy_inst, (void *)&group_tag );
mi_query( miQ_GROUP_NKIDS, NULL, group_tag, (void *)&group_nkids );
// Get the first kid of the group. That'll be the object itself.
// NOTE: The fifth argument is the kid index.
miTag object_inst;
mi_query( miQ_GROUP_KID, NULL, group_tag, (void *)&object_inst, 0 );
mi_info( " Parent object is '%s' with label %d\n",
mi_api_tag_lookup( object_inst ),
get_instance_label( object_inst ) );
for( int j = 1; j < group_nkids; j++ )
{
miTag subhrc_inst;
// To get to the actual child object, we'll have to first grab the
// miInstance that instantiates its miGroup that holds the child
// object and all of its (possible) children.
mi_query( miQ_GROUP_KID, NULL, group_tag, (void *)&subhrc_inst, j );
miTag subgroup_tag;
mi_query( miQ_INST_ITEM, NULL, subhrc_inst, (void *)&subgroup_tag );
mi_query( miQ_GROUP_KID, NULL, group_tag, (void *)&object_inst, 0 );
mi_info( " Child object %d is '%s' with label %d\n",
j + 1,
mi_api_tag_lookup( object_inst ),
get_instance_label( object_inst ) );
}
}
}
The corresponding SPDL is:
SPDL
Version = "2.0.0.0";
Reference = "{2E233074-FE99-495E-B45D-BFA40031D95F}";
PropertySet "reference_test_pset"
{
Parameter "out" output
{
GUID = "{8DB160ED-70C7-4D14-B18E-7271EA4D6901}";
Type = vector;
}
Parameter "object" input
{
GUID = "{F2E3C864-B4D5-4FB5-9C39-A8B096F6AE30}";
Type = reference;
}
Parameter "hierarchy" input
{
GUID = "{EDF39BFA-E16C-47AD-8CB6-01CFB8154E8A}";
Type = reference;
UI "hierarchy" = true;
}
}
MetaShader "reference_test_meta"
{
Name = "Reference Test";
Type = texture;
Renderer "mental ray"
{
Name = "reference_test";
FileName = "reference_test";
Options
{
"version" = 1;
}
}
}
Defaults
{
object
{
UIType = "ReferenceWidget.ReferenceWidget.1";
}
hierarchy
{
UIType = "ReferenceWidget.ReferenceWidget.1";
}
}
Layout "Default"
{
object;
hierarchy;
}




