V-Ray for 3ds Max
Rendering with V-Ray GPU directly to VR Headsets
This page provides information for how best to render using V-Ray GPU for use with VR headsets like the Oculus Rift or HTC Vive.
Last updated 1 September 2026
This page provides information for how best to render using V-Ray GPU for use with VR headsets like the Oculus Rift or HTC Vive.
Overview
V-Ray GPU can be set up to view IPR render through VR headsets such as the Oculus Rift or HTC Vive. This way, when rendering a 6x1 stereo cube panorama, users can utilize a VR headset to view the render in proper virtual space as it renders as opposed to seeing the render as a flat image in the VFB. With the help of a MAXScript, it is possible to update the position of the camera with a game controller to move around in the virtual space while V-Ray GPU updates and refreshes the render from the new camera location.
Want to follow along but don’t have a license?

V-Ray GPU Output to Headset Setup
1. Confirm headset display is installed properly.
See how to set up your devices here.
Direct internet connection is needed to login to Oculus Account. It seems that it does not work through a proxy. You need at least 5 GB disk space on your C: drive.
This step is not needed if using HTC Vive.
Oculus Rift only: connect headset to the default graphics adapter (it will not work if connected to other graphic adapters).
In the Oculus app, enable apps from unknown sources: turn on Oculus Settings > General > Unknown Sources
For HTC Vive support, install Steam and Steam VR:
https://support.steampowered.com/kb_article.php?ref=2001-UXCM-4439#install-steam
This is needed in order to use the OpenVR interface for HTC Vive, Oculus Rift and other VR devices. This step is optional for Oculus Rift.
2. Check that the headset is working and displays its home scene correctly.
V-Ray Production Render Settings
- Turn off Image filter
- Select Camera Type to Cube 6x1
- Render resolution width must be divisible by 6
V-Ray GPU IPR Settings
- Go to Render Settings > Settings > Stereoscopic rendering and select Stereo mode > Oculus Rift (mono), Oculus Rift (stereo), OpenVR (mono) or OpenVR (stereo)
- Select suitable image output size, for example 3000x500. You may start with a lower resolution.
- Render Device Select > exclude the video card that is connected to the VR headset. Using the same adapter for GPU rendering and VR display will result in frame drops and poor VR experience. DR session with the local host excluded should work fine.
3. Start V-Ray GPU IPR render. The first render will start slowly since it takes some time to load the Oculus VR library.
MAXScript Reference
The information in this section will help explain how to use MAXScript to navigate around the VR environment with a game controller. Below is a download link to a sample MAXScript that sets the buttons and analog sticks in a general configuration to get you up and running. For more details, please see comments in the top section of the script file.
Access to VR controllers state
Access to VR controllers state is available in ActiveShade mode. Currently, the controller state is only accessible during Oculus Rift preview sessions (Stereo mode = Oculus rift).
You can refer to the current renderer and check to see if it supports VR controller interfaces from MAXScript:
<code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">renderers.current</span><span data-v-c2b1f83f="" class="line">V_Ray_GPU_Next:V_Ray_GPU_Next</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">ivraygpu=getinterface renderers.current "vrayrtmax_interface"</span><span data-v-c2b1f83f="" class="line"><MixinInterface:vrayrtmax_interface></span></code>
VR controller interfaces
Assuming that variables ivrayrt and rt are initialized as stated above, you can list the VR controllers related interface properties:
<code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">showinterface ivraygpu</span><span data-v-c2b1f83f="" class="line"><MixinInterface:vrayrtmax_interface></span><span data-v-c2b1f83f="" class="line">Interface: vrayrtmax_interface</span><span data-v-c2b1f83f="" class="line"> Properties:</span><span data-v-c2b1f83f="" class="line"> .vrControllerLTouch : Interface : Read</span><span data-v-c2b1f83f="" class="line"> .vrControllerRTouch : Interface : Read</span><span data-v-c2b1f83f="" class="line"> .vrControllerRemote : Interface : Read</span><span data-v-c2b1f83f="" class="line"> .vrControllerXBox : Interface : Read</span><span data-v-c2b1f83f="" class="line"> Methods:</span><span data-v-c2b1f83f="" class="line"> Actions:</span><span data-v-c2b1f83f="" class="line">OK</span></code>
The interfaces are also available as renderer properties:
<code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">showproperties renderers.current</span><span data-v-c2b1f83f="" class="line"> ...</span><span data-v-c2b1f83f="" class="line"> .vrControllerLTouch : Interface</span><span data-v-c2b1f83f="" class="line"> .vrControllerRTouch : Interface</span><span data-v-c2b1f83f="" class="line"> .vrControllerRemote : Interface</span><span data-v-c2b1f83f="" class="line"> .vrControllerXBox : Interface</span><span data-v-c2b1f83f="" class="line"> ...</span><span data-v-c2b1f83f="" class="line">false</span></code>
All VR controller interfaces are uniform – they contain the same methods and properties regardless of controller type. Interface information can be displayed as follows:
<code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">showinterface renderers.current.vrControllerLTouch</span><span data-v-c2b1f83f="" class="line"> Interface: VRController_LTouch</span><span data-v-c2b1f83f="" class="line"> Properties:</span><span data-v-c2b1f83f="" class="line"> .connected : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .timeInSeconds : double : Read</span><span data-v-c2b1f83f="" class="line"> .indexTriggers : float by value array : Read</span><span data-v-c2b1f83f="" class="line"> .gripButtons : float by value array : Read</span><span data-v-c2b1f83f="" class="line"> .thumbSticks : point2 by value array : Read</span><span data-v-c2b1f83f="" class="line"> .buttonA : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonB : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonRThumb : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonRShoulder : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonX : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonY : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonLThumb : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonLShoulder : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonUp : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonDown : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonLeft : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonRight : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonEnter : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonBack : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonVolUp : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonVolDown : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .buttonHome : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchA : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchB : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchRThumb : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchRThumbRest : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchRIndexTrigger : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchX : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchY : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchLThumb : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchLThumbRest : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchLIndexTrigger : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchRIndexPointing : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchRThumbUp : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchLIndexPointing : boolean : Read</span><span data-v-c2b1f83f="" class="line"> .touchLThumbUp : boolean : Read</span><span data-v-c2b1f83f="" class="line"> Methods:</span><span data-v-c2b1f83f="" class="line"> <void>setNotifyCallback <string>callback <float>threshold</span><span data-v-c2b1f83f="" class="line"> Actions:</span><span data-v-c2b1f83f="" class="line">OK</span></code>
VR controller interface details
Property | Description |
|---|
Property | Description |
|---|---|
connected | True if the corresponding controller is connected; otherwise false. |
timeInSeconds | System time of last controller state update. |
indexTriggers[1] | Left and right finger trigger positions, in the range of 0.0 to 1.0. |
gripButtons[1] | Left and right grip button positions, in the range of 0.0 to 1.0. |
thumbSticks[1] | Left and right thumb stick position coordinates in the range of -1.0 to 1.0, as point2 values. |
buttons, touches | Boolean properties that represent the state of various buttons and sensors on the controller. |
setNotifyCallback <callback> <threshold> | Sets notification MAXScript that will be executed whenever controller state changes. |
setNotifyCallback Sample Use
Sets notification callback which outputs left index trigger position of the XBox controller whenever its state changes:
<code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">fn myNotifyCallback = (</span><span data-v-c2b1f83f="" class="line"> format "XBox Left Trigger value: %\</span><span data-v-c2b1f83f="" class="line">" renderers.current.vrControllerXBox.indexTriggers[1]</span><span data-v-c2b1f83f="" class="line"> )</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line"> renderers.current.vrControllerXBox.setNotifyCallback "myNotifyCallback()" 0.1</span></code>
Stop receiving notifications from the XBox controller:
<code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">renderers.current.vrControllerXBox.setNotifyCallback "" 0.1</span></code>
Process notifications from two different controllers using a common callback:
<code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">iXBox= renderers.current.vrControllerXBox</span><span data-v-c2b1f83f="" class="line">iRemote= renderers.current.vrControllerRemote</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">fn myNotifyCallbackWithParam controller_interface = (</span><span data-v-c2b1f83f="" class="line"> format "controller % button UP state %\</span><span data-v-c2b1f83f="" class="line">" controller_interface controller_interface.buttonUP</span><span data-v-c2b1f83f="" class="line"> )</span><span data-v-c2b1f83f="" class="line"></span><span data-v-c2b1f83f="" class="line">iXBox.setNotifyCallback "myNotifyCallbackWithParam iXBox" 0.1</span><span data-v-c2b1f83f="" class="line">iRemote.setNotifyCallback "myNotifyCallbackWithParam iRemote" 0.1</span></code>
Scripting Focus
Focus method in VRay GPU is settable using MAXScript:
<code data-v-c2b1f83f=""><span data-v-c2b1f83f="" class="line">renderers.current.stereo_focus=0</span></code>
stereo_focus can take the following values:
0 - parallel
1 - rotation
2 - shear transform
Notes
- Head orientation tracking is only supported when rendering a panorama using the Cube 6x1 camera.
- Rotation and shear use camera target distance as a "zero parallax" plane distance.
- In order to get a comfortable feel, you must set the camera target distance to a high value. Alternatively, you can change the stereo_focus method to 0 (parallel) using MAXScript.
- Shear is not supported for panorama renders.