PROPixx Demo 6 – Drawing in 3D using RB3D mode

Red-Blue 3D mode (RB3D) is a grayscale 3D mode in which we create a 3D stimili using blue color information for the left eye image and the red information for the right eye image.

Note

PROPixx Revision 20 or more is required for using this mode at a lower frame rate than 120 Hz.

This mode can be ran at any refresh rate under or equal to 120 Hz. Each frame will show the left image at half-intensity for 1.2 ms, full intensity right image for 2.4 ms, then the left image for another 1.2 ms at half-intensity. The rest of the frame is blank. This results to the same exposure time for both eyes, and prevents bias of which image is projected first or last.

This demo shows how to generate a basic 3D dot stimuli, identical to other stereo demos included in Psychtoolbox, in RB3D mode. Simply generate the information for your left image in the blue channel and the information of the right image in the red channel.

To set the PROPixx in a different mode, we use a sequencer, Datapixx('SetPropixxDlpSequenceProgram', 1);, the 1 is for RB3D mode, 3 is for setting up 480 Hz stimuli and 5 for 1440 Hz. Select 0 for normal display.

In this mode you also have access to crosstalk correction. This allows you to modify the image to remove part of the other’s eye image to correct the crosstalk effect. The default value of the crosstalk correction (CrosstalkRL and CrosstalkLR) is zero, it follows this formula :

L_{final} = L_{initial} - CrosstalkRL \times R_{initial}

These crosstalk factor can be set using: Datapixx('SetPropixx3DCrosstalkLR', 0); , Datapixx('SetPropixx3DCrosstalkRL', 0); and for setting both to the same value, Datapixx('SetPropixx3DCrosstalk', 0);

At the end of the script, we put back the normal sequencer, Datapixx('SetPropixxDlpSequenceProgram', 0);.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
 function DatapixxImagingStereoDemoRB3D()
%
% Taken from the iconic PTB ImagingStereoDemo,
% slightly modified to drive PROPixx in RB3D mode.
%
% Press any key to exit demo.
%
% Apr 8, 2015  dml     Written

AssertOpenGL;

% Define response key mappings, unify the names of keys across operating
% systems:
KbName('UnifyKeyNames');
space = KbName('space');
escape = KbName('ESCAPE');

% Get the list of Screens and choose the one with the highest screen number.
% Screen 0 is, by definition, the display with the menu bar. Often when
% two monitors are connected the one without the menu bar is used as
% the stimulus display.  Choosing the display with the highest display number is
% a best guess about where you want the stimulus displayed.
scrnNum = max(Screen('Screens'));

% Prepare pipeline for configuration. This marks the start of a list of
% requirements/tasks to be met/executed in the pipeline:
PsychImaging('PrepareConfiguration');

% Tell PTB we want to display on a DataPixx device:
PsychImaging('AddTask', 'General', 'UseDataPixx');

% Enable PROPixx RB3D Sequencer
Datapixx('Open');
Datapixx('SetPropixxDlpSequenceProgram', 1);
Datapixx('RegWr');

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

% Open the window
[windowPtr, windowRect]=PsychImaging('OpenWindow', scrnNum, 0);

% Stimulus settings:
numDots = 1000;
vel = 1;   % pix/frames
dotSize = 8;
dots = zeros(3, numDots);

xmax = RectWidth(windowRect)/2;
ymax = RectHeight(windowRect)/2;
xmax = min(xmax, ymax) / 2;
ymax = xmax;

f = 4*pi/xmax;
amp = 16;

dots(1, :) = 2*(xmax)*rand(1, numDots) - xmax;
dots(2, :) = 2*(ymax)*rand(1, numDots) - ymax;

% Initially fill left- and right-eye image buffer with black background
% color:
Screen('FillRect', windowPtr, BlackIndex(scrnNum));
Screen('Flip', windowPtr);


% Set up alpha-blending for smooth (anti-aliased) drawing of dots:
% However, this mode requires blending of the function, use the 2nd one
% instead:
%Screen('BlendFunction', windowPtr, 'GL_SRC_ALPHA', 'GL_ONE_MINUS_SRC_ALPHA');
Screen('BlendFunction', windowPtr, 'GL_SRC_ALPHA', 'GL_DST_ALPHA'); 

col1 = [255 0 0];
col2 = [0 0 255];
i = 1;
keyIsDown = 0;
center = [0 0];
sigma = 50;
xvel = 2*vel*rand(1,1)-vel;
yvel = 2*vel*rand(1,1)-vel;

Screen('Flip', windowPtr);

% Maximum number of animation frames to show:
nmax = 100000;

% Perform a flip to sync us to vbl and take start-timestamp in t:
t = Screen('Flip', windowPtr);

% Run until a key is pressed:
while length(t) < nmax

        % Select left-eye image buffer for drawing:

    % Draw left stim:
    Screen('DrawDots', windowPtr, dots(1:2, :) + [dots(3, :)/2; zeros(1, numDots)], dotSize, col1, [windowRect(3:4)/2], 1);

    % Draw right stim:
    Screen('DrawDots', windowPtr, dots(1:2, :) - [dots(3, :)/2; zeros(1, numDots)], dotSize, col2, [windowRect(3:4)/2], 1);
    
    % Draw borders
    Screen('FrameRect', windowPtr, [255 0 255], [], 15);
    Screen('FrameRect', windowPtr, [255 0 0], [], 10);
    Screen('FrameRect', windowPtr, [0 0 255], [], 5);
    
    % Flip stim to display and take timestamp of stimulus-onset after
    % displaying the new stimulus and record it in vector t:
    onset = Screen('Flip', windowPtr);
    t = [t onset];

    % Now all non-drawing tasks:

    % Compute dot positions and offsets for next frame:
    center = center + [xvel yvel];
    if center(1) > xmax | center(1) < -xmax
        xvel = -xvel;
    end

    if center(2) > ymax | center(2) < -ymax
        yvel = -yvel;
    end

    dots(3, :) = -amp.*exp(-(dots(1, :) - center(1)).^2 / (2*sigma*sigma)).*exp(-(dots(2, :) - center(2)).^2 / (2*sigma*sigma));

    % Keypress ends demo
    [pressed dummy keycode] = KbCheck;
    if pressed
        break;
    end
end 

% Last Flip:
Screen('Flip', windowPtr);

% Set the PROPixx back to normal sequencer
Datapixx('SetPropixxDlpSequenceProgram', 0);
Datapixx('RegWrRd');

% Done. Close the onscreen window:
Screen('CloseAll')
Datapixx('Close');

% Compute and show timing statistics:
dt = t(2:end) - t(1:end-1);
disp(sprintf('N.Dots\tMean (s)\tMax (s)\t%%>20ms\t%%>30ms\n'));
disp(sprintf('%d\t%5.3f\t%5.3f\t%5.2f\t%5.2f\n', numDots, mean(dt), max(dt), sum(dt > 0.020)/length(dt), sum(dt > 0.030)/length(dt)));

% We're done.
return;