Last active
August 29, 2015 14:09
-
-
Save smithdanielle/967b3e31b6daf3502e82 to your computer and use it in GitHub Desktop.
Drawing dots using PTB3's `CreateProceduralGabor`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% 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