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 151 152 153 154 155 156
|
function ProceduralSmoothedDiscsDemo(ndiscs)
% ProceduralSmoothedDiscsDemo([ndiscs=200]) -- An aquarium full of discs!
%
% This demo shows how to use the Screen('DrawTextures') command to draw a
% large number of similar images quickly - in this case, smooth edged
% discs.
% History:
% 12/12/2017 modified from ProceduralGarboriumDemo (Ian Andolina)
% 24/04/2018 add per-disc alpha parameter to demo (Junxiang Luo & Ian Andolina)
% Setup defaults and unit color range:
PsychDefaultSetup(2);
% Disable synctests for this quick demo:
oldSyncLevel = Screen('Preference', 'SkipSyncTests', 2);
% Set number of gabor patches to 200 if no number provided:
if nargin < 1 || isempty(ndiscs)
ndiscs = 200;
end
fprintf('Will draw %i smoothed aperture discs per frame.\n', ndiscs);
% 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. We need alpha-blending
% here to implement the nice superposition of overlapping of discs. The demo will
% abort if your graphics hardware is not capable of any of this.
PsychImaging('PrepareConfiguration');
PsychImaging('AddTask', 'General', 'FloatingPoint32BitIfPossible');
[win, winRect] = PsychImaging('OpenWindow', screenid, 0.5);
% Retrieve size of window in pixels, need it later to make sure that our
% moving discs don't move out of the visible screen area:
[width, height] = RectSize(winRect);
% Query frame duration: We use it later on to time 'Flips' properly for an
% animation with constant framerate:
ifi = Screen('GetFlipInterval', win);
% Enable alpha-blending
Screen('BlendFunction', win, 'GL_SRC_ALPHA', 'GL_ONE_MINUS_SRC_ALPHA');
% default x + y size
virtualSize = 128;
% radius of the disc edge
radius = virtualSize / 2;
% smoothing sigma in pixel
sigma = 33;
% use alpha channel for smoothing edge of disc?
useAlpha = true;
% smoothing method: cosine (0), smoothstep (1), inverse smoothstep (2)
smoothMethod = 1;
% Build a procedural disc
disctexture = CreateProceduralSmoothedDisc(win, virtualSize, virtualSize, [0 0 0 0], radius, sigma, ...
useAlpha, smoothMethod);
% Preallocate array with destination rectangles:
texrect = Screen('Rect', disctexture);
inrect = repmat(texrect', 1, ndiscs);
dstRects = zeros(4, ndiscs);
scale = zeros(1,ndiscs);
for i=1:ndiscs
scale(i) = 0.5 + 0.5 * abs(randn);
dstRects(:, i) = CenterRectOnPointd(texrect * scale(i), rand * width, rand * height)';
end
% Preallocate array with rotation angles:
rotAngles = rand(1, ndiscs) * 360;
% create random colours for discs
colours = rand(ndiscs,4)';
myAlphas = colours(4,:);
% Initially sync us to VBL at start of animation loop.
count = 0;
vbl = Screen('Flip', win);
tstart = vbl;
% Animation loop: Run until any keypress:
while ~KbCheck
% Step one: Batch-Draw all discs at the positions (dstRects) and
% orientations (rotAngles) and colors (colours)
% and with the stimulus parameters 'discParameters'
Screen('DrawTextures', win, disctexture, [], dstRects, rotAngles, [], [], colours);
% Mark drawing ops as finished, so the GPU can do its drawing job while
% we can compute updated parameters for next animation frame. This
% command is not strictly needed, but it may give a slight additional
% speedup, because the CPU can compute new stimulus parameters in
% Matlab, while the GPU is drawing the stimuli for this frame.
% Sometimes it helps more, sometimes less, or not at all, depending on
% your system and code, but it only seldomly hurts.
% performance...
Screen('DrawingFinished', win);
% Compute updated per disc alpha values and positions for next frame. This code
% is vectorized, but could be probably optimized even more. Indeed,
% these few lines of Matlab code are the main speed-bottleneck for this
% demos animation loop on modern graphics hardware, not the actual drawing
% of the stimulus. The demo as written here is CPU bound - limited in
% speed by the speed of your main processor.
% compute a new per disc alpha
colours(4,:) = (1+sin(myAlphas*100-200 + count*0.05))/2;
% change the direction slightly
rotAngles = rotAngles + 10 * randn(1, ndiscs);
% Compute centers of all patches, then shift them in new direction of
% motion 'rotAngles', use the mod() operator to make sure they don't
% leave the window display area. Its important to use RectCenterd and
% CenterRectOnPointd instead of RectCenter and CenterRectOnPoint,
% because the latter ones would round all results to integral pixel
% locations, which would make for an odd and jerky movement. It is
% also important to feed all matrices and vectors in proper format, as
% these routines are internally vectorized for higher speed.
[x, y] = RectCenterd(dstRects);
x = mod(x + 3.33 * cos(rotAngles/360*2*pi), width);
y = mod(y - 3.33 * sin(rotAngles/360*2*pi), height);
% Recompute dstRects destination rectangles for each patch, given the
% 'per gabor' scale and new center location (x,y):
dstRects = CenterRectOnPointd(inrect .* repmat(scale,4,1), x, y);
% Done. Flip one video refresh after the last 'Flip', ie. try to
% update the display every video refresh cycle if you can.
% This is the same as Screen('Flip', win);
% but the provided explicit 'when' deadline allows PTB's internal
% frame-skip detector to work more accurately and give a more
% meaningful report of missed deadlines at the end of the script. Not
% important for this demo, but here just in case you didn't know ;-)
vbl = Screen('Flip', win, vbl + 0.5 * ifi);
count = count + 1;
end
% A final synced flip, so we can be sure all drawing is finished when we
% reach this point; print some stats
tend = Screen('Flip', win);
avgfps = count / (tend - tstart);
fprintf('\nPresented a total of %i frames at %.2g FPS...\n',count,avgfps);
% Close onscreen window, release all ressources:
sca;
% Restore old settings for sync-tests:
Screen('Preference', 'SkipSyncTests', oldSyncLevel);
|