Introduction In this chapter we'll cover another type of animations supported by V-Ray - the flythrough animations. This means scenes where the camera "flies through" the scene, e.g. has its position animated. The other name which is used is "walk-through" animations.
Parameters Light cache If we use light cache, it's best if we calculate it for the entire walk-through animation, and not for a single frame only. Note that this is not strictly necessary - we can render the animation with the light cache being calculated each frame; however, rendering it only once will save rendering time, especially for long animations.
For this to work, we need to set the light cache settings parameter mode to Fly-through (SettingsLightCache::mode = 1). Make sure that the timeline animation range (set in SettingsOutput) matches the range which you want to render. This is important because the light cache will look at the current timeline animation range when calculating the fly-through cache.
Since all the light cache samples will be distributed among all the animation frames, we will need to increase the light cache Subdivs value (for example SettingsLightCache::subdivs = 2000, the default is 1000). The exact value depends on the quality you want to achieve and on your specific animation. If the camera moves slowly, or the path is relatively short (e.g. just one room of a house) then you can use lower Subdivs value, since most of the samples will fall in the same place anyways. If the camera moves quickly or covers larger parts of the scene, you will need more samples to get adequate coverage everywhere.
Here's an explanation of the Fly-through mode taken from the docs: "Fly-through – Computes a light cache for an entire fly-through animation, assuming that the camera position/orientation is the only thing that changes. The movement of the camera in the active time segment only is taken in consideration. Note that it may be better to set Scale to World (SettingsLightCache::world_scale = true) for fly-through animations. The light cache for the entire animated sequence is computed only at the first rendered frame and is reused without changes for subsequent frames."
We'll cover in depth the light cache parameters in a later chapter about GI.
The preferred method for rendering animation is by using Brute force/Light cache as primary/secondary engine or Brute force/Brute force.
Example The above animation is generated by rendering the file "Animated_Camera.vrscene" from the scene bundle . Check the comments inside the file and the included ones to see how GI can be used more optimally in an animation.
Code Example This example is similar to the one from the previous chapter, but instead of animating an object, we'll animate the renderView's position. Here, the so called Animation2 API (available in AppSDK 6 and above is used).
Animation2 API is particularly useful, in the case when applying changes to animated parameter values during rendering. In this case, there's no need to change the current time/frame with renderer.setCurrentTime(t).
Python <code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line"># Compatibility with Python 2.7.</span><span data-v-c2b1f83f="" class="line">from __future__ import print_function</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line"># The directory containing the vray shared object should be present in the PYTHONPATH environment variable.</span><span data-v-c2b1f83f="" class="line"># Try to import the vray module from VRAY_SDK/python, if it is not in PYTHONPATH</span><span data-v-c2b1f83f="" class="line">import sys, os</span><span data-v-c2b1f83f="" class="line">VRAY_SDK = os.environ.get('VRAY_SDK')</span><span data-v-c2b1f83f="" class="line">if VRAY_SDK:</span><span data-v-c2b1f83f="" class="line"> sys.path.append(os.path.join(VRAY_SDK, 'python'))</span><span data-v-c2b1f83f="" class="line">import vray</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">startFrame = 1</span><span data-v-c2b1f83f="" class="line">endFrame = 20</span><span data-v-c2b1f83f="" class="line">SCENE_PATH = os.path.join(os.environ.get('VRAY_SDK'), 'scenes')</span><span data-v-c2b1f83f="" class="line"># Change process working directory to SCENE_PATH in order to be able to load relative scene resources.</span><span data-v-c2b1f83f="" class="line">os.chdir(SCENE_PATH)</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">def updateNextFrameRenderView(renderer, startFrame):</span><span data-v-c2b1f83f="" class="line"> # Next frame to be updated</span><span data-v-c2b1f83f="" class="line"> frameToUpdate = renderer.frame + 1 if renderer.frame > 0 else startFrame + 1</span><span data-v-c2b1f83f="" class="line"> # t corresponds to the time of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> t = frameToUpdate / renderer.classes.SettingsOutput.getInstanceOrCreate().frames_per_second</span><span data-v-c2b1f83f="" class="line"> # Obtain a reference to the 'RenderView' plugin.</span><span data-v-c2b1f83f="" class="line"> renderView = renderer.classes.RenderView.getInstanceOrCreate()</span><span data-v-c2b1f83f="" class="line"> # Obtain a copy of the renderView transform at time t.</span><span data-v-c2b1f83f="" class="line"> updatedTransform = renderView.getValue('transform', t)</span><span data-v-c2b1f83f="" class="line"> # Modify the copy of the renderView transform.</span><span data-v-c2b1f83f="" class="line"> # The changes do not affect the scene directly since updatedTransform is a copy of the actual transform.</span><span data-v-c2b1f83f="" class="line"> updatedTransform = updatedTransform.replaceOffset(updatedTransform.offset + vray.Vector(0, 0, 3 * t))</span><span data-v-c2b1f83f="" class="line"> # Update the transform value in renderView at time t (applying the changes above).</span><span data-v-c2b1f83f="" class="line"> # NOTE: Animation2 API is particularly useful, in the case when </span><span data-v-c2b1f83f="" class="line"> # applying changes to animated parameter values during rendering.</span><span data-v-c2b1f83f="" class="line"> # In this case, there's no need to change the current time/frame with renderer.time = t</span><span data-v-c2b1f83f="" class="line"> renderView.setValue('transform', updatedTransform, t)</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">def onStateChanged(renderer, oldState, newState, instant):</span><span data-v-c2b1f83f="" class="line"> if newState == vray.RENDERER_STATE_IDLE_FRAME_DONE or newState == vray.RENDERER_STATE_IDLE_DONE:</span><span data-v-c2b1f83f="" class="line"> print('Image Ready, frame ' + str(renderer.frame) + ' (sequenceEnd = ' + str(renderer.sequenceEnded) + ')')</span><span data-v-c2b1f83f="" class="line"> if newState == vray.RENDERER_STATE_IDLE_FRAME_DONE:</span><span data-v-c2b1f83f="" class="line"> # Prepare the renderView of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> updateNextFrameRenderView(renderer, startFrame)</span><span data-v-c2b1f83f="" class="line"> # If the sequence has NOT finished - continue with next frame.</span><span data-v-c2b1f83f="" class="line"> renderer.continueSequence()</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line"># Create an instance of VRayRenderer with default options.</span><span data-v-c2b1f83f="" class="line"># The renderer is automatically closed after the `with` block.</span><span data-v-c2b1f83f="" class="line">with vray.VRayRenderer() as renderer:</span><span data-v-c2b1f83f="" class="line"> # Register a simple log callback. Always useful for debugging.</span><span data-v-c2b1f83f="" class="line"> def dumpMsg(renderer, message, level, instant):</span><span data-v-c2b1f83f="" class="line"> if level == vray.LOGLEVEL_ERROR:</span><span data-v-c2b1f83f="" class="line"> print("[ERROR]", message)</span><span data-v-c2b1f83f="" class="line"> elif level == vray.LOGLEVEL_WARNING:</span><span data-v-c2b1f83f="" class="line"> print("[Warning]", message)</span><span data-v-c2b1f83f="" class="line"> elif level == vray.LOGLEVEL_INFO:</span><span data-v-c2b1f83f="" class="line"> print("[info]", message)</span><span data-v-c2b1f83f="" class="line"> # Uncomment for testing, but you might want to ignore these in real code</span><span data-v-c2b1f83f="" class="line"> #else: print("[debug]", message)</span><span data-v-c2b1f83f="" class="line"> renderer.setOnLogMessage(dumpMsg)</span><span data-v-c2b1f83f="" class="line"> # Add a listener for the renderer state change event.</span><span data-v-c2b1f83f="" class="line"> # We will use it to detect when a frame is completed and allow the next one to start.</span><span data-v-c2b1f83f="" class="line"> renderer.setOnStateChanged(onStateChanged)</span><span data-v-c2b1f83f="" class="line"> # Load scene from a file.</span><span data-v-c2b1f83f="" class="line"> renderer.load(os.path.join(SCENE_PATH, 'animation.vrscene'))</span><span data-v-c2b1f83f="" class="line"> # Maximum paths per pixel for interactive mode. Set a low sample level to complete rendering faster.</span><span data-v-c2b1f83f="" class="line"> # The default value is unlimited. We have to call this *after* loading the scene.</span><span data-v-c2b1f83f="" class="line"> renderer.setInteractiveSampleLevel(1)</span><span data-v-c2b1f83f="" class="line"> # NOTE: 'useAnimatedValues' is not necessary to be set, in case only Animation2 API is used</span><span data-v-c2b1f83f="" class="line"> # renderer.useAnimatedValues = True</span><span data-v-c2b1f83f="" class="line"> # Prepare the renderView of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> updateNextFrameRenderView(renderer, startFrame)</span><span data-v-c2b1f83f="" class="line"> # Set 'start' and 'end' of the sequence. 'step' is omitted and defaults to 1.</span><span data-v-c2b1f83f="" class="line"> # For all possible use cases of 'renderSequence' check the documentation for VRayRenderer.renderSequence.</span><span data-v-c2b1f83f="" class="line"> renderer.renderSequence({'start': startFrame, 'end': endFrame})</span><span data-v-c2b1f83f="" class="line"> # Wait until the entire sequence has finished rendering.</span><span data-v-c2b1f83f="" class="line"> renderer.waitForSequenceEnd()</span></code>
C++ <code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">#define VRAY_RUNTIME_LOAD_PRIMARY</span><span data-v-c2b1f83f="" class="line">#include "vraysdk.hpp"</span><span data-v-c2b1f83f="" class="line">#include "vrayplugins.hpp"</span><span data-v-c2b1f83f="" class="line">#include "utils.h"</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">using namespace VRay;</span><span data-v-c2b1f83f="" class="line">using namespace VRay::Plugins;</span><span data-v-c2b1f83f="" class="line">using namespace std;</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">const char *BASE_PATH = getenv("VRAY_SDK");</span><span data-v-c2b1f83f="" class="line">string SCENE_PATH = (BASE_PATH ? string(BASE_PATH) : string(".")) + PATH_DELIMITER + "scenes";</span><span data-v-c2b1f83f="" class="line">const int startFrame = 1;</span><span data-v-c2b1f83f="" class="line">const int endFrame = 20;</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">void updateNextFrameRenderView(VRayRenderer &renderer, const int startFrame) {</span><span data-v-c2b1f83f="" class="line"> const int currentFrame = renderer.getCurrentFrame();</span><span data-v-c2b1f83f="" class="line"> // Next frame to be updated</span><span data-v-c2b1f83f="" class="line"> const int frameToUpdate = (currentFrame > 0) ? (currentFrame + 1) : (startFrame + 1);</span><span data-v-c2b1f83f="" class="line"> // t corresponds to the time of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> const double t = frameToUpdate / renderer.getInstanceOrCreate<SettingsOutput>().get_frames_per_second();</span><span data-v-c2b1f83f="" class="line"> // Obtain a reference to the 'RenderView' plugin.</span><span data-v-c2b1f83f="" class="line"> RenderView renderView = renderer.getInstanceOrCreate<RenderView>();</span><span data-v-c2b1f83f="" class="line"> // Obtain a copy of the renderView transform at time t.</span><span data-v-c2b1f83f="" class="line"> Transform updatedTransform = renderView.get_transform(t);</span><span data-v-c2b1f83f="" class="line"> // Modify the copy of the renderView transform.</span><span data-v-c2b1f83f="" class="line"> // The changes do not affect the scene directly since updatedTransform is a copy of the actual transform.</span><span data-v-c2b1f83f="" class="line"> updatedTransform.offset += Vector(0.0, 0.0, 3 * t);</span><span data-v-c2b1f83f="" class="line"> // Update the transform value in renderView at time t (applying the changes above).</span><span data-v-c2b1f83f="" class="line"> // NOTE: Animation2 API is particularly useful, in the case when </span><span data-v-c2b1f83f="" class="line"> // applying changes to animated parameter values during rendering.</span><span data-v-c2b1f83f="" class="line"> // In this case, there's no need to change the current time/frame with renderer.setCurrentTime(t)</span><span data-v-c2b1f83f="" class="line"> renderView.set_transform(updatedTransform, t);</span><span data-v-c2b1f83f="" class="line">}</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">void onStateChanged(VRayRenderer &renderer, RendererState oldState, RendererState newState, double instant, void* userData) {</span><span data-v-c2b1f83f="" class="line"> if (newState == IDLE_FRAME_DONE || newState == IDLE_DONE) {</span><span data-v-c2b1f83f="" class="line"> printf("Image Ready, frame %d (sequenceEnded = %d)\</span><span data-v-c2b1f83f="" class="line">", renderer.getCurrentFrame(), renderer.isSequenceEnded());</span><span data-v-c2b1f83f="" class="line"> if (newState == IDLE_FRAME_DONE) {</span><span data-v-c2b1f83f="" class="line"> // Prepare the renderView of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> updateNextFrameRenderView(renderer, startFrame);</span><span data-v-c2b1f83f="" class="line"> // If the sequence has NOT finished - continue with next frame.</span><span data-v-c2b1f83f="" class="line"> renderer.continueSequence();</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line">}</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">int main() {</span><span data-v-c2b1f83f="" class="line"> // Change process working directory to SCENE_PATH in order to be able to load relative scene resources.</span><span data-v-c2b1f83f="" class="line"> changeCurrentDir(SCENE_PATH.c_str());</span><span data-v-c2b1f83f="" class="line"> // Load V-Ray SDK library.</span><span data-v-c2b1f83f="" class="line"> VRayInit init(NULL, true);</span><span data-v-c2b1f83f="" class="line"> // Create an instance of VRayRenderer with default options.</span><span data-v-c2b1f83f="" class="line"> // The renderer is automatically closed at the end of the current scope.</span><span data-v-c2b1f83f="" class="line"> VRayRenderer renderer;</span><span data-v-c2b1f83f="" class="line"> // It's recommended to always have a console log</span><span data-v-c2b1f83f="" class="line"> renderer.setOnLogMessage(logMessage);</span><span data-v-c2b1f83f="" class="line"> // Add a listener for the renderer state change event.</span><span data-v-c2b1f83f="" class="line"> // We will use it to detect when a frame is completed and allow the next one to start.</span><span data-v-c2b1f83f="" class="line"> renderer.setOnStateChanged(onStateChanged);</span><span data-v-c2b1f83f="" class="line"> // Load scene from a file.</span><span data-v-c2b1f83f="" class="line"> renderer.load("animation.vrscene");</span><span data-v-c2b1f83f="" class="line"> // Maximum paths per pixel for interactive mode. Set a low sample level to complete rendering faster.</span><span data-v-c2b1f83f="" class="line"> // The default value is unlimited. We have to call this *after* loading the scene.</span><span data-v-c2b1f83f="" class="line"> renderer.setInteractiveSampleLevel(1);</span><span data-v-c2b1f83f="" class="line"> // NOTE: 'useAnimatedValues' is not necessary to be set, in case only Animation2 API is used</span><span data-v-c2b1f83f="" class="line"> // renderer.useAnimatedValues(true);</span><span data-v-c2b1f83f="" class="line"> // Prepare the renderView of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> updateNextFrameRenderView(renderer, startFrame);</span><span data-v-c2b1f83f="" class="line"> // Set 'start' and 'end' of the sequence.</span><span data-v-c2b1f83f="" class="line"> // For all possible use cases of 'renderSequence' check the documentation for VRayRenderer.renderSequence.</span><span data-v-c2b1f83f="" class="line"> SubSequenceDesc subSequenceDescriptions[1];</span><span data-v-c2b1f83f="" class="line"> subSequenceDescriptions[0].start = startFrame;</span><span data-v-c2b1f83f="" class="line"> subSequenceDescriptions[0].end = endFrame;</span><span data-v-c2b1f83f="" class="line"> subSequenceDescriptions[0].step = 1;</span><span data-v-c2b1f83f="" class="line"> renderer.renderSequence(subSequenceDescriptions, 1);</span><span data-v-c2b1f83f="" class="line"> // Wait until the entire sequence has finished rendering.</span><span data-v-c2b1f83f="" class="line"> renderer.waitForSequenceEnd();</span><span data-v-c2b1f83f="" class="line"> return 0;</span><span data-v-c2b1f83f="" class="line">}</span></code>
C#.NET <code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">using System;</span><span data-v-c2b1f83f="" class="line">using System.IO;</span><span data-v-c2b1f83f="" class="line">using VRay;</span><span data-v-c2b1f83f="" class="line">using VRay.Plugins;</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">namespace _03_animation2_api</span><span data-v-c2b1f83f="" class="line">{</span><span data-v-c2b1f83f="" class="line"> class Program</span><span data-v-c2b1f83f="" class="line"> {</span><span data-v-c2b1f83f="" class="line"> const int startFrame = 1;</span><span data-v-c2b1f83f="" class="line"> const int endFrame = 20;</span><span data-v-c2b1f83f="" class="line"> static void UpdateNextFrameRenderView(VRayRenderer renderer, int startFrame)</span><span data-v-c2b1f83f="" class="line"> {</span><span data-v-c2b1f83f="" class="line"> // Next frame to be updated</span><span data-v-c2b1f83f="" class="line"> int frameToUpdate = (renderer.Frame > 0) ? (renderer.Frame + 1) : (startFrame + 1);</span><span data-v-c2b1f83f="" class="line"> // t corresponds to the time of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> double t = frameToUpdate / renderer.GetInstanceOrCreate<SettingsOutput>().FramesPerSecond;</span><span data-v-c2b1f83f="" class="line"> // Obtain a reference to the 'RenderView' plugin.</span><span data-v-c2b1f83f="" class="line"> RenderView renderView = renderer.GetInstanceOrCreate<RenderView>();</span><span data-v-c2b1f83f="" class="line"> // Obtain a copy of the renderView transform at time t.</span><span data-v-c2b1f83f="" class="line"> Transform updatedTransform = renderView.Get_Transform(t);</span><span data-v-c2b1f83f="" class="line"> // Modify the copy of the renderView transform.</span><span data-v-c2b1f83f="" class="line"> // The changes do not affect the scene directly since updatedTransform is a copy of the actual transform.</span><span data-v-c2b1f83f="" class="line"> updatedTransform = updatedTransform.ReplaceOffset(updatedTransform.Offset + new Vector(0, 0, 3 * t));</span><span data-v-c2b1f83f="" class="line"> // Update the transform value in renderView at time t (applying the changes above).</span><span data-v-c2b1f83f="" class="line"> // NOTE: Animation2 API is particularly useful, in the case when </span><span data-v-c2b1f83f="" class="line"> // applying changes to animated parameter values during rendering.</span><span data-v-c2b1f83f="" class="line"> // In this case, there's no need to change the current time/frame with renderer.Time = t</span><span data-v-c2b1f83f="" class="line"> renderView.Set_Transform(updatedTransform, t);</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line"> static void Main(string[] args)</span><span data-v-c2b1f83f="" class="line"> {</span><span data-v-c2b1f83f="" class="line"> string SCENE_PATH = Path.Combine(Environment.GetEnvironmentVariable("VRAY_SDK"), "scenes");</span><span data-v-c2b1f83f="" class="line"> // Change process working directory to SCENE_PATH in order to be able to load relative scene resources.</span><span data-v-c2b1f83f="" class="line"> Directory.SetCurrentDirectory(SCENE_PATH);</span><span data-v-c2b1f83f="" class="line"> // Create an instance of VRayRenderer with default options. The renderer is automatically closed after the `using` block.</span><span data-v-c2b1f83f="" class="line"> using (VRayRenderer renderer = new VRayRenderer())</span><span data-v-c2b1f83f="" class="line"> {</span><span data-v-c2b1f83f="" class="line"> // Add a listener for any type of log message.</span><span data-v-c2b1f83f="" class="line"> renderer.LogMessage += new EventHandler<MessageEventArgs>((source, e) =></span><span data-v-c2b1f83f="" class="line"> {</span><span data-v-c2b1f83f="" class="line"> // You can remove the if for testing, but you might want to ignore Debug in real code</span><span data-v-c2b1f83f="" class="line"> if (e.LogLevel != LogLevelType.Debug)</span><span data-v-c2b1f83f="" class="line"> {</span><span data-v-c2b1f83f="" class="line"> Console.WriteLine(String.Format("[{0}] {1}", e.LogLevel.ToString(), e.Message));</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line"> });</span><span data-v-c2b1f83f="" class="line"> // Add a listener for state changes.</span><span data-v-c2b1f83f="" class="line"> // It is invoked when the renderer prepares for rendering, renders, finishes or fails.</span><span data-v-c2b1f83f="" class="line"> renderer.StateChanged += new EventHandler<StateChangedEventArgs>((source, e) =></span><span data-v-c2b1f83f="" class="line"> {</span><span data-v-c2b1f83f="" class="line"> if (e.NewState == VRayRenderer.RendererState.IDLE_FRAME_DONE || e.NewState == VRayRenderer.RendererState.IDLE_DONE)</span><span data-v-c2b1f83f="" class="line"> {</span><span data-v-c2b1f83f="" class="line"> Console.WriteLine("Image Ready, frame " + renderer.Frame + " (sequenceEnded = " + renderer.IsSequenceEnded + ")");</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line"> // Prepare the renderView of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> UpdateNextFrameRenderView(renderer, startFrame);</span><span data-v-c2b1f83f="" class="line"> // If the sequence has NOT finished - continue with next frame.</span><span data-v-c2b1f83f="" class="line"> renderer.ContinueSequence();</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line"> });</span><span data-v-c2b1f83f="" class="line"> // Load scene from a file.</span><span data-v-c2b1f83f="" class="line"> renderer.Load("animation.vrscene");</span><span data-v-c2b1f83f="" class="line"> // Maximum paths per pixel for interactive mode. Set a low sample level to complete rendering faster.</span><span data-v-c2b1f83f="" class="line"> // The default value is unlimited. We have to call this *after* loading the scene.</span><span data-v-c2b1f83f="" class="line"> renderer.SetInteractiveSampleLevel(1);</span><span data-v-c2b1f83f="" class="line"> // NOTE: 'UseAnimatedValues' is not necessary to be set, in case only Animation2 API is used</span><span data-v-c2b1f83f="" class="line"> // renderer.UseAnimatedValues = true;</span><span data-v-c2b1f83f="" class="line"> // Prepare the renderView of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> UpdateNextFrameRenderView(renderer, startFrame);</span><span data-v-c2b1f83f="" class="line"> // Set 'start' and 'end' of the sequence. 'step' is omitted and defaults to 1.</span><span data-v-c2b1f83f="" class="line"> // For all possible use cases of 'renderSequence' check the documentation for VRayRenderer.renderSequence.</span><span data-v-c2b1f83f="" class="line"> renderer.RenderSequence(new SubSequenceDesc[] { new SubSequenceDesc(startFrame, endFrame) });</span><span data-v-c2b1f83f="" class="line"> // Wait until the entire sequence has finished rendering.</span><span data-v-c2b1f83f="" class="line"> renderer.WaitForSequenceEnd();</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line">}</span></code>
Node.js <code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">var path = require('path');</span><span data-v-c2b1f83f="" class="line">var vray = require(path.join(process.env.VRAY_SDK, 'node', 'vray'));</span><span data-v-c2b1f83f="" class="line">var SCENE_PATH = path.join(process.env.VRAY_SDK, 'scenes');</span><span data-v-c2b1f83f="" class="line">const startFrame = 1;</span><span data-v-c2b1f83f="" class="line">const endFrame = 20;</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">function updateNextFrameRenderView(renderer, startFrame) {</span><span data-v-c2b1f83f="" class="line"> // Next frame to be updated</span><span data-v-c2b1f83f="" class="line"> var frameToUpdate = (renderer.frame > 0) ? (renderer.frame + 1) : (startFrame + 1);</span><span data-v-c2b1f83f="" class="line"> // t corresponds to the time of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> var t = frameToUpdate / renderer.classes.SettingsOutput.getInstanceOrCreate().frames_per_second;</span><span data-v-c2b1f83f="" class="line"> // Obtain a reference to the 'RenderView' plugin.</span><span data-v-c2b1f83f="" class="line"> var renderView = renderer.classes.RenderView.getInstanceOrCreate()</span><span data-v-c2b1f83f="" class="line"> // Obtain a copy of the renderView transform at time t.</span><span data-v-c2b1f83f="" class="line"> var updatedTransform = renderView.getValue("transform", t);</span><span data-v-c2b1f83f="" class="line"> // Modify the copy of the renderView transform.</span><span data-v-c2b1f83f="" class="line"> // The changes do not affect the scene directly since updatedTransform is a copy of the actual transform.</span><span data-v-c2b1f83f="" class="line"> updatedTransform = updatedTransform.replaceOffset(updatedTransform.offset.add(vray.Vector(0, 0, 3 * t)));</span><span data-v-c2b1f83f="" class="line"> // Update the transform value in renderView at time t (applying the changes above).</span><span data-v-c2b1f83f="" class="line"> // NOTE: Animation2 API is particularly useful, in the case when </span><span data-v-c2b1f83f="" class="line"> // applying changes to animated parameter values during rendering.</span><span data-v-c2b1f83f="" class="line"> // In this case, there's no need to change the current time/frame with renderer.time = t</span><span data-v-c2b1f83f="" class="line"> renderView.setValue("transform", updatedTransform, t);</span><span data-v-c2b1f83f="" class="line">}</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">// Change process working directory to SCENE_PATH in order to be able to load relative scene resources.</span><span data-v-c2b1f83f="" class="line">process.chdir(SCENE_PATH);</span><span data-v-c2b1f83f="" class="line">// Create an instance of VRayRenderer with default options.</span><span data-v-c2b1f83f="" class="line">var renderer = vray.VRayRenderer();</span><span data-v-c2b1f83f="" class="line">// It's recommended to always have a console log callback</span><span data-v-c2b1f83f="" class="line">renderer.on("logMessage", function (message, level, instant) {</span><span data-v-c2b1f83f="" class="line"> if (level == vray.LOGLEVEL_ERROR)</span><span data-v-c2b1f83f="" class="line"> console.log("[ERROR] ", message);</span><span data-v-c2b1f83f="" class="line"> else if (level == vray.LOGLEVEL_WARNING)</span><span data-v-c2b1f83f="" class="line"> console.log("[Warning] ", message);</span><span data-v-c2b1f83f="" class="line"> else if (level == vray.LOGLEVEL_INFO)</span><span data-v-c2b1f83f="" class="line"> console.log("[info] ", message);</span><span data-v-c2b1f83f="" class="line"> // Uncomment for testing, but you might want to ignore these in real code</span><span data-v-c2b1f83f="" class="line"> //else console.log("[debug] ", message);</span><span data-v-c2b1f83f="" class="line">});</span><span data-v-c2b1f83f="" class="line">// Add a listener for the renderer state change event.</span><span data-v-c2b1f83f="" class="line">// We will use it to detect when a frame is completed and allow the next one to start.</span><span data-v-c2b1f83f="" class="line">renderer.on("stateChanged", function (oldState, newState, instant) {</span><span data-v-c2b1f83f="" class="line"> if (newState == "idleFrameDone" || newState == "idleDone") {</span><span data-v-c2b1f83f="" class="line"> console.log("Image Ready, frame " + renderer.frame + " (sequenceEnd = " + renderer.sequenceEnded + ")");</span><span data-v-c2b1f83f="" class="line"> // Check if the sequence has finished rendering.</span><span data-v-c2b1f83f="" class="line"> if (newState == "idleDone") {</span><span data-v-c2b1f83f="" class="line"> // Closes the renderer.</span><span data-v-c2b1f83f="" class="line"> renderer.close();</span><span data-v-c2b1f83f="" class="line"> } else {</span><span data-v-c2b1f83f="" class="line"> // Prepare the renderView of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> updateNextFrameRenderView(renderer, startFrame);</span><span data-v-c2b1f83f="" class="line"> // If the sequence has NOT finished - continue with next frame.</span><span data-v-c2b1f83f="" class="line"> renderer.continueSequence();</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line"> } else if (newState.startsWith("idle")) {</span><span data-v-c2b1f83f="" class="line"> console.log("Unexpected end of render sequence: ", newState);</span><span data-v-c2b1f83f="" class="line"> renderer.close();</span><span data-v-c2b1f83f="" class="line"> }</span><span data-v-c2b1f83f="" class="line">});</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">// Load scene from a file asynchronously.</span><span data-v-c2b1f83f="" class="line">renderer.load("animation.vrscene", function (err) {</span><span data-v-c2b1f83f="" class="line"> if (err) throw err;</span><span data-v-c2b1f83f="" class="line"> // Maximum paths per pixel for interactive mode. Set a low sample level to complete rendering faster.</span><span data-v-c2b1f83f="" class="line"> // The default value is unlimited. We have to call this *after* loading the scene.</span><span data-v-c2b1f83f="" class="line"> renderer.setInteractiveSampleLevel(1);</span><span data-v-c2b1f83f="" class="line"> // NOTE: "useAnimatedValues" is not necessary to be set, in case only Animation2 API is used</span><span data-v-c2b1f83f="" class="line"> // renderer.useAnimatedValues = true;</span><span data-v-c2b1f83f="" class="line"> // Prepare the renderView of the next frame to be rendered</span><span data-v-c2b1f83f="" class="line"> updateNextFrameRenderView(renderer, startFrame);</span><span data-v-c2b1f83f="" class="line"> // Set "start" and "end" of the sequence.</span><span data-v-c2b1f83f="" class="line"> // "step" is omitted and defaults to 1.</span><span data-v-c2b1f83f="" class="line"> // For all possible use cases of "renderSequence" check the documentation</span><span data-v-c2b1f83f="" class="line"> renderer.renderSequence({ "start": startFrame, "end": endFrame });</span><span data-v-c2b1f83f="" class="line"> // Prevent garbage collection and exiting nodejs until the renderer is closed.</span><span data-v-c2b1f83f="" class="line"> renderer.keepAlive();</span><span data-v-c2b1f83f="" class="line">});</span></code>