©Anton Podvalny

Table of Contents


Workflow


There are two main properties of the production render mode of V-Ray:

  • It is the most efficient way to generate a high quality render (also known as final rendering).
  • It does not allow on-the-fly changes. Once started nothing can be changed.

As a consequence users would usually have to either use the interactive mode or render with low settings for the production renderer several times until they have the desired scene setup. Another way to speed up iterations is region rendering in either mode, specifically when the changes being made are local. When the work on the scene is finished it can be saved to disk in .vrscene format. This allows you to distribute it or just to skip translating your native data to V-Ray plugins the next time. Notice that you don't have to do this. You can use V-Ray entirely from memory without ever exporting .vrscene files.

Switching engines


A convenient feature of the AppSDK is that it allows you to switch render modes without losing scene data that is already in memory. You need to stop rendering, but all plugins and parameters you created or loaded from a scene remain and you can instantly start rendering in the other mode. For example you might want to modify the scene lighting in interactive mode and then you can run a production render without having to export the scene to a file. You can also do the inverse - modify a scene after production rendering. If you make changes to the scene while a production rendering is ongoing, this rendering will not be affected, but your changes will persist and will be used the next time you start rendering.

Currently V-Ray can't pause production rendering like it can pause in interactive mode. However, you can stop and resume a production render - see Resumable production rendering below.

Here is an example of a simple production rendering with a pre-made scene loaded from disk:

 

with vray.VRayRenderer() as renderer:
    renderer.renderMode = 'production' # the default is 'interactive'
    renderer.load('retro.vrscene')
    renderer.startSync()
    # ...
VRayInit init(NULL, true);
VRayRenderer renderer;
renderer.setRenderMode(VRayRenderer::RENDER_MODE_PRODUCTION); // the default is VRayRenderer::RENDER_MODE_INTERACTIVE
renderer.load("retro.vrscene");
renderer.startSync();
// ...
using (VRayRenderer renderer = new VRayRenderer())
{
    renderer.RenderMode = RenderMode.PRODUCTION; // the default is RenderMode.INTERACTIVE
    renderer.Load("retro.vrscene");
    renderer.StartSync();
    // ...
}
var renderer = vray.VRayRenderer();
renderer.renderMode = 'production'; // the default is 'interactive' 
renderer.load('retro.vrscene', function(err) {
    if (err) throw err;
    renderer.startSync();
    // ...
});


We don't handle the events emitted by this rendering here. This important topic is covered in details in the Events chapter.

Here's a sample image from production rendering (retro.vrscene is included in the AppSDK installation package in scenes/ folder):

 

Sampling modes


The Production render mode can use two types of image sampling, controlled by the parameter type of SettingsImageSampler:

  • The first one is the adaptive, or so-called "bucket" sampling mode, where rectangular sub-images are fully rendered by separate threads or machines.
  • The other one is the progressive sampling mode, where the whole image is sampled and updated continuously. Progressive production rendering does not emit the Bucket events. Instead, image updates come with the ProgressiveImageUpdated event.

 

with vray.VRayRenderer() as renderer:
    # The default 'interactive' mode uses RTEngine, which is controlled by SettingsRTEngine.
    renderer.renderMode = 'production'
    renderer.load('sampling.vrscene')
    # It is recommended to use the 'getInstanceOrCreate' method when a settings plugin is needed because there should be at most one instance of its type in the scene.
    imageSampler = renderer.classes.SettingsImageSampler.getInstanceOrCreate()
    # Change the boolean to true to switch from buckets to progressive.
    progressive = False
    imageSampler.type = (3 if progressive else 1)
    # Start rendering.

    renderer.startSync()
    # ...
VRayInit init(NULL, true);
VRayRenderer renderer;
// The default RENDER_MODE_INTERACTIVE uses RTEngine, which is controlled by SettingsRTEngine.
renderer.setRenderMode(VRayRenderer::RenderMode::RENDER_MODE_PRODUCTION);
renderer.load("sampling.vrscene");
// It is recommended to use the 'getInstanceOrCreate' method when a settings plugin is needed because there should be at most one instance of its type in the scene.
SettingsImageSampler imageSampler = renderer.getInstanceOrCreate<SettingsImageSampler>();
// Change the boolean to true to switch from buckets to progressive.
bool progressive = false;
imageSampler.set_type(progressive ? 3 : 1);
// Start rendering.
renderer.startSync();
// ...
using (VRayRenderer renderer = new VRayRenderer())
{
	// The default RenderMode.INTERACTIVE uses RTEngine, which is controlled by SettingsRTEngine.
	renderer.RenderMode = RenderMode.PRODUCTION;
	renderer.Load("sampling.vrscene");
	// It is recommended to use the 'GetInstanceOrCreate' method when a settings plugin is needed because there should be at most one instance of its type in the scene.
	SettingsImageSampler imageSampler = renderer.GetInstanceOrCreate<SettingsImageSampler>();
	// Change the boolean to true to switch from buckets to progressive.
	bool progressive = false;
	imageSampler.SetValue("type", (progressive ? 3 : 1));
	// Start rendering.
	renderer.StartSync();
	// ...
}
var renderer = vray.VRayRenderer();
// The default 'interactive' mode uses RTEngine, which is controlled by SettingsRTEngine.
renderer.renderMode = 'production';
renderer.load('sampling.vrscene', function (err) {
	if (err) throw err;
	// It is recommended to use the 'getInstanceOrCreate' method when a settings plugin is needed because there should be at most one instance of its type in the scene.
	var imageSampler = renderer.classes.SettingsImageSampler.getInstanceOrCreate();
    // Change the boolean to true to switch from buckets to progressive.
    var progressive = false;
    imageSampler.type = progressive ? 3 : 1;
	// Start rendering.
	renderer.startSync();
	// ...
});

Production rendering on GPU


V-Ray supports the use of its GPU engine for final frame rendering. The motivation for this is that GPU hardware is very fast.

  • There are two modes - "Production CUDA" and "Production RTX" - both can only be used as a progressive renderer.
  • Animations are supported and currently Light Cache and Brute Force can be used for global illumination.
  • As with Interactive GPU mode, it may give slightly different results compared to the CPU renderer, because it is a completely separate implementation on a very different hardware architecture.
  • A few features such as specific textures may not yet be implemented in the GPU engine.
  • The sampling settings are the same as for Interactive GPU rendering in SettingsRTEngine (SettingsImageSampler does not apply).
  • Further details about RTX are described in the OptiX and NVLink FAQ
  • This article aims to assist the choice of the appropriate render engine depending on the user’s needs - V-Ray (CPU) and V-Ray GPU render engines comparison 

 

with vray.VRayRenderer() as renderer:
    renderer.renderMode = 'productionCuda' # or 'productionOptix'
    renderer.load('retro.vrscene')
    renderer.startSync()
    # ...
VRayInit init(NULL, true);
VRayRenderer renderer;
renderer.setRenderMode(VRayRenderer::RENDER_MODE_PRODUCTION_CUDA); // or VRayRenderer::RENDER_MODE_PRODUCTION_OPTIX
renderer.load("retro.vrscene");
renderer.startSync();
// ...
using (VRayRenderer renderer = new VRayRenderer())
{
    renderer.RenderMode = RenderMode.PRODUCTION_CUDA; // or RenderMode.PRODUCTION_OPTIX
    renderer.Load("retro.vrscene");
    renderer.StartSync();
    // ...
}
var renderer = vray.VRayRenderer();
renderer.renderMode = 'productionCuda'; // or 'productionOptix' 
renderer.load('retro.vrscene', function(err) {
    if (err) throw err;
    renderer.startSync();
    // ...
});

Resumable production rendering


While production rendering can't be paused keeping everything in memory, it can resume from where it was interrupted the next time you run it. We call this feature "resumable rendering". To enable it, simply call the setResumableRendering() method on VRayRenderer. It will save rendered buckets to a .vrimg file or progressive samples to .vrprog file. It also saves the Light Cache. When you start a render with resumable rendering enabled, it will load any pre-existing results from this file and continue from there.

Notes regarding the parameters of ResumableRenderingOptions:

  • outputFileName - If you have not set SettingsOutput.img_file, V-Ray doesn't have a location to save to, so this parameter has to be set. It can also be used to override the img_file location. The file extension is automatically replaced with .vrimg for buckets and .vrprog for progressive. This file will be in the current working directory which we set to the scene directory. An existing progressive file will cannot be used for bucket rendering and vice versa.
  • compressProgressiveFiles - Progressive rendering resume files can get very large (gigabytes) because they have to store lots of information. Compression is enabled by default.
  • deleteResumableFileOnSuccess - If set, the resumable file will be deleted automatically if the frame is completed successfully. This applies to the intermediate .vrimg or .vrprog files, it doesn't apply when a .vrimg file is set as the main output.
  • progressiveAutoSaveSeconds - This is the interval at which the resume file is saved when the progressive sampler is used. It will cause a checkpoint file save around the middle of the 15 second render time we allow here. There will be a console message about that. With bucket rendering the file is automatically saved with each completed bucket. If set to 0 a file will only be saved at the end of the rendering. It can still be resumed at a lower noise threshold or higher time/sample limit.

def setupResumableRendering(renderer):
    resumableOptions = {
        'outputFile': 'resumableFile.ext',
        'compressProgressiveFiles': True,
        'progressiveAutoSaveSeconds': 8
    }
    # Passing options is not obligatory.
    renderer.setResumableRendering(True, **resumableOptions)

with vray.VRayRenderer() as renderer:
    # Resumable rendering is available in Production and GPU Production mode.
    renderer.renderMode = 'production'
    setupResumableRendering(renderer)
    renderer.load(os.path.join(SCENE_PATH, 'retro.vrscene'))
    # Change the boolean to true to switch from buckets to progressive.
    # Resumable rendering works differently in the two modes. 
    # For buckets it saves a smaller file that contains finished buckets. 
    # For progressive it saves a large file with all the samples accumulated for the whole frame so far.
    progressive = False
    sampler = renderer.plugins['vraySettingsImageSampler']
    sampler.type = (3 if progressive else 1)

    # Render for 15 seconds and stop.
    # Run the program again and see how it starts where it left off.
    # Notice that the light cache is also saved and reused.
    renderer.startSync()
    renderer.waitForRenderEnd(15000)
void setupResumableRendering(VRayRenderer &renderer) {
	ResumableRenderingOptions options;
	options.outputFileName = "resumableFile.ext";
	options.compressProgressiveFiles = true;
	options.progressiveAutoSaveSeconds = 8;
	// Passing options is not obligatory.
	renderer.setResumableRendering(true, &options);
}

int main() {
	VRayInit init(NULL, true);
	VRayRenderer renderer;
	// Resumable rendering is available in Production and GPU Production mode.
	renderer.setRenderMode(VRayRenderer::RENDER_MODE_PRODUCTION);
	setupResumableRendering(renderer);
	renderer.load("retro.vrscene");
	// Change the boolean to true to switch from buckets to progressive.
	// Resumable rendering works differently in the two modes. 
	// For buckets it saves a smaller file that contains finished buckets. 
	// For progressive it saves a large file with all the samples accumulated for the whole frame so far.
	bool progressive = false;
	SettingsImageSampler sampler = renderer.getPlugin<SettingsImageSampler>("vraySettingsImageSampler");
	sampler.set_type(progressive ? 3 : 1);
	// Render for 15 seconds and stop.
	// Run the program again and see how it starts where it left off.
	// Notice that the light cache is also saved and reused.
	renderer.startSync();
	renderer.waitForRenderEnd(15000);
	return 0;
}
private static void setupResumableRendering(VRayRenderer renderer)
{
	ResumableRenderingOptions options = new ResumableRenderingOptions();
	options.OutputFileName = "resumableFile.ext";
	options.CompressProgressiveFiles = true;
	options.ProgressiveAutoSaveSeconds = 8;
	// Passing options is not obligatory.
	renderer.SetResumableRendering(true, options);
}

static void Main(string[] args)
{
	using (VRayRenderer renderer = new VRayRenderer())
	{
		// Resumable rendering is available in Production and GPU Production mode.
		renderer.RenderMode = RenderMode.PRODUCTION;
		setupResumableRendering(renderer);
		renderer.Load("retro.vrscene");
		// Change the boolean to true to switch from buckets to progressive.
		// Resumable rendering works differently in the two modes. 
		// For buckets it saves a smaller file that contains finished buckets. 
		// For progressive it saves a large file with all the samples accumulated for the whole frame so far.
		bool progressive = false;
		SettingsImageSampler sampler = renderer.GetPlugin<SettingsImageSampler>("vraySettingsImageSampler");
		sampler.SetValue("type", (progressive ? 3 : 1));
		// Render for 15 seconds and stop.
		// Run the program again and see how it starts where it left off.
		// Notice that the light cache is also saved and reused.
		renderer.StartSync();
		renderer.WaitForRenderEnd(15000);
	}
}
var renderer = vray.VRayRenderer();
// Resumable rendering is available in Production and GPU Production mode.
renderer.renderMode = 'production';
renderer.load('retro.vrscene', function(err) {
    if (err) throw err;
    var resumableOptions = {
        'outputFile': 'resumableFile.ext',
        'compressProgressiveFiles': true,
        'progressiveAutoSaveSeconds': 8
    };
    // Passing options is not obligatory.
    renderer.setResumableRendering(true, resumableOptions);
    // Change the boolean to true to switch from buckets to progressive.
    // Resumable rendering works differently in the two modes. 
    // For buckets it saves a smaller file that contains finished buckets. 
    // For progressive it saves a large file with all the samples accumulated for the whole frame so far.
    var progressive = false;
    var sampler = renderer.plugins['vraySettingsImageSampler'];
    sampler.type = progressive ? 3 : 1;
    renderer.start(function(err) {
		if (err) throw err;
		// Render for 15 seconds and stop.
		// Run the program again and see how it starts where it left off.
		// Notice that the light cache is also saved and reused.
        renderer.waitForRenderEnd(15000, function() {
			renderer.close();
		});
    });
});

Relevant settings


There are several scene plugins (see the upcoming Plugins chapter) with parameters relating to this render mode.

Image sampling is controlled by SettingsImageSampler. It controls whether to sample in buckets or progressively and how much. This is one of the most important places to control the render time vs. noise tradeoff. For details see the Global Settings lesson.

The global illumination engines (Light Cache and Irradiance Map) run a prepass in production mode. They can't be used in interactive mode. The GI engines are configured with SettingsLightCache and SettingsIrradianceMap - see the Global Illumination section for more details.

Finally, SettingsRegionsGenerator controls the size of the buckets and the order in which they are rendered. The parameters of this plugin are:

  • xc - The maximum width of buckets in pixels
  • yc - The maximum height of buckets in pixels
  • xymeans - The size in pixels or number of regions - 0:Size in pixels; 1:Number of regions
  • seqtype - The ordering algorithm - 0:Top-Bottom; 1:Left-Right; 2:Checker; 3:Spiral; 4:Triangulation; 5:Hilbert curve; 6:Random
  • reverse - If true, reverse the order in which buckets are generated
  • dynbuckets - Whether to split the final buckets into smaller pieces for better processor utilization - 0:Disabled; 1:Enabled; 2:Enabled (legacy algorithm)

You can control how many threads to use through the numThreads property of VRayRenderer. By default all available threads are used.

  • No labels
Was this helpful?