在显示移动光栅之前预渲染帧

时间:2013-01-29 19:11:58

标签: matlab frame psychtoolbox

我正在使用来自Psychtool盒子的DemoDrift2创建一个移动光栅。光栅移动完美,效果很好。但是,我需要将其与其他一些设备连接并与其他软件一起使用。在这些情况下,光栅显示得更慢并且摇晃。如何在显示光栅之前预渲染帧?

function DriftDemo2(angle, cyclespersecond, f, drawmask, gratingsize)
% function DriftDemo2([angle=30][, cyclespersecond=1][, f=0.05][, drawmask=1],[gratingsize=400])


if nargin < 5
gratingsize = [];
end

if isempty(gratingsize)
% By default the visible grating is 400 pixels by 400 pixels in size:
gratingsize = 400;
end

if nargin < 4
drawmask = [];
end

if isempty(drawmask)
% By default, we mask the grating by a gaussian transparency mask:
drawmask=1;
end;

if nargin < 3
f = [];
end

if isempty(f)
% Grating cycles/pixel: By default 0.05 cycles per pixel.
f=0.05;
end;

if nargin < 2
cyclespersecond = [];
end

if isempty(cyclespersecond)
% Speed of grating in cycles per second: 1 cycle per second by default.
cyclespersecond=1;
end;

if nargin < 1
angle = [];
end

if isempty(angle)
% Angle of the grating: We default to 30 degrees.
angle=30;
end;

movieDurationSecs=20;   % Abort demo after 20 seconds.

% Define Half-Size of the grating image.
texsize=gratingsize / 2;

% Screen('Preference', 'SkipSyncTests', 1);

try
% This script calls Psychtoolbox commands available only in OpenGL-based 
% versions of the Psychtoolbox. 
AssertOpenGL;

% Get the list of screens and choose the one with the highest screen number.
screens=Screen('Screens');
screenNumber=max(screens);

% Find the color values which correspond to white and black:
% functions WhiteIndex and BlackIndex:
white=WhiteIndex(screenNumber);
black=BlackIndex(screenNumber);

% Round gray to integral number, to avoid roundoff artifacts with some
% graphics cards:
gray=round((white+black)/2);

% This makes sure that on floating point framebuffers we still get a
% well defined gray:
if gray == white
    gray=white / 2;
end

% Contrast 'inc'rement range for given white and gray values:
inc=white-gray;

% Open a double buffered fullscreen window and set default background
% color to gray:
[w screenRect]=Screen('OpenWindow',screenNumber, gray);

if drawmask
    % Enable alpha blending for proper combination of the gaussian aperture
    % with the drifting sine grating:
    Screen('BlendFunction', w, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
end

% Calculate parameters of the grating:


p=ceil(1/f);

% frequency in radians:
fr=f*2*pi;

% This is the visible size of the grating. It is twice the half-width
% of the texture plus one pixel to make sure it has an odd number of
% pixels and is therefore symmetric around the center of the texture:
visiblesize=2*texsize+1;

% Create one single static grating image:
%
% We only need a texture with a single row of pixels(i.e. 1 pixel in height) to
% define the whole grating! If the 'srcRect' in the 'Drawtexture' call
% below is "higher" than that (i.e. visibleSize >> 1), the GPU will
% automatically replicate pixel rows. This 1 pixel height saves memory
% and memory bandwith, ie. it is potentially faster on some GPUs.
%
% However it does need 2 * texsize + p columns, i.e. the visible size
% of the grating extended by the length of 1 period (repetition) of the
% sine-wave in pixels 'p':
x = meshgrid(-texsize:texsize + p, 1);

% Compute actual cosine grating:
grating=gray + inc*cos(fr*x);

% Store 1-D single row grating in texture:
gratingtex=Screen('MakeTexture', w, grating);

% Create a single gaussian transparency mask and store it to a texture:
% The mask must have the same size as the visible size of the grating
% to fully cover it. Here we must define it in 2 dimensions and can't
% get easily away with one single row of pixels.
%
% We create a  two-layer texture: One unused luminance channel which we
% just fill with the same color as the background color of the screen
% 'gray'. The transparency (aka alpha) channel is filled with a
% gaussian (exp()) aperture mask:
mask=ones(2*texsize+1, 2*texsize+1, 2) * gray;
[x,y]=meshgrid(-1*texsize:1*texsize,-1*texsize:1*texsize);
mask(:, :, 2)=white * (1 - exp(-((x/90).^2)-((y/90).^2)));
masktex=Screen('MakeTexture', w, mask);

% Query maximum useable priorityLevel on this system:
priorityLevel=MaxPriority(w); %#ok<NASGU>

% We don't use Priority() in order to not accidentally overload older
% machines that can't handle a redraw every 40 ms. If your machine is
% fast enough, uncomment this to get more accurate timing.
%Priority(priorityLevel);

% Definition of the drawn rectangle on the screen:
% Compute it to  be the visible size of the grating, centered on the
% screen:
dstRect=[0 0 visiblesize visiblesize];
dstRect=CenterRect(dstRect, screenRect);

% Query duration of one monitor refresh interval:
ifi=Screen('GetFlipInterval', w);

% Translate that into the amount of seconds to wait between screen
% redraws/updates:

% waitframes = 1 means: Redraw every monitor refresh. If your GPU is
% not fast enough to do this, you can increment this to only redraw
% every n'th refresh. All animation paramters will adapt to still
% provide the proper grating. However, if you have a fine grating
% drifting at a high speed, the refresh rate must exceed that
% "effective" grating speed to avoid aliasing artifacts in time, i.e.,
% to make sure to satisfy the constraints of the sampling theorem
% (See Wikipedia: "Nyquist?Shannon sampling theorem" for a starter, if
% you don't know what this means):
waitframes = 1;

% Translate frames into seconds for screen update interval:
waitduration = waitframes * ifi;

% Recompute p, this time without the ceil() operation from above.
% Otherwise we will get wrong drift speed due to rounding errors!
p=1/f;  % pixels/cycle    

% Translate requested speed of the grating (in cycles per second) into
% a shift value in "pixels per frame", for given waitduration: This is
% the amount of pixels to shift our srcRect "aperture" in horizontal
% directionat each redraw:
shiftperframe= cyclespersecond * p * waitduration;

% Perform initial Flip to sync us to the VBL and for getting an initial
% VBL-Timestamp as timing baseline for our redraw loop:
vbl=Screen('Flip', w);

% We run at most 'movieDurationSecs' seconds if user doesn't abort via keypress.
vblendtime = vbl + movieDurationSecs;
i=0;

% Animationloop:
while(vbl < vblendtime)

    % Shift the grating by "shiftperframe" pixels per frame:
    % the mod'ulo operation makes sure that our "aperture" will snap
    % back to the beginning of the grating, once the border is reached.
    % Fractional values of 'xoffset' are fine here. The GPU will
    % perform proper interpolation of color values in the grating
    % texture image to draw a grating that corresponds as closely as
    % technical possible to that fractional 'xoffset'. GPU's use
    % bilinear interpolation whose accuracy depends on the GPU at hand.
    % Consumer ATI hardware usually resolves 1/64 of a pixel, whereas
    % consumer NVidia hardware usually resolves 1/256 of a pixel. You
    % can run the script "DriftTexturePrecisionTest" to test your
    % hardware...
    xoffset = mod(i*shiftperframe,p);
    i=i+1;

    % Define shifted srcRect that cuts out the properly shifted rectangular
    % area from the texture: We cut out the range 0 to visiblesize in
    % the vertical direction although the texture is only 1 pixel in
    % height! This works because the hardware will automatically
    % replicate pixels in one dimension if we exceed the real borders
    % of the stored texture. This allows us to save storage space here,
    % as our 2-D grating is essentially only defined in 1-D:
    srcRect=[xoffset 0 xoffset + visiblesize visiblesize];

    % Draw grating texture, rotated by "angle":
    Screen('DrawTexture', w, gratingtex, srcRect, dstRect, angle);

    if drawmask==1
        % Draw gaussian mask over grating:
        Screen('DrawTexture', w, masktex, [0 0 visiblesize visiblesize], dstRect, angle);
    end;

    % Flip 'waitframes' monitor refresh intervals after last redraw.
    % Providing this 'when' timestamp allows for optimal timing
    % precision in stimulus onset, a stable animation framerate and at
    % the same time allows the built-in "skipped frames" detector to
    % work optimally and report skipped frames due to hardware
    % overload:
    vbl = Screen('Flip', w, vbl + (waitframes - 0.5) * ifi);

    % Abort demo if any key is pressed:
    if KbCheck
        break;
    end;
end;

% Restore normal priority scheduling in case something else was set
% before:
Priority(0);

%The same commands wich close onscreen and offscreen windows also close
%textures.
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 %try..catch..enter code here

感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

预渲染是通过调用owpnt = Screen('OpenOffscreenWindow',...)然后发出常规绘图命令完成的,但是将owpnt作为目标传递。然后将它们写入纹理,您可以使用Screen('DrawTexture')显示。

每帧需要一个屏幕外窗口。这将很快耗尽您的视频卡的内存。所以:

  1. 确保屏幕外窗口的尺寸尽可能小:使其适合您的光栅
  2. 屏幕('关闭')asap
  3. 不需要的屏幕外窗口