I’m not really sure what the problem is. First I confirmed that the gratings look good on my MacBook Pro (OS 10.12.6)-driven CRT (gamma = 2.24). They do (see exhibit 1). Then I ran exactly the same code (exhibit 2, adapted from AdditiveBlendingForLinearSuperpositionTutorial) on a new PC with built-in display “HP 800 G3 AiO” (gamma = 2.27). To see the artifacts, you’ll need to zoom into exhibit 3. Is this an inescapable hardware issue? Or is it a problem with PTB?
function debugPseudoGray
KbName('UnifyKeyNames');
UpArrow = KbName('UpArrow');
DownArrow = KbName('DownArrow');
LeftArrow = KbName('LeftArrow');
RightArrow = KbName('RightArrow');
esc = KbName('ESCAPE');
space = KbName('space');
GammaIncrease = KbName('i');
GammaDecrease = KbName('d');
try
% This script calls Psychtoolbox commands available only in OpenGL-based
% versions of the Psychtoolbox. The Psychtoolbox command AssertPsychOpenGL will issue
% an error message if someone tries to execute this script on a computer without
% an OpenGL Psychtoolbox
AssertOpenGL;
% 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. Chosing the display with the highest dislay number is
% a best guess about where you want the stimulus displayed.
screenNumber = max(Screen('Screens'));
% Open a double-buffered fullscreen window with a gray (intensity =
% 0.5) background and support for 16- or 32 bpc floating point framebuffers.
PsychImaging('PrepareConfiguration');
lrect = [];
% This will try to get 32 bpc float precision if the hardware supports
% simultaneous use of 32 bpc float and alpha-blending. Otherwise it
% will use a 16 bpc floating point framebuffer for drawing and
% alpha-blending, but a 32 bpc buffer for gamma correction and final
% display. The effective stimulus precision is reduced from 23 bits to
% about 11 bits when a 16 bpc float buffer must be used instead of a 32
% bpc float buffer:
PsychImaging('AddTask', 'General', 'FloatingPoint32BitIfPossible');
PsychImaging('AddTask', 'General', 'EnablePseudoGrayOutput');
PsychImaging('AddTask', 'FinalFormatting', 'DisplayColorCorrection', 'SimpleGamma');
doTheGamma =1;
%PsychImaging('AddTask', 'General', 'InterleavedLineStereo', 0);
% Finally open a window according to the specs given with above
% PsychImaging calls, clear it to a background color of 0.5 aka 50%
% luminance:
[w, wRect]=PsychImaging('OpenWindow', screenNumber, 0.5, lrect);
gamma = 1 / 2.0;
PsychColorCorrection('SetEncodingGamma', w, gamma);
% From here on, all color values should be specified in the range 0.0
% to 1.0 for displayable luminance values. Values outside that range
% are allowed as intermediate results, but the final stimulus image
% should be in range 0-1, otherwise result will be undefined.
[width, height]=Screen('WindowSize', w);
% Enable alpha blending. We switch it into additive mode which takes
% source alpha into account:
Screen('BlendFunction', w, GL_SRC_ALPHA, GL_ONE);
inc=0.25;
s=200;
[x,y]=meshgrid(-s:s-1, -s:s-1);
angle=0*pi/180; % 30 deg orientation.
f=2*p/16; % cycles/pixel
a=cos(angle)*f;
b=sin(angle)*f;
% Build grating texture:
m=sin(a*x+b*y);
tex=Screen('MakeTexture', w, m,[],[], 2);
% Show the gray background:
Screen('Flip', w);
i=0;
rotate = 0;
yd =0;
show2nd = 1;
Screen('TextSize', w, 18);
% Center mouse on stimulus display, then make mouse cursor invisible:
[cx, cy] = RectCenter(wRect);
SetMouse(cx, cy, w);
HideCursor(screenNumber);
framecount = 0;
tstart = GetSecs;
% Animation loop:
while 1
Screen('DrawTexture', w, tex, [], [], [], [], 0.25);
i=i+rotate;
[x,y,buttons]=GetMouse(w);
[x,y] = RemapMouse(w, 'AllViews', x, y);
if any(buttons)
if buttons(1)
i=i+0.1;
end
if buttons(2)
i=i-0.1;
end
end
if show2nd
dstRect=CenterRectOnPoint(Screen('Rect', tex), x, y+yd);
Screen('DrawTexture', w, tex, [], dstRect, i, [], inc);
end
[d1, d2, keycode]=KbCheck; %#ok<*ASGLU>
if d1
if keycode(UpArrow)
yd=yd-0.1;
end
if keycode(DownArrow)
yd=yd+0.1;
end
if keycode(LeftArrow) && inc >= 0.001
inc=inc-0.001;
end
if keycode(RightArrow) && inc <= 0.999
inc=inc+0.001;
end
% Change of encoding gamma?
if keycode(GammaIncrease) && doTheGamma
gamma = min(gamma+0.001, 1.0);
PsychColorCorrection('SetEncodingGamma', w, gamma);
end
if keycode(GammaDecrease) && doTheGamma
gamma = max(gamma-0.001, 0.0);
PsychColorCorrection('SetEncodingGamma', w, gamma);
end
if keycode(space)
show2nd = 1-show2nd;
KbReleaseWait;
if show2nd
HideCursor(screenNumber);
else
ShowCursor(screenNumber);
end
end
if keycode(esc)
break;
end
end
txt0= 'At startup:\ngrating = sin(f*cos(angle)*x + f*sin(angle)*y); % Compute luminance grating matrix in Matlab.\n';
txt1= 'tex = Screen(''MakeTexture'', win, grating, [], [], 2); % Convert it into a 32bpc floating point texture.\n';
txt2= 'Screen(''BlendFunction'', win, GL_SRC_ALPHA, GL_ONE); % Enable additive alpha-blending.\n\nIn Display loop:\n\n';
txt3= 'Screen(''DrawTexture'', win, tex, [], [], [], [], 0.25); % Draw static grating at center of screen.\n';
txt4 = sprintf('Screen(''DrawTexture'', win, tex, [], [%i %i %i %i], %f, [], %f);\n', dstRect(1), dstRect(2), dstRect(3), dstRect(4), i, inc);
txt5 = sprintf('\nEncoding Gamma is %f --> Correction for a %f gamma display.', gamma, 1/gamma);
DrawFormattedText(w, [txt0 txt1 txt2 txt3 txt4 txt5], 0, 20, 1.0);
framecount = framecount + 1;
% For the fun of it: Set a specific scanline to send a trigger
% signal for the VideoSwitcher. This does nothing if the driver for
% VideoSwitcher is not selected. We send out a trigger for 1 redraw
% cycle every 30 redraw cycles. The triggerline is placed at
% scanline 10 (for no special reason):
if mod(framecount, 30) == 0
PsychVideoSwitcher('SetTrigger', w, 10, 1);
end
% Show stimulus at next display retrace:
Screen('Flip', w);
end
% Done.
avgfps = framecount / (GetSecs - tstart);
fprintf('Average redraw rate in demo was %f Hz.\n', avgfps);
% Again, just to test conversion speed: A fast benchmark with sync of
% buffer swaps to retrace disabled -- Go as fast as you can!
nmaxbench = 300;
tstart = Screen('Flip', w);
for i=1:nmaxbench
Screen('Flip', w, 0, 2, 2);
end
tend = Screen('Flip', w);
fprintf('Average update rate in pipeline was %f Hz.\n', nmaxbench / (tend - tstart));
Screen('Preference','TextAntiAliasing', 1);
% We're done: Close all windows and textures:
sca;
catch %#ok<*CTCH>
%this "catch" section executes in case of an error in the "try" section
%above. Importantly, it closes the onscreen window if its open.
ShowCursor(screenNumber);
sca;
Screen('Preference','TextAntiAliasing', 1);
psychrethrow(psychlasterror);
end %try..catch..
% Restore gfx gammatables if needed:
RestoreCluts;
return;