User Guide

Voxel Unity SDK Quickstart Guide

Everything you need to build, tune and ship Unity applications that run on a Voxel VX2 / VX2-XL volumetric display with the Voxel Unity Plugin (VxU).

Overview

Unity is a popular 3D engine for developing applications and games. The Voxel Unity Plugin (VxU) makes it possible for Unity applications to run on the Voxel VLED display, allowing you to leverage all the benefits of the Unity Engine, including the Asset Store and community support resources.

To get started developing VLED apps with Unity, you will need to download both Unity and the Voxel VLED Environment. At the time of writing, the VxU plugin only supports Windows.

Getting started with Unity

We recommend using the latest 2022 Unity version with the Voxel Unity Plugin. Unity Hub makes it easy to manage your Unity installation.

Note: When developing any software with Unity, avoid changing Unity builds mid-project — switching Unity versions can cause compatibility problems and potentially break your project.

Downloading the VxU plugin

The Voxel Unity Plugin is not on the Unity Asset Store. It is an asset package contained within the Voxel VLED Environment, which is obtainable from our website (www.voxon.co).

The Voxel Unity Plugin uses a C# bridge to interact with the VLED environment (ledhost.dll or voxiebox.dll). For this interaction to work, a few files and system settings need to be in place:

  • C#-Bridge-Interface.dll and C#-Runtime.dll must exist in the Voxel Runtime directory (by default C:\Voxon\System\Runtime).
  • The user Path variable needs the Voxel Runtime added.
  • The Voxel Runtime path needs to be added to the system registry.

These are set up for you when you install the Voxel VLED Environment.

Project setup

Make a new Unity project in the Unity Hub, using the Built-In Render Pipeline.

Importing the VxU package

Import the Voxel VxU Unity package through Assets > Import Package > Custom Package. Locate the Voxel .unitypackage file and open it.

By default, make sure all the files are ticked to be imported, and import them into your project. When you are more familiar with the plugin, you can import only the files you need.

Once the plugin has imported successfully, you will notice some new directories in your project and a Voxel menu option in the top menu bar.

Building the scene

The VxCamera

Create an empty GameObject and add a VxCamera component. The VxCamera applies a global transformation matrix to map captured scene depth data in Unity to voxel coordinates within the display. With the VxCamera GameObject selected, you can view and adjust the volume parameters in the Inspector.

  • The Camera Shape parameter is set to VXCAM_LOCK_TO_HARDWARE by default. For development it can be useful to set it to VXCAM_Cylinder so you can preview the capture area even without a VX2 connected.
  • For a VX2, set the viewfinder Dimensions to 4,4,4.
  • For a VX2-XL, set the viewfinder Dimensions to 8,4,8.

The capture camera

Make a Unity camera to act as your capture camera (GameObject > Camera, or reserve the Main Camera for this purpose). The capture camera writes scene depth and colour data to a hidden RenderTexture, which is used to rebuild the captured scene in the VLED display — so it cannot also be used for standard scene rendering. As a side effect of RenderTexture projection, the capture camera appears to behave as a light source and casts a shadow on occluded surfaces.

Set the capture camera up as follows:

SettingValue
Clear FlagsSolid Color
BackgroundBlack
ProjectionOrthographic (Perspective can work, but may result in a non-ideal render projection)
SizeLarge enough that the camera bounds fully encapsulate the capture volume
Clipping PlanesSmall enough to fully encapsulate the capture volume
HDROff
MSAAOff (paired with HDR off, these settings reduce visual artifacts inside the display)

VxLitRenderer & VxHardwareController

  • Add a VxLitRenderer component to your designated capture camera.
  • Assign the camera component to the VxLitRenderer's Depth Camera field.
  • Set the Render Type to Render_Poltex_From_Depth_Data.
  • You don't have to change the resolution now, but you may get better visual output by setting the Resolution to 700.
  • Add a VxHardwareController component to the camera. This displays debugging information in the LedWin window, and includes an option to automatically start the display at a set speed once the application launches.

The Voxel shader

Any object in your scene needs to use a Voxon/VxLitShader in order to be captured by the capture camera. In this early stage of development, the VxLitShaders only support diffuse texture maps and colour tinting.

LuminosityCullThreshold
Culls output below a luminosity threshold.
BrightnessAdjust
Multiplies the overall brightness of the individual material.
Shadow Opacity
Reserved — do not use at this stage.

Be aware: there can be significant overhead when rendering large numbers of objects using the VxLitShader.

Render pipeline overview

The VxCamera, VxLitRenderer and VxLitShader are the vital elements in the VxU render pipeline. Any object with the VxLitShader calls the VxLitRenderer to capture its depth data within the scene. The VxLitRenderer converts the captured image into a point-cloud array and calculates visual effects like depth occlusion. Lastly, the VxCamera takes the point-cloud data from the VxLitRenderer — relative to its object position, orientation and scale — and transforms it into a space relative to the VLED display device.

1 mm0.078125 Unity units
1 Unity unit12.8 mm

VXProcess settings

The VXProcess settings are the global settings for developing for the Voxel environment. You'll find them in the menu bar under Voxel > Process.

Guidelines
Toggles a border around the outside of the volume on or off. Also accessible in code with VXProcess.Instance.guidelines.
Show_info
Displays a panel in the LedWin window with the version information of the environment the app was built with — the Unity Plugin, the Core Runtime, the VxU Bridge and LedWin — plus volume render analytics: VPS (volume-frames rendered per second), IDrawables (script objects added to the drawable register) and GameObjects.
Camera > Active
When checked, testing your app launches the Voxel Simulator. Disable this to debug without loading the simulator.
Camera > Apply_vx_on_load
At runtime, automatically applies a VXComponent to any object with a renderer that is not tagged VoxieHide and does not already have one. Not required with the VxLitRenderer pipeline.
Camera > Editor Camera
Designates the capture camera used in the volume-capture pipeline. Must be set manually — without it, the display volume will always be empty.
Performance > Fixed Frame Rate
Enable this to force the volume to update at a fixed rate.
Performance > Target Frame Rate
The target frame rate to operate at when a fixed frame rate is enabled.
Recording > Capture Export Path
Where to output VCB (Volumetric Compressed Bitmap) video files when recording.
Recording > Record on Load
If enabled, the scene is automatically recorded when it starts.
Recording > Recording Style
Toggle between recording an ANIMATION (a chronological series of frames) or a SINGLE_FRAME (one instance).
Logging > Logger_max_lines
The number of lines the internal Voxel logger can output on the secondary screen during runtime. Default is 10.

Testing your app

With the capture camera, capture volume and VXProcess set up, you're ready to test.

Important: Always save your project before testing, as Unity / the VxU plugin can crash often. Always press the Esc key to exit the simulator once you have finished testing — do not press the Play triangle button in Unity to end the test, as it may crash your project. In case of Unity crashing, it is possible to recover the scene.

Real-world scale

10 Unity units1 Voxel unit
VX2 diameter2 Voxel units = 256 mm
VX2-XL diameter4 Voxel units = 512 mm

Input manager

Because Unity runs in headless mode, the standard Unity Input System is unavailable. Voxel's input manager allows input during headless mode and supports keyboard, mouse, SpaceMouse, and up to 4 joypad inputs.

  • Clear all inputs in the input array, or add a new input element.
  • Input name string — the name used to query the input. Note that if an input element's name matches another, the input manager will attempt to hide the repeated element.
  • Input key/button — the assigned button on an input device. Joypad button labels (and mapped indices) are relative to the layout of an Xbox controller.
  • Clear a single input element as needed.
  • Controls for saving and loading the input JSON file are at the bottom of the input manager panel (you may need to scroll down). Ensure you save changes for them to apply.

Using Voxel inputs

Query input for a defined key or button with the following functions (using Quit as an example string).

Keyboard inputs

Voxon.Input.GetKey("Quit");     // true as long as the key is held
Voxon.Input.GetKeyUp("Quit");   // true on the frame the key is released
Voxon.Input.GetKeyDown("Quit"); // true on the frame the key is pressed

// Alternatively, query specific keys by keycode:
Voxon.VXProcess.Runtime.GetKeyDown(VX_KEYS.KB_F1); // true if F1 is pressed

Joypad inputs

Voxon.Input.GetAxis("Horizontal");   // analogue input value from -1 to 1
Voxon.Input.GetButton("Quit");       // true as long as the button is held
Voxon.Input.GetButtonUp("Quit");     // true on the frame the button is released
Voxon.Input.GetButtonDown("Quit");   // true on the frame the button is pressed

You can change from the default XInput (joyAPIType = 1) to Direct Input (joyAPIType = 0):

VXProcess.Runtime.SetJoyAPI(int joyAPIType);

Input configurations are saved as a .json file within the project directory, and can be transferred between projects using the load button at the bottom right of the input manager panel.

VxU builds

For the most part, building a Unity project for the Voxel VX2 is identical to building a standard Windows build. The Voxel plugin adds the following folders and files to the build, in addition to the standard build files:

  • BuildDllsC#-bridge-interface.dll, C#-Runtime.dll, LedWin.dll
  • VX.bat

VX.bat is your launch file for running the application in headless mode. While you can run the application via the .exe, this comes with significant processing overhead and shouldn't be the standard running mode.

The files in BuildDlls are direct copies of the DLLs in your Voxon\System\Runtime folder, and let you distribute specific DLL versions with your application if needed. To use them, drag them into the build directory — the Unity application will prioritise those over the DLLs installed on the user's machine.

It is strongly recommended to configure Project Settings > Player. To maximise compatibility with Voxel Lighthouse, the Product Name should not contain spaces.

Performance monitoring

A "Volume" can be considered the 3D equivalent of a 2D frame, where scene data is composited and rendered for viewing. In viewing terms, Volumes Per Second (VPS) is roughly analogous to Frames Per Second (FPS), and indicates how smooth and complete motion on the display will appear.

Each volume is made of individual slices that illuminate a single plane within the volume as the LED panel moves through it. The number of slices in a volume is directly proportional to the revolution speed of the VLED display. In most circumstances the VX2 operates at 900 rpm.

You can preview the current VPS draw rate on the secondary screen by turning on Show_Info in the VXProcess window. Bear in mind that VPS is not correlated to the Unity framerate — the display can refresh the volume at a different rate to the frames Unity calculates. VPS is heavily affected by the number of illuminated voxels in the display, in addition to the load of running the Unity application.

Tips to improve your VPS while developing:

  • In general, the more voxels (3D pixels) you render, the harder the CPU works.
  • The VX2's resolution is low compared to a traditional 2D screen — roughly the equivalent of 128 × 128 × something pixels. Fine details in textures and meshes are often lost at this resolution, so consider leaning into the low-resolution style; playing to the display's strengths lets the viewer fill in the gaps.
  • Reduce the overall number of draw calls by reducing meshes and submeshes (a mesh with multiple materials is split into a submesh per material).
  • Reduce texture size — every texture rendered needs to be interpreted by the voxel frame buffer.
  • Check whether other processes on your PC are using resources.
  • Unity's own profiler may help you find performance in other aspects of your project.

Direct DLL functions & IDrawable

If you are an experienced Vx app developer, you may wish to interact with the volume directly. To draw Voxel primitives — such as text and simple shapes like cubes, spheres, cones, lines and dots — from a custom C# script, inherit the IDrawable class from the Voxel namespace and add it to the VXProcess.cs internal IDrawable reference list.

The VxProcess manages a list of references to IDrawable-inherited classes. When rendering a scene, this list is iterated through and each one's Draw() function is called. All VXGameObject references are also maintained in a separate list within the VxProcess. Together these lists maintain most (in most cases, all) of the Unity GameObjects that are rendered on the Voxel display.

Implementing IDrawable

using Voxon;

public class YourClass : MonoBehaviour, IDrawable
{
    void Start()
    {
        // Add this instance to the IDrawables list
        VXProcess.Drawables.Add(this);
    }

    // Called by the VXProcess on every update
    public void Draw()
    {
        VXProcess.Runtime.DrawBox();
        VXProcess.Runtime.DrawCube();
        VXProcess.Runtime.DrawLine();
        VXProcess.Runtime.DrawSphere();
    }
}

VXProcess.Runtime gives you access directly to the C# bridge, so you can interact with the Voxel Runtime in many ways beyond just drawing graphics. An example of drawing straight to the display can be found in the CanvasToLED pipeline.

Canvas setup

The Voxel VLED display supports rendering a low-resolution Unity Canvas within the volume.

How it works: the Canvas object is captured by a dedicated camera and saved to a RenderTexture with the same resolution as the LED panel. The CanvasToLED component then converts the RenderTexture to a 7-colour palette, and each pixel is drawn directly onto the display at a desired angle.

Workflow

  1. Create a new Render Texture. Set the size to match the display resolution (128 × 128 for VX2, 256 × 128 for VX2-XL). Set Filter Mode: Point.
  2. Create a camera to serve as the UI camera, with: Clear Flags Solid Color; Background Black; Projection Orthographic; Culling Mask (optional) UI; Size varies; Clipping Planes (optional) Near 0.3, Far 1.
  3. Create a Canvas. Set its layer to UI and Pixel Perfect: True. Assign the UI camera as the Render Camera. On the Canvas Scaler component set Scale Factor: 1 and Reference Pixels Per Unit: 1.
  4. Add a CanvasToLED component to the canvas object. Assign the UI camera to CanvasCamera and the RenderTexture to RenderTexture.
  5. Set GridSize to the horizontal width of your target display (128 for VX2, 256 for VX2-XL). This must match the display resolution of the Render Texture.

CanvasToLED parameters

Draw Mode
Determines how the canvas is drawn. Axial draws it as a flat plane through the diameter of the display; Concentric projects it onto a cylinder in or around the display.
Gradient steps
Allows a slightly broader luminosity gamut by repeating brighter pixels over multiple slices. This is very computationally expensive and can interfere with the readability of your interface.
Sweep Slider
In Concentric mode, determines how much of the cylindrical radius the canvas covers.
View 2D Compatibility
At runtime, modifications are made to UI elements so they appear better on the LED display. Enabling this lets the canvas present normally in the Unity game window.
AxialPosOffset
In Axial mode, applies a horizontal offset to where the canvas is drawn.
FacingOffset
Applies an offset to where the canvas faces; a value of 0 has the canvas elements facing the front of the display.

Note: FacingOffset is not measured in degrees or radians. Its effect depends on the current rotational speed of the VLED display and the number of image slices produced to render a volume, so user-adjusted values may need an additional modifier to deliver the same experience across different devices.

Pixel-perfect graphics

When working with a pixel-perfect canvas, ensure your graphical elements are set up for a pixel-perfect pipeline — otherwise elements rendered in the CanvasToLED pipeline may appear hazy or jagged.

  • Make sure images are drawn at the appropriate scale and are not resized.
  • When importing, set Filter Mode to Point (no filter) and Compression to None.
  • CanvasToLED supports TextMeshPro, but TextMeshPro does not inherently support Unity's Pixel Perfect setting. You may need to find appropriate fonts and adjust settings so they fit the pixel grid, and may need to adjust text boxes individually.
  • CanvasToLED assists with alignment in a limited way: it draws a black border on text to prevent pixel colour bleeding, then boosts the colour intensity of the inner text fill so colours draw closer to their actual value. Side effects: CanvasToLED does not support text borders, and TextMeshPro text is only ever drawn in the 7-colour palette (no dithering).

Appendix A — Data flow from Unity to the volumetric display

An overview of how data and interactions travel from Unity to the volumetric display.

  1. UnityA Unity scene containing an active camera prefab and some models or scripts that interact with the volumetric display.
  2. Unity × Voxel PluginHas a valid Voxel camera prefab linked to it and a valid VxProcess script defined in its Process Manager.
  3. VxProcess.cs (includes Runtime.cs)Manages a valid Voxel Runtime and camera. Starts a new Voxel Application Window, then enters its main update loop: check for a Voxel Runtime breath(), process all graphics and prepare the volumetric image while listening for system and user input. Sends the volumetric frame data to the display through its Runtime.cs class instance.
  4. VXURuntime.csA local instance that lets the VxProcess script interact with the C# Runtime — a local wrapper / C# instance that adheres to IRuntimePromise. Requires C#-Runtime.dll to work.
  5. C# Bridge Interface — C#-Runtime.dllConverts the C# Voxel runtime calls into C++ so the native Voxel Runtime (ledhost.dll or voxiebox.dll) can be accessed.
  6. Voxel Runtime (voxiebox.dll)The native runtime receives the translated data and instructions, operates the Voxel application, and sends data to the volumetric display.
  7. Volumetric displayRenders the Voxel frame data as a complete volume.
Get started

Bring your content to the volume

Explore the VX2 and VX2-XL, try the live simulator, or talk to us about your use case.