---
title: "Animation with Moving Objects"
canonical: "https://documentation.chaos.com/space/APPSDK/132677841/Animation%20with%20Moving%20Objects"
format: markdown
---
## **Introduction**

---

In this chapter we'll talk about the first type of animations V-Ray can render - these with moving (animated) objects. Generally V-Ray is able to animate all numeric/color values of plugin properties. This means that we'll consider "animation" every plugin property which value is changing over time.

## **Parameters**

---

Generally we need to set some values in the *SettingsOutput* plugin to have animated properties inside the scene. Here's an example excerpt from a .vrscene file with animated values:

```
SettingsOutput {
  img_width=400;
  img_height=400;
  anim_start=1;
  anim_end=10;
  anim_frame_padding=4;
  anim_renumber_on=0;
  anim_renumber_start=0;
  anim_renumber_step=1;
  anim_ren_frame_start=0;
  frame_start=1;
  frames_per_second=1;
  frames=List(
      List(1, 10)
  );
}
```


Here are the animation related parameters explained:

- **anim_start** - Start of animation range in time units
- **anim_end** - End of animation range in time units
- **anim_frame_padding** - Animation Frame Name Padding
- **anim_renumber_on** - If true, frame renumbering is used
- **anim_renumber_start** - Start number for renumber frames
- **anim_renumber_step** - Renumber frames step
- **anim_ren_frame_start** - First frame of animation range
- **frame_start** - The frame number at the start of the animation range
- **frames_per_second** - Number of frames per unit time (related to `SettingsUnitsInfo::seconds_scale`)
- **frames** - List of frames to be rendered. May contain intervals in the form of lists with start and end frame

## **Example**

---

![image](media://c6b7d53d-96ff-4081-bce7-b26839214f17)

The above animation is generated by rendering the file "Animated_Object&Camera.vrscene" from the [scene bundle](https://drive.google.com/file/d/1qgh_xbFpGhpmBVZzqJVl-_o_K00Z5R3V/view?usp=sharing). Check the comments inside the file and the included ones to see how GI can be used more optimally in an animation.

## **Code Example**

---

Here we'll show how to render a static scene and animate one of the object's positions:


<details>
<summary>Python</summary>

```python
# Compatibility with Python 2.7.
from __future__ import print_function

# The directory containing the vray shared object should be present in the PYTHONPATH environment variable.
# Try to import the vray module from VRAY_SDK/python, if it is not in PYTHONPATH
import sys, os
VRAY_SDK = os.environ.get('VRAY_SDK')
if VRAY_SDK:
    sys.path.append(os.path.join(VRAY_SDK, 'python'))
import vray

SCENE_PATH = os.path.join(os.environ.get('VRAY_SDK'), 'scenes')
# Change process working directory to SCENE_PATH in order to be able to load relative scene resources.
os.chdir(SCENE_PATH)

def onStateChanged(renderer, oldState, newState, instant):
    if newState == vray.RENDERER_STATE_IDLE_FRAME_DONE or newState == vray.RENDERER_STATE_IDLE_DONE:
        print('Image Ready, frame ' + str(renderer.frame) + ' (sequenceEnd = ' + str(renderer.sequenceEnded) + ')')
        if newState == vray.RENDERER_STATE_IDLE_FRAME_DONE:
            # If the sequence has NOT finished - continue with next frame.
            renderer.continueSequence()

# Create an instance of VRayRenderer with default options.
# The renderer is automatically closed after the `with` block.
with vray.VRayRenderer() as renderer:
    # Register a simple log callback. Always useful for debugging.
    def dumpMsg(renderer, message, level, instant):
        if level == vray.LOGLEVEL_ERROR:
            print("[ERROR]", message)
        elif level == vray.LOGLEVEL_WARNING:
            print("[Warning]", message)
        elif level == vray.LOGLEVEL_INFO:
            print("[info]", message)
        # Uncomment for testing, but you might want to ignore these in real code
        #else: print("[debug]", message)
    renderer.setOnLogMessage(dumpMsg)
    # Add a listener for the renderer state change event. We will use it to detect when a frame is completed and allow the next one to start.
    renderer.setOnStateChanged(onStateChanged)
    # Load scene from a file.
    renderer.load(os.path.join(SCENE_PATH, 'animation.vrscene'))
    # Maximum paths per pixel for interactive mode. Set a low sample level to complete rendering faster.
    # The default value is unlimited. We have to call this *after* loading the scene.
    renderer.setInteractiveSampleLevel(1)
    # 'useAnimatedValues' is used so that setting different value of the same property 
    # will result in making it an animated value instead of replacing the value.
    renderer.useAnimatedValues = True
    # Obtain a reference to the Node plugin, containing the cube geometry.
    cubeShapeNode = renderer.plugins['pCubeShape1@node']
    # Move the cube for each step of the animation.
    for i in range(1, 21):
        # Increase the time point with 1 every iteration.
        # The current frame is updated automatically based on the
        # 'frames_per_second' property of the 'SettingsOutput' plugin, if set.
        renderer.time = i
        # Obtain a copy of the cubeShapeNode transform.
        updatedTransform = cubeShapeNode.transform
        # Modify the copy of the cubeShapeNode transform.
        # The changes do not affect the scene directly since updatedTransform is a copy of the actual transform.
        updatedTransform = updatedTransform.replaceOffset(updatedTransform.offset + vray.Vector(0, 0, -3 * i))
        # Update the transform value in cubeShapeNode (applying the changes above).
        cubeShapeNode.transform = updatedTransform
    # Set 'start' and 'end' of the sequence. 'step' is omitted and defaults to 1.
    # For all possible use cases of 'renderSequence' check the documentation for VRayRenderer.renderSequence.
    renderer.renderSequence({'start': 1, 'end': 20})
    # Wait until the entire sequence has finished rendering.
    renderer.waitForSequenceEnd()
```
</details>

<details>
<summary>C++</summary>

```c++
#define VRAY_RUNTIME_LOAD_PRIMARY
#include "vraysdk.hpp"
#include "vrayplugins.hpp"
#include "utils.h"

using namespace VRay;
using namespace VRay::Plugins;
using namespace std;

const char *BASE_PATH = getenv("VRAY_SDK");
string SCENE_PATH = (BASE_PATH ? string(BASE_PATH) : string(".")) + PATH_DELIMITER + "scenes";

void onStateChanged(VRayRenderer &renderer, RendererState oldState, RendererState newState, double instant, void* userData) {
	if (newState == IDLE_FRAME_DONE || newState == IDLE_DONE) {
		printf("Image Ready, frame %d (sequenceEnded = %d)\
", renderer.getCurrentFrame(), renderer.isSequenceEnded());
		if (newState == IDLE_FRAME_DONE) {
			// If the sequence has NOT finished - continue with next frame.
			renderer.continueSequence();
		}
	}
}

int main() {
	// Change process working directory to SCENE_PATH in order to be able to load relative scene resources.
	changeCurrentDir(SCENE_PATH.c_str());
	// Load V-Ray SDK library.
	VRayInit init(NULL, true);
	// Create an instance of VRayRenderer with default options.
	// The renderer is automatically closed at the end of the current scope.
	VRayRenderer renderer;
	// It's recommended to always have a console log
	renderer.setOnLogMessage(logMessage);
	// Add a listener for the renderer state change event.
	// We will use it to detect when a frame is completed and allow the next one to start.
	renderer.setOnStateChanged(onStateChanged);
	// Load scene from a file.
	renderer.load("animation.vrscene");
	// Maximum paths per pixel for interactive mode. Set a low sample level to complete rendering faster.
	// The default value is unlimited. We have to call this *after* loading the scene.
	renderer.setInteractiveSampleLevel(1);
	// 'useAnimatedValues' is used so that setting different value of the same property 
	// will result in making it an animated value instead of replacing the value.
	renderer.useAnimatedValues(true);
	// Obtain a reference to the Node plugin, containing the cube geometry.
	Node cubeShapeNode = renderer.getPlugin<Node>("pCubeShape1@node");
	// Move the cube for each step of the animation.
	for (int i = 1; i <= 20; i++) {
		// Increase the time point with 1. The current frame is updated
		// automatically based on SettingsOutput.frames_per_second, if set.
		renderer.setCurrentTime(i);
		// Obtain a copy of the cubeShapeNode transform.
		Transform updatedTransform = cubeShapeNode.get_transform();
		// Modify the copy of the cubeShapeNode transform.
		// The changes do not affect the scene directly since updatedTransform is a copy of the actual transform.
		updatedTransform.offset += Vector(0.0, 0.0, -3 * i);
		// Update the transform value in cubeShapeNode (applying the changes above).
		cubeShapeNode.set_transform(updatedTransform);
	}
	// Set 'start' and 'end' of the sequence.
	// For all possible use cases of 'renderSequence' check the documentation for VRayRenderer.renderSequence.
	SubSequenceDesc subSequenceDescriptions[1];
	subSequenceDescriptions[0].start = 1;
	subSequenceDescriptions[0].end = 20;
	subSequenceDescriptions[0].step = 1;
	renderer.renderSequence(subSequenceDescriptions, 1);
	// Wait until the entire sequence has finished rendering.
	renderer.waitForSequenceEnd();

	return 0;
}
```
</details>

<details>
<summary>C#.NET</summary>

```csharp
using System;
using System.IO;
using VRay;
using VRay.Plugins;

namespace _02_animate_from_code
{
	class Program
	{
		static void Main(string[] args)
		{
			string SCENE_PATH = Path.Combine(Environment.GetEnvironmentVariable("VRAY_SDK"), "scenes");
			// Change process working directory to SCENE_PATH in order to be able to load relative scene resources.
			Directory.SetCurrentDirectory(SCENE_PATH);
			// Create an instance of VRayRenderer with default options. The renderer is automatically closed after the `using` block.
			using (VRayRenderer renderer = new VRayRenderer())
			{
				// Add a listener for any type of log message.
				renderer.LogMessage += new EventHandler<MessageEventArgs>((source, e) =>
				{
					// You can remove the if for testing, but you might want to ignore Debug in real code
					if (e.LogLevel != LogLevelType.Debug)
					{
						Console.WriteLine(String.Format("[{0}] {1}", e.LogLevel.ToString(), e.Message));
					}
				});
				// Add a listener for state changes.
				// It is invoked when the renderer prepares for rendering, renders, finishes or fails.
				renderer.StateChanged += new EventHandler<StateChangedEventArgs>((source, e) =>
				{
					if (e.NewState == VRayRenderer.RendererState.IDLE_FRAME_DONE || e.NewState == VRayRenderer.RendererState.IDLE_DONE)
					{
						Console.WriteLine("Image Ready, frame " + renderer.Frame + " (sequenceEnded = " + renderer.IsSequenceEnded + ")");
						// If the sequence has NOT finished - continue with next frame.
						renderer.ContinueSequence();
					}
				});
				// Load scene from a file.
				renderer.Load("animation.vrscene");
				// Maximum paths per pixel for interactive mode. Set a low sample level to complete rendering faster.
				// The default value is unlimited. We have to call this *after* loading the scene.
				renderer.SetInteractiveSampleLevel(1);
				// 'UseAnimatedValues' is used so that setting different value of the same property
				// will result in making it an animated value instead of replacing the value.
				renderer.UseAnimatedValues = true;
				// Obtain a reference to the Node plugin, containing the cube geometry.
				Node cubeShapeNode = renderer.GetPlugin<Node>("pCubeShape1@node");
				// Move the cube for each step of the animation.
				for (int i = 1; i <= 20; i++)
				{
					// Increase the time point with 1. The current frame is updated
					// automatically based on the 'frames_per_second' property of the
					// 'SettingsOutput' plugin, if set.
					renderer.Time = i;
					// Obtain a copy of the cubeShapeNode transform.
					Transform updatedTransform = cubeShapeNode.Transform;
					// Modify the copy of the cubeShapeNode transform.
					// The changes do not affect the scene directly since updatedTransform is a copy of the actual transform.
					updatedTransform = updatedTransform.ReplaceOffset(updatedTransform.Offset + new Vector(0, 0, -3 * i));
					// Update the transform value in cubeShapeNode (applying the changes above).
					cubeShapeNode.Transform = updatedTransform;
				}
				// Set 'start' and 'end' of the sequence. 'step' is omitted and defaults to 1.
				// For all possible use cases of 'renderSequence' check the documentation for VRayRenderer.renderSequence.
				renderer.RenderSequence(new SubSequenceDesc[] { new SubSequenceDesc(1, 20) });
				// Wait until the entire sequence has finished rendering.
				renderer.WaitForSequenceEnd();
			}
		}
	}
}
```
</details>

<details>
<summary>Node.js</summary>

```javascript
var path = require('path');
var vray = require(path.join(process.env.VRAY_SDK, 'node', 'vray'));

var SCENE_PATH = path.join(process.env.VRAY_SDK, 'scenes');
// Change process working directory to SCENE_PATH in order to be able to load relative scene resources.
process.chdir(SCENE_PATH);

// Create an instance of VRayRenderer with default options.
var renderer = vray.VRayRenderer();
// It's recommended to always have a console log callback
renderer.on("logMessage", function(message, level, instant) {
	if (level == vray.LOGLEVEL_ERROR)
		console.log("[ERROR] ", message);
	else if (level == vray.LOGLEVEL_WARNING)
		console.log("[Warning] ", message);
	else if (level == vray.LOGLEVEL_INFO)
		console.log("[info] ", message);
	// Uncomment for testing, but you might want to ignore these in real code
	//else console.log("[debug] ", message);
});
// Add a listener for the renderer state change event.
// We will use it to detect when a frame is completed and allow the next one to start.
renderer.on("stateChanged", function(oldState, newState, instant) {
	if (newState == "idleFrameDone" || newState == "idleDone") {
		console.log("Image Ready, frame " + renderer.frame + " (sequenceEnd = " + renderer.sequenceEnded + ")");
		// Check if the sequence has finished rendering.
		if (newState == "idleDone") {
			renderer.close();
		} else {
			// If the sequence has NOT finished - continue with next frame.
			renderer.continueSequence();
		}
	} else if (newState.startsWith("idle")) {
		console.log("Unexpected end of render sequence: ", newState);
		renderer.close();
	}
});
// Load scene from a file asynchronously.
renderer.load("animation.vrscene", function(err) {
	if (err) throw err;
	// Maximum paths per pixel for interactive mode. Set a low sample level to complete rendering faster.
	// The default value is unlimited. We have to call this *after* loading the scene.
	renderer.setInteractiveSampleLevel(1);
	// "useAnimatedValues" is used so that setting different value of the same 
	// will result in making it an animated value instead of replacing the value.
	renderer.useAnimatedValues = true;
	// Obtain a reference to the Node plugin, containing the cube geometry.
	var cubeShapeNode = renderer.plugins["pCubeShape1@node"]
	// Move the cube for each step of the animation.
	for (var i = 1; i <= 20; i++) {
		// Increase the time point with 1. The current frame is updated
		// automatically based on SettingsOutput.frames_per_second, if set.
		renderer.time = i;
		// Obtain a copy of the cubeShapeNode transform.
		var updatedTransform = cubeShapeNode.transform;
		// Modify the copy of the cubeShapeNode transform.
		// The changes do not affect the scene directly since updatedTransform is a copy of the actual transform.
		updatedTransform = updatedTransform.replaceOffset(updatedTransform.offset.add(vray.Vector(0, 0, -3 * i)));
		// Update the transform value in cubeShapeNode (applying the changes above).
		cubeShapeNode.transform = updatedTransform;
	}
	// Set "start" and "end" of the sequence. "step" is omitted and defaults to 1.
	// For all possible use cases of "renderSequence" check the documentation for VRayRenderer.renderSequence.
	renderer.renderSequence({"start": 1, "end": 20});
	// Prevent garbage collection and exiting nodejs until the renderer is closed.
	renderer.keepAlive();
});
```
</details>