Iray Programmer's Manual

Own canvas class

This topic introduces:

  1. example_render_target_advanced.h, which demonstrates how to set up a custom rendering infrastructure when the default rendering infrastructure is not sufficient for your needs

Customized rendering infrastructure

To render a scene, you have to provide some rendering infrastructure for the Iray API. Basically, you have to provide buffers where the rendered image is written to. These buffers are defined by the interfaces mi::neuraylib::IRender_target, mi::neuraylib::ICanvas, and mi::neuraylib::ITile.

Most of the example programs shipped with Iray use internal default implementations. However, the example for progressive rendering demonstrates an advanced way of providing the required rendering infrastructure by using custom implementations of the interfaces mi::neuraylib::ICanvas and mi::neuraylib::ITile and the corresponding classes Canvas and Tile. Those implementations are in their own include file shown below. For simplicity, the only supported pixel type is Color, that is, one float per channel.

You can see the cancas class in use in:

example_render_target_advanced.h

001 /******************************************************************************
002  * © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.
003  *****************************************************************************/
004 
005 // examples/example_render_target_advanced.h
006 //
007 // Code shared by some rendering examples
008 
009 #ifndef EXAMPLE_RENDER_TARGET_ADVANCED_H
010 #define EXAMPLE_RENDER_TARGET_ADVANCED_H
011 
012 #include <mi/neuraylib.h>
013 
014 // A simple implementation of the ITile interface with pixel type "Color".
015 //
016 // This implementation is for educational purposes. Being able to supply your own implementation
017 // of the ICanvas and ITile interfaces might be advantageous depending on the context. If you do
018 // not have any special needs you can simply use the default implementation available via
019 // mi::neuraylib::IImage_api::create_tile().
020 class Tile : public mi::base::Interface_implement<mi::neuraylib::ITile>
021 {
022 public:
023     // Constructor.
024     //
025     // Creates a tile of the given width and height with pixel type "Color".
026     Tile( mi::Uint32 width, mi::Uint32 height)
027     {
028         m_width = width;
029         m_height = height;
030         m_data = new mi::Float32[m_width * m_height * 4];
031     }
032 
033     // Destructor
034     ~Tile() { delete[] m_data; }
035 
036     // Implement the interface of mi::neuraylib::ITile
037     void set_pixel( mi::Uint32 x_offset, mi::Uint32 y_offset, const mi::Float32* floats)
038     {
039         mi::Float32* position = &m_data[(x_offset + y_offset * m_width) * 4];
040         position[0] = floats[0];
041         position[1] = floats[1];
042         position[2] = floats[2];
043         position[3] = floats[3];
044     }
045     void get_pixel( mi::Uint32 x_offset, mi::Uint32 y_offset, mi::Float32* floats) const
046     {
047         mi::Float32* position = &m_data[(x_offset + y_offset * m_width) * 4];
048         floats[0] = position[0];
049         floats[1] = position[1];
050         floats[2] = position[2];
051         floats[3] = position[3];
052     }
053     const char* get_type() const { return "Color"; }
054     mi::Uint32 get_resolution_x() const { return m_width; }
055     mi::Uint32 get_resolution_y() const { return m_height; }
056     const void* get_data() const { return m_data; }
057     void* get_data() { return m_data; }
058 
059 private:
060     // Width of the tile
061     mi::Uint32 m_width;
062     // Height of the tile
063     mi::Uint32 m_height;
064     // The data of this tile, 32 bytes per pixel
065     mi::Float32* m_data;
066 };
067 
068 // A simple implementation of the ICanvas interface with a single tile with pixel type "Color".
069 //
070 // This implementation is for educational purposes. Being able to supply your own implementation
071 // of the ICanvas and ITile interfaces might be advantageous depending on the context. If you do
072 // not have any special needs you can simply use the default implementation available via
073 // mi::neuraylib::IImage_api::create_canvas().
074 class Canvas : public mi::base::Interface_implement<mi::neuraylib::ICanvas>
075 {
076 public:
077     // Constructor.
078     //
079     // Creates a canvas with a single tile of the given width and height.
080     Canvas( mi::Uint32 width, mi::Uint32 height)
081     {
082         m_width = width;
083         m_height = height;
084         m_gamma = 1.0f;
085         m_tile = new Tile( width, height);
086     }
087 
088     // Implement the interface of mi::neuraylib::ICanvas
089     mi::Uint32 get_resolution_x() const { return m_width; }
090     mi::Uint32 get_resolution_y() const { return m_height; }
091     mi::Uint32 get_tile_resolution_x() const { return m_width; }
092     mi::Uint32 get_tile_resolution_y() const { return m_height; }
093     mi::Uint32 get_tiles_size_x() const { return 1; }
094     mi::Uint32 get_tiles_size_y() const { return 1; }
095     mi::Uint32 get_layers_size() const { return 1; }
096     const mi::neuraylib::ITile* get_tile(
097         mi::Uint32 pixel_x, mi::Uint32 pixel_y, mi::Uint32 layer = 0) const
098     {
099         if( pixel_x >= m_width || pixel_y >= m_height || layer > 0)
100             return 0;
101         m_tile->retain();
102         return m_tile.get();
103     }
104     mi::neuraylib::ITile* get_tile(
105         mi::Uint32 pixel_x, mi::Uint32 pixel_y, mi::Uint32 layer = 0)
106     {
107         if( pixel_x >= m_width || pixel_y >= m_height || layer > 0)
108             return 0;
109         m_tile->retain();
110         return m_tile.get();
111     }
112     const char* get_type() const { return "Color"; }
113     mi::Float32 get_gamma() const { return m_gamma; }
114     void set_gamma( mi::Float32 gamma) { m_gamma = gamma; }
115 
116 private:
117     // Width of the canvas
118     mi::Uint32 m_width;
119     // Height of the canvas
120     mi::Uint32 m_height;
121     // Gamma value of the canvas
122     mi::Float32 m_gamma;
123     // The only tile of this canvas
124     mi::base::Handle<mi::neuraylib::ITile> m_tile;
125 };
126 
127 // An advanced implementation of the IRender_target interface using the custom implementations
128 // of the abstract ICanvas and ITile interfaces above.
129 class Render_target : public mi::base::Interface_implement<mi::neuraylib::IRender_target>
130 {
131 public:
132     // Constructor.
133     //
134     // Creates a render target with a single canvas of the given width and height.
135     // This variant uses custom implementations for canvases and tiles that are defined above
136     // by the classes Tile and Canvas. In these implementations the pixel type is fixed to "Color"
137     // for simplicity.
138     Render_target( mi::Uint32 width, mi::Uint32 height)
139     {
140         m_canvas = new Canvas( width, height);
141     }
142 
143     // Implement the interface of mi::neuraylib::IRender_target
144     mi::Uint32 get_canvas_count() const { return 1; }
145     const char* get_canvas_name( mi::Uint32 index) const { return index == 0 ? "result" : 0; }
146     const mi::neuraylib::ICanvas* get_canvas( mi::Uint32 index) const
147     {
148         if( index > 0)
149             return 0;
150         m_canvas->retain();
151         return m_canvas.get();
152     }
153     mi::neuraylib::ICanvas* get_canvas( mi::Uint32 index)
154     {
155         if( index > 0)
156             return 0;
157         m_canvas->retain();
158         return m_canvas.get();
159     }
160 
161 private:
162     // The only canvas of this render target
163     mi::base::Handle<mi::neuraylib::ICanvas> m_canvas;
164 };
165 
166 #endif // MI_EXAMPLE_RENDER_TARGET_ADVANED_H