Skip to content

Instantly share code, notes, and snippets.

@smithdanielle
Last active August 29, 2015 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smithdanielle/967b3e31b6daf3502e82 to your computer and use it in GitHub Desktop.
Save smithdanielle/967b3e31b6daf3502e82 to your computer and use it in GitHub Desktop.
Drawing dots using PTB3's `CreateProceduralGabor`
% gaborDotsMinimal.m
% An example of how to draw dots using PTB3's `CreateProceduralGabor`
sca;
try
% PTB-3 correctly installed and functional? Abort otherwise.
AssertOpenGL;
% Select screen with maximum id for output window:
screenid = max(Screen('Screens'));
% Open a fullscreen, onscreen window with gray background. Enable 32bpc
% floating point framebuffer via imaging pipeline on it, if this is possible
% on your hardware while alpha-blending is enabled. Otherwise use a 16bpc
% precision framebuffer together with alpha-blending.
PsychImaging('PrepareConfiguration');
PsychImaging('AddTask', 'General', 'FloatingPoint32BitIfPossible');
[win winRect] = PsychImaging('OpenWindow', screenid, 128);
% Find center of screen:
xcen = winRect(3)/2;
ycen = winRect(4)/2;
% Enable alpha-blending, set it to a blend equation useable for linear
% superposition with alpha-weighted source.
Screen('BlendFunction', win, GL_SRC_ALPHA, GL_ONE);
% Stimulus parameters
dot.size = 35; %0.0583; %0.01416; % size of dot
dot.area = [1138 1138]; % 2 degrees x 2 degrees, replication of Gantz & Bedell (2011)
dot.number = 581; % number of background dots
dot.center = [0 0];
% Initial parameters of gabors:
gabor.phase = 90; % phase of underlying sine grating in degrees
gabor.sigma = 7; %1.75; % sigma of gaussian
gabor.freq = .00005*2*pi; % frequency of grating
gabor.contrast = 5.0; % contrast of grating
gabor.aspectratio = 1.0;
% Parameters of line stimuli
line.initial.size = [8 105]; % initial dimensions of line
line.center = [0 0];
line.phase = 90; % white line
line.sigma = 7; %1.75;
line.freq = .00005*2*pi;
line.contrast = 5.0;
line.aspectratio = line.initial.size(1)/line.initial.size(2);
% Initialize matrix with spec for all dots; everything identical except for
% randomising dot colour by changing phase of underlying grating
gabor.allParameters = repmat([gabor.freq, gabor.sigma, gabor.contrast, gabor.aspectratio, 0, 0, 0]', 1, dot.number);
gabor.allParameters = vertcat(RandSample([90 270],[1 dot.number]), gabor.allParameters);
% Create Gaussian-filtered image matrix for the line
line.matrix.initial = (ones(line.initial.size(2)+ceil(3*line.sigma), line.initial.size(1)+ceil(3*line.sigma)))-0.5;
line.matrix.initial(12:116, 11:19) = 1;
% Apply gaussian filter to matrix
h = fspecial('gaussian',[1,2*ceil(3*line.sigma)+1],line.sigma);
line.matrix.gauss = conv2(h,h,line.matrix.initial,'same');
% Normalise filtered matrix
m = min(line.matrix.gauss(:));
range = max(line.matrix.gauss(:)) - m;
line.matrix.gauss = (line.matrix.gauss - m) ./ range;
% Then scale to [x,y]:
rangeXY = 1 - 0.5;
line.matrix.norm = (line.matrix.gauss*rangeXY) + 0.5;
% Build a procedural gabor texture for a single dot. The 'nonsymetric' flag set
% to 1 == Gabor shall allow runtime change of aspect-ratio:
gausstex = CreateProceduralGabor(win, 35, 35, 1, [0.5 0.5 0.5 0]);
% Build a gaussian-enveloped line texture:
linetex = Screen('MakeTexture', win, line.matrix.norm, [], [], 2);
% Preallocate array with destination rectangles:
% This also defines initial gabor patch orientations, scales and location
% for the very first drawn stimulus frame:
texrect = Screen('Rect', gausstex);
inrect = repmat(texrect', 1, dot.number);
linerect = Screen('Rect', linetex);
[dot.X,dot.Y] = meshgrid(xcen-0.5*dot.area(1):1.2*dot.size:xcen + 0.5*dot.area(1), ycen-0.5*dot.area(2):1.2*dot.size:ycen + 0.5*dot.area(2));
numElements = numel(dot.X);
% Jitter stimuli
dot.jX = jitter(dot.X, 0.75,1); % jitter the dots using a normal distribution
dot.jY = jitter(dot.Y, 0.75,1); % with magnitude of 15% of smallest dot-to-dot spacing
% Place stimuli
indicesOfAllPoints = randperm(numElements);
dot.dstRects.test = zeros(4, dot.number);
dot.dstRects.test = CenterRectOnPoint(texrect, dot.jX(indicesOfAllPoints(1:dot.number))', dot.jY(indicesOfAllPoints(1:dot.number))')';
line.dstRect.test = zeros(4,1);
line.dstRect.test = CenterRectOnPoint(linerect, xcen, ycen);
% Initially sync us to VBL at start of animation loop.
vbl = Screen('Flip', win);
tstart = vbl;
while ~KbCheck
Screen('DrawTextures', win, gausstex, [], dot.dstRects.test, [], [], [], [], [], kPsychDontDoRotation, gabor.allParameters);
Screen('DrawTexture', win, linetex, [], line.dstRect.test, [], [], [], [], [], kPsychDontDoRotation, [line.phase, line.freq, line.sigma, line.contrast, line.aspectratio, 0, 0, 0]);
vbl = Screen('Flip', win);
end
Priority(0);
% Close all textures. This is not strictly needed, as
% Screen('CloseAll') would do it anyway. However, it avoids warnings by
% Psychtoolbox about unclosed textures. The warnings trigger if more
% than 10 textures are open at invocation of Screen('CloseAll') and we
% have 12 textues here:
Screen('Close');
% Close window:
Screen('CloseAll');
catch
%this "catch" section executes in case of an error in the "try" section
%above. Importantly, it closes the onscreen window if its open.
Screen('CloseAll');
Priority(0);
psychrethrow(psychlasterror);
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment