Skip to main content
Skip table of contents

3D Projection with the PROPixx and 3D Polarizer

In this guide, we will cover how to present stereoscopic stimuli using the PROPixx projector and DepthQ 3D Polarizer. These two devices can be used together for full-colour stereoscopic presentation at up to 480 Hz (240 Hz/eye). In addition to high-speed presentation, this system has several other advantages, including:

  • Passive circular filters are plastic and thus MRI, MEG and OPM safe

  • Custom filter sheets can be purchased to create custom viewing apparati (e.g., for non-human primates)

  • No specialized graphics card or native 3D support required

  • Optional custom high-speed sequencer designed in partnership with the NIH to actively manage crosstalk levels, and reduce Pulfrich effects

First, we will consider some general hardware and screen requirements, then discuss our recommended method of preparing stimuli for 3D stimulus presentation. Code examples will be provided where appropriate.

Getting Started: Equipment and Materials

To effectively present 3D stimuli, the DepthQ polarizer must be connected to the VESA 3D port on the back of the PROPixx (pictured below). The polarizer should be placed directly in front of the lens with the arrow pointing away from the projector. Wingnuts on the sizes of the polarizer frame can be used to adjust the height of the polarizing filter so that it aligns with the lens.

A.png

A. VESA 3D port on the back of the PROPixx. B. Example placement of DepthQ polarizer in front of the projection lens. C. Example 3D rear-projection layout, note the polarizer in front of the PROPixx on the left.

The 3D glasses provided along with the polarizer are standard circular polarizing filters. These are the same glasses used for 3D movies at a cinema. If you need a custom lens layout, you can purchase right- and left-handed circular filter material directly from certain manufacturers (for example, here) and cut it to size. Note that when buying filter material, HE indicates left-handed and HER indicates right-handed polarization.

It is normal for the polarizer and glasses to filter some visible light. Average spectral transmission of 30-35% is not uncommon. During luminance tests, VPixx staff scientists noted that inexpensive, commercial 3D filter glasses can vary in transmission rates across units. Users requiring an exact measure of light transmission should take direct measurements using a colorimeter or spectrophotometer, and should not assume measurements generalize across individual pairs glasses.

Projection screen materials

Typical projection screens are designed for Lambertian light distribution. In other words, they aim to diffuse or reflect light in every direction, thus ensuring 1) equal luminance output across the display surface and 2) wide viewing angles. Unfortunately, this same property severely degrades 3D polarization. In practice, projection screens optimized for 2D use make for poor-quality 3D displays.

Fortunately, specialty ‘silvered’ screen materials exist. These materials prioritize direct reflectance or transmission, preserving polarized light. Silvered screens are often recognizable by their shiny surface and grey coloration (as opposed to the bright white of 2D screens). Below is a side-by-side example:

3D.png

Left: a silvered 3D screen, with a visibly darker material. Right: a standard 2D screen.

VPixx Technologies manufactures several screen shapes and sizes for standalone, tabletop and in-bore projection systems. All of our screen models can be fitted with a 3D-optimized screen material.

Due to the non-Lambertian light distribution, 3D screens are more prone to hotspotting (bright spots and uneven luminance), particularly at short projection distances. VPixx Software Tools include a PROPixx calibration routine to correct for hotspotting in these cases; see the section below for details.

Hotspot correction with the PROPixx projector

Due to their polarization preservation qualities, 3D-optimized screens can sometimes display hotspotting or uneven luminance, particularly at short projection distances. To perform a hotspot correction, you will need:

  • A device which can report the luminance value for specific screen points in cd/m^2, and

  • A Windows computer with LabMaestro 1.7 or later installed   

First, ensure your firmware is on the latest version. To do this, open LabMaestro with your device connected, Select the PROPixx device, right-click and select Firmware Update from the side menu. Follow the steps in the widget to complete the update.

After the update, set the PROPixx to the correct projection mode for your layout (e.g., rear projection, ceiling mount projection, desired resolution).

Select the PROPixx from the device menu, right-click and select “Hotspot Correction.” Follow the steps in the widget to complete the calibration.

After the correction is done once, it can be enabled or disabled on any computer via the following methods:

  • In LabMaestro via device settings (right click PROPixx and select ‘Configuration’)

  • In MATLAB via the following commands (followed by a register write):

    • Datapixx('EnableHotspotCorrection');

    • Datapixx('DisableHotspotCorrection');

  • In Python via the PROPixx class (followed by a register write):

    • setHotSpotCorrection(enable) #set to true or false

If you intend to build your own screen for stereoscopic presentation, we recommend the following flexible screen materials from Stuart FilmScreen, which can be purchased directly from the supplier:

Rear-projection: Stuart FilmScreen FilmScreen 150
Front-projection: Stuart FilmScreen Silver 5D

These are the same materials we use in our screens.


Mirrors in the light path

Some projection systems use one or more 45-degree mirrors to redirect the beam of light to the screen. This is common in MEG and MRI facilities, where the projection waveguide may be offset from the screen location. MRI systems also use mirrors mounted on the head coil to allow the participant to view an image on a screen at the head of the bore.

For 3D applications, we recommend all mirrors in the light path be first-surface for the best possible 3D image. That is, the reflective layer of the mirror should be in front of the glass layer, not behind it. This ensures internal reflections within the glass layer do not compromise the polarization.

mirror1.png

Types of mirrors. Source: https://www.dynasil.com/optical-coatings/first-surface-vs-second-surface-mirror/

An easy way to tell if a mirror is first- or second-surface is to place an item against it. If it connects with its reflection, it is a first-surface mirror.

mirror2.png

Source: Wikipedia

Finally, some eye-tracking systems utilize “hot” mirrors that have an infrared reflective coating. It is strongly advised to not use hot mirrors during 3D stimulus presentation, as these are known to disrupt polarization.

Enabling 3D Mode and Formatting 3D Stimuli

There are many ways to format 3D stimuli for presentation. Here we discuss several strategies and when it is best to use them. All of the strategies discussed are supported by the PROPixx; some are more robust than others. At the end of this section, there is a summary of the different options, their supported refresh rates and their best use cases.

Frame-sequential stereo

In frame-sequential stereo, images are interleaved temporally. Even and odd video frames are presented to the left and right eye, respectively.

Time (4).png

Frame sequential stereo

Image alternation is controlled manually (e.g., drawing left and right eye images and flipping them one after another) or via dedicated stereo draw buffers alternately sampled during stimulus presentation.

This mode is the default behaviour for a connected 3D Polarizer. It will alternate polarization on subsequent video frames until instructed otherwise, independent of video content.

This method’s biggest advantage is simplicity and ease of implementation; however, it is vulnerable to frame dropping and 3D de-synchronization. As such we recommend a small modification to this method, described in the next section.

Stereo Blue Lines

Stereo Blue Lines are a popular method of explicitly encoding each video frame to target the correct eye. This preserves stereo synchronization even if your system is dropping frames.

Stereo Blue Line is easy to implement:

  1. Organize your stimuli as you would for frame-sequential stereo.

  2. To assign a frame to the left eye: Set the bottom row of pixels in the frame to an intensity greater than mid-grey [128, 128, 128]

  3. To assign a frame to the right eye: Set the bottom row of pixels in the frame to an intensity less than mid-grey [128, 128, 128]

Note images must be full-screen for Blue Lines to work.

Time (5).png

Stereo Blue Lines added to the bottom of each image to ensure they are shown to the correct eye. The lines are exaggerated for visibility.

Some software will automate Blue Line generation for you. We generally recommend drawing the line yourself. It is simple and ensures you are formatting your video frames correctly.

MATLAB Example
MATLAB
function helloWorld3D()

% Initialize PROPixx
initializePROPixx();

% Initialize Psychtoolbox window
PsychDefaultSetup(2);
screenNumber = max(Screen('Screens'));
[windowPtr, rect] = PsychImaging('OpenWindow', screenNumber, 0);
Screen('BlendFunction', windowPtr, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
HideCursor;

% Initialize stimuli
helloText = 'Hello';
worldText = 'World';

% Start loop drawing the message
while true
    DrawFormattedText(windowPtr, helloText, 'center', 'center', 255);
    drawBlueLine(windowPtr, rect, 0);
    Screen('Flip', windowPtr);

    DrawFormattedText(windowPtr, worldText, 'center', 'center', 255);
    drawBlueLine(windowPtr, rect, 1);
    Screen('Flip', windowPtr);
    
    [~, ~, keyCode] = KbCheck;
    if keyCode(KbName('Escape'))
        break;
    end
end

% Close the Psychtoolbox window
sca;
Datapixx('Close');
end

function initializePROPixx()
% All VPixx hardware commands to set the right mode for the PROPixx
Datapixx('Open');
Datapixx('EnableVideoStereoBlueline');
Datapixx('RegWr');
end

function drawBlueLine(windowPtr, rect, frame)
% Helper function to draw lines on the appropriate image
% if Frame = 0, draw left eye blueline
% if Frame = 1 draw right eye no blueline
% Call immediately before flip
if frame == 0
    frameColor = [255, 255, 255];
else
    frameColor = [0, 0, 0];
end
rowStart = [rect(3)/2-16, rect(4)-1];
rowEnd = [rect(3)/2+16, rect(4)-1];
Screen('DrawLine', windowPtr, frameColor, rowStart(1), rowStart(2), rowEnd(1), rowEnd(2),2);
end
Python Example
PY
from psychopy import core, visual
from psychopy.hardware import keyboard
from pypixxlib._libdpx import DPxOpen, DPxClose, DPxWriteRegCache, DPxEnableVidVesaBlueline, DPxSetVidMode

def initializePROPixx():
    #All VPixx hardware commands to set the right mode for the PROPixx
    DPxOpen()
    DPxSetVidMode('C24')
    DPxEnableVidVesaBlueline()
    DPxWriteRegCache()
    
def drawBlueLine(win, frame=0):
    #Helper function to draw lines on the appropriate image
    #if Frame = 0, draw left eye blueline
    #if Frame = 1 draw right eye no blueline
    #Call immediately before flip
    if frame==0: 
        frameColor = [255,255,255]
    else:
        frameColor = [0,0,0]
    rowStart= [-win.size[0]/2, -win.size[1]/2]
    rowEnd =[win.size[0]/2, -win.size[1]/2]
    line = visual.Line(
            win=win,
            units = 'pix',
            start=rowStart,
            end=rowEnd,
            interpolate = False, #MUST be set to false
            colorSpace = 'rgb255',
            lineColor = frameColor,
            lineWidth=2)
    line.draw()
    
#Begin Experiment
kb = keyboard.Keyboard()
initializePROPixx()
win = visual.Window(
        screen = 1,
        monitor =None, 
        fullscr=True,
        color='black',
        units = "pix"
        )

#Initialize our stimuli
hello = visual.TextStim(win=win, text='Hello')
world = visual.TextStim(win=win, text='World')

#Start a loop drawing our message
while True:
    hello.draw()
    drawBlueLine(win, frame=0)
    win.flip()
    world.draw()
    drawBlueLine(win, frame=1)
    win.flip()
    keys = kb.getKeys(keyList=['escape'])
    if keys:
        break
    
win.close()
core.quit()
DPxClose()

‘Blue line’ is the name for historical reasons, but it’s a misnomer. The colour of the line is not important. As long as your pixel values are brighter than mid-grey ([128, 128, 128] in RGB255) it will work as intended.

PsychoPy users: Blue Lines must be drawn with interpolation turned off. Otherwise, the pixel values will blend with the background colour and may not trigger proper polarization.

Quad4x3D Mode

If you are using the Quad4x sequencer, a special command will immediately assign each quadrant to a specific eye. Simply enable the mode and ensure you assign the correct stimuli to each quadrant. This method is robust against de-synchronization by frame dropping, because if a frame is dropped all four quadrants are lost, and the next frame will show content in the correct order.

Time (6).png

In Quad4x3D, quadrants are assigned automatically to each eye.

For more details on Quad4x, see our VOCAL on high-speed projection modes.

MATLAB Example
MATLAB
function helloWorld3DQuad4x()

% Initialize PROPixx
initializePROPixx();

% Initialize Psychtoolbox window
PsychDefaultSetup(2);
screenNumber = max(Screen('Screens'));
[windowPtr] = PsychImaging('OpenWindow', screenNumber, 0);
Screen('BlendFunction', windowPtr, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
HideCursor;

%Initialize quadrants for QUAD4x
quadrants = initializeQuadrants();

% Start drawing loop
while 1
    for quadrantID = fieldnames(quadrants)'
        quadrantID = quadrantID{1};

        % Create text stimulus according to quadrant
        if strcmp(quadrantID, 'Q1') || strcmp(quadrantID, 'Q3')
            text = 'Hello';
        else
            text = 'World';
        end
        
        oldPos = [1920/2, 1080/2]; %center of full screen display
        newPos = assignToQuadrant(oldPos, quadrants.(quadrantID));

        % Draw text & blueline
        Screen('DrawText', windowPtr, text, newPos(1), newPos(2),[255, 255, 255]);
    end
    
    % Flip screen after all four quadrants drawn
    Screen('Flip', windowPtr);

    %Check for escape
    [~, ~, keyCode] = KbCheck;
    if keyCode(KbName('Escape'))
        break;
    end

end

% Close window and cleanup
sca;
closePROPixx();
end

%---- HELPER FUNCTIONS
function quadrants = initializeQuadrants()
  % Define quadrant parameters
  quadrants = struct(...
      'Q1', [0, 0], ...       % Top left
      'Q2', [960, 0], ...   % Top right
      'Q3', [0, 540], ...       % Bottom left
      'Q4', [960, 540] );    % Bottom right
end

function newpos = assignToQuadrant(oldpos, quadrantOffset)
    %Helper function to adjust position to quadrant. 
    newpos = [oldpos(1)/2+quadrantOffset(1), oldpos(2)/2+quadrantOffset(2)];
end

function initializePROPixx()
  % All VPixx hardware commands to set the right mode for the PROPixx
  Datapixx('Open');
  Datapixx('SetPropixxDlpSequenceProgram', 2); 
  Datapixx('RegWr');
  Datapixx('EnablePropixxQuad4x3d');
  Datapixx('RegWr');
end

function closePROPixx()
  % Return to defaults and shut down
  Datapixx('SetPropixxDlpSequenceProgram', 0); 
  Datapixx('DisablePropixxQuad4x3d');
  Datapixx('RegWr');
  Datapixx('Close')
end
Python Example
PY
Coming soon!

Top-Bottom Mode

Top-Bottom mode was introduced in software revision 3.9 (July 2021) and is ideal for stimuli generated in Unity and Unreal game engines. In this mode, left and right images are stacked on top of one another in a single double-height image (1920 x 2160 @ 60 Hz), which the system deconstructs and presents to each eye sequentially (1920 x 1080 @ 120 Hz).

Time (7).png

Top-bottom mode uses a double-height image and shows the left and right eye content sequentially

This mode will be the subject of its own VOCAL, which is currently in preparation. It will be linked here when it is published.

RB3D Mode

RB3D Mode is a custom PROPixx sequencer that VPixx designed in partnership with the NIH. This mode uses the red and blue colour channels to specify right and left eye images, respectively; the system converts these to greyscale images presented to the right and left eye in a single video frame via a custom subframe DLP sequencer. Each frame will show the left image at half-intensity for 1.2 ms, full intensity right image for 2.4 ms, and then the left image for another 1.2 ms at half-intensity. The rest of the frame is blank. This results in the same exposure time for both eyes, and prevents bias of which image is projected first or last.

Time (10).png

Left and right eye information is drawn in blue and red channels on a single frame. The sequencer shows the images in greyscale according to the timeline above.

RB3D mode enables active management of crosstalk levels and actively eliminates Pulfrich effects. Crosstalk is defined by the following formula

Where the default value is 0.

MATLAB Example
MATLAB
function helloWorldRB3D()

% Initialize PROPixx
initializePROPixx();

% Initialize Psychtoolbox window
PsychDefaultSetup(2);
screenNumber = max(Screen('Screens'));
[windowPtr, rect] = PsychImaging('OpenWindow', screenNumber, 0);
HideCursor;

% Initialize stimuli
helloText = 'Hello';
worldText = 'World';

% You can modify the per eye crosstalk here.
Datapixx('SetPropixx3DCrosstalkLR', 0);
Datapixx('SetPropixx3DCrosstalkRL', 0);
Datapixx('RegWr');

% Start loop drawing the message
while true

    %Select red channel while locking others (prevents overwriting colours)
    Screen('BlendFunction', windowPtr, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, [1 0 0 0]);
    DrawFormattedText(windowPtr, helloText, 'center', 'center', [255,0,0]);

    %Select blue channel while locking others (prevents overwriting colours)
    Screen('BlendFunction', windowPtr, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, [0 0 1 0]);
    DrawFormattedText(windowPtr, worldText, 'center', 'center', [0,0,255]);
    Screen('Flip', windowPtr);
    
    [~, ~, keyCode] = KbCheck;
    if keyCode(KbName('Escape'))
        break;
    end
end

% Close the Psychtoolbox window
sca;
closePROPixx();
end

function initializePROPixx()
  % All VPixx hardware commands to set the right mode for the PROPixx
  Datapixx('Open');
  Datapixx('SetPropixxDlpSequenceProgram', 1); 
  Datapixx('RegWr');
end

function closePROPixx()
  % Return to defaults and shut down
  Datapixx('SetPropixxDlpSequenceProgram', 0); 
  Datapixx('RegWr');
  Datapixx('Close');
end
Python Example
PY
Coming soon!

Summary of Different 3D Modes Available with the PROPixx

Description

Maximum Refresh

Best Used For:

Frame-sequential stereo

Temporally interleave left/right eye images

Up to 60 Hz/eye

Simple 3D applications where no frame drops are present

Frame-sequential stereo with Blue Lines

Temporally interleave left/right eye images, blue line used to encode polarization assignment

Up to 240 Hz/eye (in 480 Hz real-time mode)

Any 3D application where video must be robust against frame dropping

Quad4x3D

Four quadrants of display are shown sequentially

240 Hz/eye

High speed displays, robust against frame dropping

Top-Bottom Mode

Left and right eye images stacked in a double-height window; shown sequentially on display

Up to 60 Hz/eye

3D applications where stimuli are created in Unreal or Unity game engines

RB3D Mode

Custom sequencer that presents left and right eye images as greyscale subframes

Up to 120 Hz/eye

Specialized applications where greyscale is appropriate and crosstalk levels are actively controlled

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.