Process


Description

Fired whenever the rendering engine is requested to perform a process (for example, render a frame). For sequences, all the frames in a sequence will be called before switching to another render job (although the render can be terminated before the sequence is done). This guarantees that the renderer can recycle previous frame's data.

The Process callback uses the RendererContext to retrieve the renderer options property, get Framebuffer information, and send tile data back to the Render Manager.


Applies To

Custom Renderers


Syntax

CStatus <renderer_name>_Process( CRef& in_context )
{ 
        ... 
}

<renderer_name> is the name specified in the call to PluginRegistrar::RegisterRenderer, with any spaces converted to underscores.


Parameters

Parameter Language Type Description
in_context C++ CRef& A reference to the RendererContext object. Context::GetSource returns the Renderer.

Context Attributes

Attribute Type Description
RenderID unsigned int The unique identifier for this particular rendering job. Softimage creates a rendering job whenever it needs a rendered output. So a single pass render is one render job, each shaderball image is a render job, each render region is a separate render job, and so forth.
Process siRenderProcessType The process type requested by the render manager.
RenderType CString The current type of rendering being performed. For example "Pass", "Region" or "Shaderball".
Scene CRefArray of Model objects A list of models that together make up the scene to render. When rendering the current scene, this is simply the scene root model. When rendering shaderballs this can be a composite of the hero object (for example, the apple) and the background object (for example, the checkerboard pattern).
ObjectList CRefArray of X3DObjects (Optional) A subset of objects to render from the scene root(s) given in the "Scene" attribute. These objects override any currently selected object, including the "SelectionOnly" only attribute. The "TrackSelection" attribute also changes its behaviour to enclose the objects given in this list, rather than the current selection.
DirtyList CRefArray of X3DObjects If defined, lists the objects that have been changed since this rendering engine got called last. If the list is empty, then nothing has changed and the user has most likely just requested a refresh of the render. If the attribute is not defined, then the whole scene can be considered as dirty. Use RendererContext::SetObjectClean to selectively remove items from the dirty list so that they don't show up at the next render.
Lights CRefArray of Light objects The list of scene lights. This is more of a convenience list and saves the renderer having to traverse the scene models to grab all the lights and check their visibility, etc..
Camera Primitive The viewing camera Primitive for this render. Use ProjectItem::GetParent3DObject to get the owner X3DObject in order to access the kinematic state and other properties of the camera.
Material Material or Shader The material or shader to use if an object's material has nothing connected to it. This is used for shaderball previews only.
Warning This attribute is not provided for region and pass rendering.
ImageWidth unsigned int The width of the image output in pixels.
ImageHeight unsigned int The height of the image output in pixels.
CropLeft unsigned int The left offset of the crop rectangle.
CropBottom unsigned int The bottom offset of the crop rectangle.
CropWidth unsigned int The width of the crop rectangle.
CropHeight unsigned int The height of the crop rectangle.
SelectionOnly bool Only render objects that are selected.
TrackSelection bool Automatically adjust the crop window to fit the object selection (in screen space). In this case the specified crop values should be ignored.
MotionBlur bool Motion blur enabled.
ShutterSpeed double Shutter open time in frames.
ShutterOffset double Shutter offset in frames.
ShutterType siRenderShutterType The three shutter types (center, end on frame and start on frame).
MotionBlurDeformation bool Motion blur affect deformations and not only transforms.
FileOutput bool Images should be written to disk, otherwise only send fragments.
SkipExistingFiles bool Skip existing files, if they're deemed rendered already. Locking must be done in order for two machines not to overwrite each others' files.
FieldRender bool Field rendering enabled.
FieldInterleave siRenderFieldType Field interleave type ( none, Even/NTSC, Odd/PAL).
ArchiveFileName CString The current frame's archive filename to use. For multi-frame archives, this will be the same filename for all the frames in the sequence.
Note This attribute and the next one are only set if the process type is siRenderProcessExportArchive or siRenderProcessExportObjectArchive.
ArchiveMultiFrame bool Embed all frames into a single archive file.
ArchiveDisplayProxies bool The render engine should generate a set of three images for each exported frame. The images are used to show a cardboard-style representation of the object archive contents in the viewport. The three images are generated as projected on the XY, XZ, and YZ axis planes, looking down the -Z, -Y, and -X axes, respectively, in orthographic camera mode. The camera should also be placed be outside the bounding box in order to capture all the geometry.
Note This attribute is only set if the process type is siRenderProcessExportObjectArchive.
RenderMapList CRefArray of Property objects The list of RenderMap properties to generate coming from the RegenerateMaps command.
Note This attribute is only set if the process type is siRenderProcessRenderMap.
RenderMapTileSize unsigned int The tile size coming from the RegenerateMaps command.
Note This attribute is only set if the process type is siRenderProcessRenderMap.

Return Value

CStatus

The Process callback should return a status code depending upon whether the render succeeded, was aborted or there was an internal failure.

Status Description
CStatus::OK Render completed successfully, in other words, all requested data was successfully written out or passed back to Softimage.
CStatus::Abort This can only be returned if the Process callback is responding to a call to the Abort callback. It should not be returned under any other circumstances.
CStatus::Fail Non-fatal error condition was encountered, such as missing textures, abort request from an event (from the RendererContext::TriggerEvent call), etc. In this case one-shot render operations such as pass renders or exports are canceled. Continuous render operations (such as render region or shaderballs) simply stop updating until refreshed.
(any other failure code) Renderer encountered a catastrophic failure. At this point the whole render job is canceled. If the job was created by the region, the region will close automatically. If the failure happened to a shaderball, that shaderball stops updating.

Examples

//
// Example rendering engine
//

// There is only ever *one* instance of this plug-in running so global variables
// are "ok".

#include <xsi_application.h>
#include <xsi_camera.h>
#include <xsi_context.h>
#include <xsi_decl.h>
#include <xsi_longarray.h>
#include <xsi_math.h>
#include <xsi_pluginregistrar.h>
#include <xsi_renderer.h>
#include <xsi_renderercontext.h>
#include <xsi_customproperty.h>
#include <xsi_ppglayout.h>
#include <xsi_pass.h>
#include <xsi_project.h>
#include <xsi_scene.h>
#include <xsi_passcontainer.h>
#include <xsi_primitive.h>
#include <xsi_x3dobject.h>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

using namespace XSI; 

SICALLBACK XSILoadPlugin( PluginRegistrar& in_reg )
{
        in_reg.PutAuthor(L"Softimage");
        in_reg.PutName(L"Color Renderer");
        in_reg.PutEmail(L"support@softimage.com");
        in_reg.PutURL(L"http://www.softimage.com");
        in_reg.PutVersion(1,0);
        in_reg.RegisterProperty( L"Color Renderer Options" );
        in_reg.RegisterRenderer( L"Color Renderer" );

        return CStatus::OK;
}

////////////////////////////////////////////////////////////////////////////////
// Rendering Engine Section

/*! Abort handling.
*/
static bool                             g_bAborted;
HANDLE                                  g_hAbort;
CRITICAL_SECTION                g_barrierAbort;

void setAbort( bool in_bAbort )
{
        ::EnterCriticalSection( &g_barrierAbort );
        g_bAborted = in_bAbort;
        if( in_bAbort )
                ::SetEvent( g_hAbort );
        else
                ::ResetEvent( g_hAbort );
        ::LeaveCriticalSection( &g_barrierAbort );
}

bool isAborted( )
{
        bool            bAbort;
        ::EnterCriticalSection( &g_barrierAbort );
        bAbort= g_bAborted;
        ::LeaveCriticalSection( &g_barrierAbort );

        return( bAbort );
}


/*! Initialization function for the renderer, called when the
        plug-in is loaded.

        This is where the rendering engine tells the environment what 
        process types it can perform (render, export archives etc.), 
        which property to use for its options and which output formats 
        it supports (and how those formats are defined).

        The renderer can perform any other one-time initialization here also.
*/
SICALLBACK ColorRenderer_Init( CRef &in_ctxt )
{
        Context         ctxt( in_ctxt );
        Renderer        renderer = ctxt.GetSource();

        // Tell the render manager what render processes we support.
        CLongArray      process;
        process.Add( siRenderProcessRender );
        renderer.PutProcessTypes( process );

        // Specify the custom property to use for the renderer options
        renderer.AddProperty( siRenderPropertyOptions, L"Color Renderer.Color Renderer Options" );

        // Add the Softimage PIC format as an output format.
        renderer.AddOutputImageFormat( L"Softimage PIC", L"pic" );
        renderer.AddOutputImageFormatSubType( siRenderChannelColorType, L"RGBA", siImageBitDepthInteger8 );

        // And some arbitrary image format.
        renderer.AddOutputImageFormat( L"Foo Format", L"foo" );
        renderer.AddOutputImageFormatSubType( siRenderChannelColorType, L"RGBA", siImageBitDepthInteger8 );
        renderer.AddOutputImageFormatSubType( siRenderChannelColorType, L"RGBA", siImageBitDepthInteger16 );
        renderer.AddOutputImageFormatSubType( siRenderChannelColorType, L"RGB", siImageBitDepthInteger8 );
        renderer.AddOutputImageFormatSubType( siRenderChannelGrayscaleType, L"Gray", siImageBitDepthInteger16 );

        // Create the handles for a thread-safe abort
        g_bAborted = false;
        ::InitializeCriticalSection( &g_barrierAbort );
        g_hAbort = ::CreateEvent( NULL, FALSE, FALSE, NULL );
        
        return( CStatus::OK );
}


/*! This is called when the plug-in is unloaded.
        The rendering engine should shut down completely and clean 
        out any global data. Any rendering jobs using this engine
        have already been terminated at this point.
*/
SICALLBACK ColorRenderer_Term( CRef &in_ctxt )
{
        ::DeleteObject( g_hAbort );
        ::DeleteCriticalSection( &g_barrierAbort );

        g_hAbort = NULL;
        ::ZeroMemory( &g_barrierAbort, sizeof( g_barrierAbort ) );

        return( CStatus::OK );
}

class MyFragment : public RendererImageFragment
{
public:
        MyFragment( 
                unsigned int in_offX, unsigned int in_offY, unsigned int in_width, unsigned int in_height, 
                double in_color[ 4 ] )
        {
                offX = in_offX;
                offY = in_offY;
                width = in_width;
                height = in_height;

                unsigned int            r, g, b, a;

                r = (unsigned int)( in_color[ 0 ] * 255.0 );
                g = (unsigned int)( in_color[ 1 ] * 255.0 );
                b = (unsigned int)( in_color[ 2 ] * 255.0 );
                a = (unsigned int)( in_color[ 3 ] * 255.0 );

                color = ( a << 24 ) | ( b << 16 ) | ( g << 8 ) | ( r );
        }

        unsigned int GetOffsetX( ) const { return( offX ); }
        unsigned int GetOffsetY( ) const { return( offY ); }
        unsigned int GetWidth( ) const { return( width ); }
        unsigned int GetHeight( ) const { return( height ); }
        bool GetScanlineRGBA( unsigned int in_uiRow, siImageBitDepth in_eBitDepth, unsigned char *out_pScanline ) const
        {
                unsigned int            *pScanline = (unsigned int *)out_pScanline;
                for( unsigned int i = 0; i < width; i++ )
                        pScanline[ i ] = color;

                return( true );
        }

private:
        unsigned int    offX, offY, width, height;
        unsigned int    color;
};

/*! This is the main function that gets called by the render manager
        whenever the rendering engine is requested to perform a process
        (render a frame, export an archive, etc.).

        It is called with a specialized Context object, called RendererContext.
        The RendererContext allows to retrieving the renderer options property,
        getting framebuffer information and sending tile data back to the render 
        manager.
*/
SICALLBACK ColorRenderer_Process( CRef &in_ctxt )
{
        setAbort( false );

        RendererContext ctxt( in_ctxt );
        Renderer                renderer = ctxt.GetSource();

        // The LockSceneData method *must* be called before accessing any potential
        // scene data. This is to ensure that multiple threads do not concurrently access
        // and/or modify the scene data. It is also important that the renderer does *not*
        // modify any scene data at all. It can modify its own private data but nothing
        // that is a part of the scene or the current application state, unless explicitly
        // allowed.
        if( renderer.LockSceneData() != CStatus::OK )
                return( CStatus::Abort );

        Primitive                       camera_prim = ctxt.GetAttribute( L"Camera" );
        X3DObject                       camera_obj      = camera_prim.GetOwners( )[ 0 ];
        Camera                          camera          = camera_obj;
        CString                         camera_name     = camera_obj.GetName();
        const wchar_t           *wcsCameraName = camera_name.GetWideString();

        // Get the size of the image to render (in pixels). The origin is defiend as the
        // bottom-left corner of the image.
        unsigned int            width, height;
        width = (ULONG)ctxt.GetAttribute( L"ImageWidth" );
        height = (ULONG)ctxt.GetAttribute( L"ImageHeight" );

        // Check if there is a crop area defined. If the offset is 0,0 and the crop 
        // width/height is the same as the image width/height, then no cropping should take
        // place. The crop window is always fully inside of the rendered image.
        unsigned int            cropOffsetX, cropOffsetY;
        unsigned int            cropWidth, cropHeight;

        cropOffsetX = (ULONG)ctxt.GetAttribute( L"CropLeft" );
        cropOffsetY = (ULONG)ctxt.GetAttribute( L"CropBottom" );
        cropWidth = (ULONG)ctxt.GetAttribute( L"CropWidth" );
        cropHeight = (ULONG)ctxt.GetAttribute( L"CropHeight" );

        // Get our render property evaluated at the correct time. If rendering fields, any 
        // parameter that is animated, needs to be evaluated at the half-frame in between the
        // current frame and the next frame after. Same goes potentially for motion blur, unless
        // the renderer is incapable of interpolating the data, in which case it should use
        // the current frame as a base.
        CTime           evalTime = ctxt.GetTime();

        Property        myProp = ctxt.GetRendererProperty( evalTime );

        double                  color[ 4 ];
        
        color[ 0 ] = myProp.GetParameterValue( L"Color_R", evalTime );
        color[ 1 ] = myProp.GetParameterValue( L"Color_G", evalTime );
        color[ 2 ] = myProp.GetParameterValue( L"Color_B", evalTime );
        color[ 3 ] = myProp.GetParameterValue( L"Color_A", evalTime );

        // Unlock the scene data *before* we start rendering and sending tile data back.
        renderer.UnlockSceneData();
        
        // Check after the scene data has been evaluted whether the abort flag is set.
        if( isAborted() )
                return( CStatus::Abort );

        // Notify the renderer manager that a new frame is about to begin. This is necessary so
        // that any recipient tile sink can re-adjust its own size to accommodate.
        ctxt.NewFrame( width, height );

        unsigned int     tileSize = 32;

        for( unsigned y = 0; y <= ( cropHeight / tileSize ); y++ )
        {
                for( unsigned x = 0; x <= ( cropWidth / tileSize ); x++ )
                {
                        unsigned int            ox, oy, sx, sy;

                        ox = x * tileSize;
                        oy = y * tileSize;
                        sx = tileSize;
                        sy = tileSize;

                        if( ( ox + tileSize ) > cropWidth )
                                sx = width - ox;
                        else
                                sx = tileSize;

                        if( ( oy + tileSize ) > cropHeight )
                                sy = height - oy;
                        else
                                sy = tileSize;

                        MyFragment              fragment( 
                                ox + cropOffsetX, oy + cropOffsetY, sx, sy, color );

                        // Send back a new tile.
                        ctxt.NewFragment( fragment );

                        DWORD           dwResult = ::WaitForSingleObject( g_hAbort, 40 );
                        if( dwResult != WAIT_TIMEOUT )
                                return( CStatus::Abort );
                }
        }

        return( CStatus::OK );
}

/*! Called by the render manager when the renderer should do a full 
        cleanup of any data that got created by the Process function. 
        This is usually called when the current scene is being destroyed,
        or if the specific render process (region, pass render, export)
        requests that data be cleaned up after the process has completed.
*/
SICALLBACK ColorRenderer_Cleanup( CRef &in_ctxt )
{
        Context         ctxt( in_ctxt );
        Renderer        renderer = ctxt.GetSource();
        
        return( CStatus::OK );
}


/*! Called when the render needs to be aborted. The function should
        trigger an abort and return as quickly as possible. It should
        *not* refer to any scene data and not perform any processing
        besides triggering the abort. It is up to the Process function
        to ensure a clean abort is done upon the receipt of an abort
        signal.
*/
SICALLBACK ColorRenderer_Abort( CRef &in_ctxt )
{
        Context         ctxt( in_ctxt );
        Renderer        renderer = ctxt.GetSource();

        setAbort( true );

        return( CStatus::OK );
}


/*! This function serves two purposes: To return the current "quality"
        level of the render options and to set a preset for the given
        "quality" level. The calculated quality level should be simply
        the value that corresponds to the closest match to a level
        preset.
        \note This mechanism might be aborted shortly and replaced by
                something else that gets handled by Softimage directly.
*/
SICALLBACK ColorRenderer_Quality( CRef &in_ctxt )
{
        Context         ctxt( in_ctxt );
        Renderer        renderer = ctxt.GetSource();

        CValue          quality = ctxt.GetAttribute( L"Quality" );
        Property        prop = ctxt.GetAttribute( L"Property" );

        static const double levels[ 5 ][ 4 ] = {
                { 1.0, 0.0, 0.0, 1.0 },
                { 0.0, 1.0, 0.0, 1.0 },
                { 1.0, 0.0, 1.0, 1.0 },
                { 1.0, 0.5, 0.5, 1.0 },
                { 0.7, 0.4, 0.3, 0.5 },
        };

        if( quality.IsEmpty() )
        {
                double  color[ 4 ];
                int             closest = -1;
                double  maxclose = DBL_MAX;

                color[ 0 ] = prop.GetParameterValue( L"Color_R", CTime() );
                color[ 1 ] = prop.GetParameterValue( L"Color_G", CTime() );
                color[ 2 ] = prop.GetParameterValue( L"Color_B", CTime() );
                color[ 3 ] = prop.GetParameterValue( L"Color_A", CTime() );

                // We're being asked for the quality value (0-4).
                // Find the closest color match.
                for( int i = 0; i < 5; i++ )
                {
                        double          close;
                        double          dist = 0.0;

                        for( int j = 0; j < 4; j++ )
                        {
                                dist += ( color[ j ] - levels[ i ][ j ] ) * ( color[ j ] - levels[ i ][ j ] );
                        }
                        close = sqrt( dist );
                        if( close < maxclose )
                        {
                                maxclose = close;
                                closest = i;
                        }
                }

                ctxt.PutAttribute( L"Quality", closest );
        }
        else
        {
                // Set a quality value based on the five levels (0-4).
                prop.PutParameterValue( L"Color_R", levels[ (ULONG)quality ][ 0 ] );
                prop.PutParameterValue( L"Color_G", levels[ (ULONG)quality ][ 1 ] );
                prop.PutParameterValue( L"Color_B", levels[ (ULONG)quality ][ 2 ] );
                prop.PutParameterValue( L"Color_A", levels[ (ULONG)quality ][ 3 ] );
        }

        return( CStatus::OK );
}


////////////////////////////////////////////////////////////////////////////////
// Renderer Options Property

SICALLBACK ColorRendererOptions_Define( CRef& in_ctxt )
{
        Context ctxt( in_ctxt );
        CustomProperty oCustomProperty;
        Parameter oParam;
        oCustomProperty = ctxt.GetSource();
        oCustomProperty.AddParameter(L"Color_R",CValue::siDouble,siPersistable,L"",L"",0l,0l,1l,0l,1l,oParam);
        oCustomProperty.AddParameter(L"Color_G",CValue::siDouble,siPersistable,L"",L"",0l,0l,1l,0l,1l,oParam);
        oCustomProperty.AddParameter(L"Color_B",CValue::siDouble,siPersistable,L"",L"",0l,0l,1l,0l,1l,oParam);
        oCustomProperty.AddParameter(L"Color_A",CValue::siDouble,siPersistable,L"",L"",0l,0l,1l,0l,1l,oParam);
        return CStatus::OK;
}

SICALLBACK ColorRendererOptions_DefineLayout( CRef& in_ctxt )
{
        Context ctxt( in_ctxt );
        PPGLayout oLayout;
        PPGItem oItem;
        oLayout = ctxt.GetSource();
        oLayout.Clear();
        oLayout.AddColor(L"Color_R",L"Color",true);
        return CStatus::OK;
}

See Also