©Anton Podvalny

Table of Contents

In this chapter we'll talk about possible optimizations when integrating AppSDK for different languages.

Language agnostic


Material previews

If you implement a material preview pane in your application, you will need to start multiple renders of the same simple scene with different materials applied. You may notice that renderer initialization isn't particularly fast due to internal reasons, which will slow the load time of the pane. The workaround is to create an Interactive renderer instead of production, set keepInteractiveRunning=true and just apply the different materials to the same base object loaded from a preset scene. This should be used only in a for-loop. When the list of materials to be previewed is exhausted the renderer should be stopped to release its resources.

Commit group of changes

In Interactive mode, use the autoCommit=false option of the renderer in addition to explicitly calling renderer.commit() to allow for a group of changes to be applied together. This will decrease the total time needed to apply the changes.

GUI message processing

As the GUI message processing is enabled by default, disabling it during internal waits could improve the overall responsiveness of the integration software. The interface is called setGUIMessageProcessing(bool enable).

Memory and performance optimizations

  • A performance optimization could come frоm transferring efficiently large data (vertices, map_channels, raw bitmap buffers) to V-Ray memory.
  • Aside from external files, large data is contained mostly in typed lists such as VectorList and IntList (which can also be nested inside general heterogenic lists as is the case with map_channels).

Plugin properties (parameters) are always set and read by value in all supported programming languages.

List plugin parameter optimization tips

In all supported programming languages AppSDK uses "smart" plugin parameter value setters that can guess and efficiently convert data in many cases:

  • If e.g. the definition type of a plugin property being set is VectorList and you try to assign an array or a list of 3*N floats or doubles to it, the data will be automatically reinterpreted or converted to a VectorList of N elements often more efficiently than doing it in your code. This can be useful in cases where you receive the data in a format different from the expected one.
  • So code like this will work (Python/js-like syntax is used in the examples below but the technique would work in all supported languages):
    mesh.vertices = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9] # values are automatically converted
    or
    mesh.vertices = FloatList(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9) # value is directly reinterpreted
    mesh.vertices value is now VectorList(Vector(1.1, 2.2, 3.3), Vector(4.4, 5.5, 6.6), Vector(7.7, 8.8, 9.9))
  • Note that e.g. std::vector<double> in C++ and List<double> or double[] in C# will be automatically converted to FloatList, VectorList or ColorList efficiently depending on the property definition type.
    But to use it you'd have to call the general Plugin.setValue(propertyName, value) function because the property setters in C++ and properties in C# are strongly typed and wouldn't accept data of any other type.

Node.js specific


Plugin properties (parameters) are always set and read by value, not by reference!

Sync/async

  • Many methods in the Node.js binding offer both synchronous and asynchronous versions. When you don't have to wait for the whole process to complete, you can use the asynchronous version.
  • In addition to the standard synchronous VRayRenderer object construction, the asynchronous API vray.createVRayRenderer(callback, options) is also available.
  • Similarly, vray.createVRayServer(callback, options) could be used to construct a VRayServer object asynchronously.
  • The following VRayRenderer methods have sync/async versions: start, export, pickPlugin, pickPlugins, load, append, loadAsText, appendAsText, loadFromBuffer, appendFromBuffer, loadFiltered, appendFiltered, loadAsTextFiltered, appendAsTextFiltered, appendFromBufferFiltered, saveIrradianceMapFile, saveLightCacheFile, savePhotonMapFile, saveCausticsFile, addHosts, removeHosts, resetHosts, getAllHosts, getActiveHosts, getInactiveHosts
  • The following VRayServer methods have sync/async versions: addHosts, removeHosts, resetHosts, getAllHosts, getActiveHosts, getInactiveHosts
  • The following VRayImage methods have sync/async versions: createFromBuffer, save, compress, getDownscaled, getResized, getDownscaledCropped, getResizedCropped, getFitIn, getFitOut, getCutIn, load, loadSize
  • The following VFB methods have sync/async versions: saveImage, loadImage

Typed Lists

  • General lists in Node.js use JavaScript Array/[]. Typed lists are based on JavaScript typed arrays.
  • FloatList, VectorList and ColorList are very thin wrappers around Float32Array and can be freely used as such (and Float32Array can be used instead in place of them in most cases).
  • Similarly IntList is a thin wrapper around Int32Array.
  • When you read plugin properties, you always get a copy of the underlying list data.
  • However, when you set plugin properties, you may opt to set the Javascript typed array data directly into V-Ray memory. The behavior is controlled per VRayRenderer instance by its VRayRenderer.maxTypedListsCopyByteSize property. If a typed list data size in bytes is above the threshold specified by maxTypedListsCopyByteSize, the data contained in the Javascript typed array will be set directly to V-Ray memory. The default value of maxTypedListsCopyByteSize is -1 which means data will always be copied. You can changed it to 0 or to a small value (e.g. 200) to reduce memory consumption and make the code faster.
  • V-Ray typed lists in Node.js once created, they cannot be resized (because typed arrays in JavaScript cannot be resized).


If needed, you may freely "convert" among all the different types of typed lists, typed arrays and node buffers by accessing their underlying ArrayBuffer binary data storage and passing it to the new type constructor:

var a = FloatList(0.1, 0.2, 0.3, 0.4, 0.5, 0.6); // let's have a float list
var b = Buffer.from(a.buffer); // now the buffer 'b' shares its bytes with 'a'
var c = new VectorList(b.buffer); // now the VectorList shares its data with buffer 'b' and the list 'a'
// 'c' is VectorList(Vector(0.1, 0.2, 0.3), Vector(0.4, 0.5, 0.6))

Since v6.20

Two new typed-list types were added in version 6.20:

  • PluginList is a resizable plugin container that inherits from JavaScript Array but can store (only) plugin objects efficiently. Now functions like VRayRenderer.classes.Node.getInstances() return PluginList instead of js array which allows hundreds of thousand instances to be returned without much memory overhead. In most cases the already written user code will continue to work without noticing the underlying change. Also, user code can construct PluginLists explicitly and pass them to plugin property setters where lists of plugins are expected (but this is not mandatory).
  • TransformList is a non-resizable array-like Transform objects container, somewhat similar to VectorList, ColorList, etc. but instead of being a thin wrapper around Float32Array, it contains its data in a FloatList/Float32Array internally. So when you access e.g. the element transList[index] you'll get or set a Transform object, not just a number as is the case with VectorList or ColorList.
    You can access the underlying FloatList data directly using the TransformList.floatList property.
    The function GeomUtils.readScatterData() returns a TransformList as part of the returned data.
    Also, user code can construct TransformLists explicitly (e.g. by wrapping existing FloatList/Float32Array instances) and pass them to plugin property setters where lists of transforms are expected.

C++ specific


Typed Lists

  • The typed lists in C++ are based on std::vector, e.g. IntList is std::vector<int>VectorList is std::vector<Vector>, etc. The general list ValueList is also based on std::vector and is std::vector<Value>
  • The Value type is a union of all types that can be inserted in a list and can contain typed lists or ValueList.
  • In C++ it is possible to set the data contained in long typed lists directly to V-Ray memory without copying leveraging the power of C++11 move semantics.
  • All lists (based on std::vector), the Value type and plugin property setters support both copy and move semantics.
  • For small data sizes (short lists up to several hundred elements) it is not beneficial to use move semantics as it has a small (a few bytes) dynamic memory allocation cost. But even if used, the data will be moved only above a certain threshold.


Plugin property setters selectively move or copy data depending on the type and size of the lists:

VectorList vectors(500000); // A large list of vectors
// Fill in the list...

// This will set a copy of vectors inside V-Ray memory
GeomStaticMesh.set_vertices(vectors);

// But this will get the vertices data pointer and set it directly into V-Ray memory avoiding the expensive copy operation
GeomStaticMesh.set_vertices(std::move(vectors));


Or in a more complex example:

VectorList vectors(500000); // A large list of vectors
IntList ints(1500000); // A large list of ints
// Fill in the lists...

ValueList channel;
channel.push_back(Value(1));
channel.push_back(Value(std::move(vectors))); // Move vectors data to Value and Value to ValueList
channel.push_back(Value(std::move(ints))); // Move ints data to Value and Value to ValueLis

ValueList mapChannels;
mapChannels.push_back(Value(std::move(channel))); // Move channel data to Value and Value to mapChannels
mesh.set_map_channels(std::move(mapChannels)); // Move large data (vectors and ints) to V-Ray memory and copy the rest

Ref lists

This is an advanced feature, enabled by the VRAY_SDK_INTEROPERABILITY macro. Use these types for large lists of primitives. The available types are: IntRefList, FloatRefList, VectorRefList, ColorRefList, CharString, CharStringRefList, Value, ValueRefList. They are also suitable for migrating existing code written against the V-Ray SDK to the AppSDK.

C# specific


Plugin properties (parameters) are always set and read by value, not by reference!

Typed Lists and Arrays

  • The data from/to .Net managed memory is always copied to/from V-Ray unmanaged memory. But we need to minimize additional unnecessary copies.
  • Typed lists in .Net are presented as IList<T> and are mostly based on List<T>. And List<T> (cast to IList<T>) is what you'll get when you read a plugin property.
  • Plugin property setters also accept IList<T>. Although any type supporting the interface would work, the underlying code is highly optimized for List<T> and T[].
  • It is very important to note that arrays in .Net support the IList<T> interface explicitly. So if your data is contained in a T[] array, assign it directly to any property or pass it directly to any function that accepts IList<T>! It's counter-productive to convert T[] to List<T> in order to pass it as IList<T> and it will make unnecessary memory allocations and copies.
  • When you know the length of the list beforehand, create it with the desired size. This will avoid unnecessary reallocations caused by extending the container. Or even better, just use plain T[length] array.

In summary

  • Use T[] or List<T> when you create lists for V-Ray.
  • Do NOT try to convert T[] to List<T>, use it directly! (T[] is convertible to IList<T>).
  • Do NOT try to convert List<T> to T[], use it directly.
  • Pre-allocate the lists with the needed length (or just use arrays) where possible.

Python specific


Plugin properties (parameters) are always set and read by value, not by reference!

Typed Lists

  • The General lists in Python use Python lists/[].
  • The V-Ray typed lists, however, use dedicated types - IntList, FloatList, VectorList, ColorList and, since version 6.20, also TransformList and PluginList and they all support the sequence protocol. This means that in most cases they can be used as Python lists but they are much more efficient.
  • All standard list operations like a.append(4) and b+=a work as well.
  • Typed lists also support the memory view buffer protocol.


To be able to be as efficient as possible and to cover all practical cases typed lists have some peculiarities. E.g. their positional and keyword arguments are entirely different:

a=IntList(1, 2, 3) # create an int list 'a' of 3 elements and a[0]=1, a[1]=2, a[2]=3
b=IntList(count=300) # create an int list 'b' with 300 elements initialized to 0. You can set their values later.

s=[1, 2, 3, 4] # if you already have a different sequence and want to create a typed array from its elements
a=IntList(source=s) # the 'source' keyword can be used.



  • No labels
Was this helpful?