オフスクリーンウィンドウ

複雑な刺激(例えば幾何学的な模様が入り乱れているような)を使う場合、各試行で呈示する直前で描画を行っていると、そこで時間のロスが生じる可能性があります。それを防止するため、使用する刺激をあらかじめオフスクリーンウィンドウ(テクスチャ)に描画しておく方法があります。試行が始まると、事前に描画しておいたオフスクリーンウィンドウを画面に呈示するだけなので、時間のロスを抑えることができます。

Screen('OpenOffscreenWindow') も参照してください。

またデモのMullerLyerIllusionのなかにも、

    %         %an example of preparing an offScreenwindow (for repeated use and fast drawing)
    %         [fixcross,rect2]=Screen('OpenOffscreenWindow',screenNumber,[],[0 0 20 20]);
    %         Screen('drawline',fixcross,[0 0 0],10,0,10,20,2);%mx-10,my,mx+10,my
    %         Screen('drawline',fixcross,[0 0 0],0,10,20,10,2);%mx,my-10,mx,my+10

のように、オフスクリーンウィンドウの使用方法について記載があります。

Screen('MakeTexture') を使用してもよいのですが、刺激によっては行列を作るのが難しい場合があると思います(例えば円を描画するときなど)。もしくはアンチエイリアシングを行いたい場合も(おそらく)MakeTextureを使うのは難しいと思います。

少し話がそれますが描画速度に興味のあるかたは、/Applications/Psychtoolbox/PsychTests/ にある DrawingSpeedTest もご覧ください。

私の環境だとprimitivetypeとmodeの組み合わせによって、最適な描画方法が異なりますが、基本的にはmode=1(複数の座標を事前に指定しておき、for文などの繰り返しを使わない方法)で問題のない速度で描画ができています。

かなり複雑な刺激の描画でない限りは、mode=1 の方法でよさそうです。オフスクリーンウィンドウを使う場合より、シンプルなコードになります。

以下にオフスクリーンウィンドウを使ったサンプルプログラムを記します。

3秒ごとにオフスクリーンウィンドウを切り替えています。

最後の刺激はアンチエイリアシングの動作確認です。

function offscreenTest
% 刺激を呈示する前にオフスクリーン(テクスチャ)に刺激を描画しておくことにより
% 時間のロスをなくす方法
%
ListenChar(2);
AssertOpenGL;
WaitSecs(0.1);
%OSで共通のキー配置にする
KbName('UnifyKeyNames');
%手作りfunction。必要に応じてコメントアウトしてください。
%myKeyCheck;
try
  bgColor = [128 128 128]; % 画面全体の背景色
  bgColor2 = [0 0 0]; % 四角形領域の背景色
 
  screenNumber=max(Screen('Screens'))
 
  %ウィンドウでの呈示
  %[windowPtr, windowRect]=Screen('OpenWindow', screenNumber, bgColor, [100, 200, 800, 600]);
  %フルスクリーンでの呈示
  [windowPtr, windowRect]=Screen('OpenWindow', screenNumber, bgColor);
   
  OvalColor = [255 255 255]; % 円の色
  StimRect = [0 0 200 200]; % Stimulus Rect 円を描画する四角形領域
  [centerX centerY] = RectCenter(StimRect); % 四角形の中心座標
 
  radius = 20; % 円の半径
  dist = 50; % 円と円のあいだの距離
 
  %-----------------------------------
  % オフスクリーン(テクスチャ)の作成 (このサンプルでは4つのオフスクリーンを作成しています)
  % オフスクリーン1:中心に1つの円
  OvalTex1 = Screen('OpenOffscreenWindow', screenNumber, bgColor2, StimRect);
  Screen('FillOval', OvalTex1, OvalColor, [centerX - radius, centerY - radius, centerX + radius, centerY + radius]);
 
  % オフスクリーン2:水平に並んだ2つの円
  OvalTex2 = Screen('OpenOffscreenWindow', screenNumber, bgColor2, StimRect);
  Screen('FillOval', OvalTex2, OvalColor, [centerX - radius, centerY - radius, centerX + radius, centerY + radius]);
  Screen('FillOval', OvalTex2, OvalColor, [centerX - radius - dist, centerY - radius, centerX + radius - dist, centerY + radius]);
  % オフスクリーン3:水平に並んだ3つの円
  OvalTex3 = Screen('OpenOffscreenWindow', screenNumber, bgColor2, StimRect);
  Screen('FillOval', OvalTex3, OvalColor, [centerX - radius, centerY - radius, centerX + radius, centerY + radius]);
  Screen('FillOval', OvalTex3, OvalColor, [centerX - radius - dist, centerY - radius, centerX + radius - dist, centerY + radius]);
  Screen('FillOval', OvalTex3, OvalColor, [centerX - radius + dist, centerY - radius, centerX + radius + dist, centerY + radius]);
 
  % オフスクリーン4:斜めの2本の線分
  % アンチエイリアシングの確認
  LineTex = Screen('OpenOffscreenWindow', screenNumber, bgColor2, StimRect);
  Screen(LineTex,'BlendFunction',GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); % アンチエイリアシングを有効に
  Screen('DrawLines', LineTex, [20, 150; 20, 40], 2, OvalColor, [], 0); % アンチエイリアシングなしの線分
  Screen('DrawLines', LineTex, [20, 150; 60, 80], 2, OvalColor, [], 1); % アンチエイリアシングありの線分
 
 
  % 呈示の開始
  Screen('DrawTexture', windowPtr, OvalTex1);
  Screen('Flip', windowPtr);
  WaitSecs(3);
 
  Screen('DrawTexture', windowPtr, OvalTex2);
  Screen('Flip', windowPtr);
  WaitSecs(3);
 
  Screen('DrawTexture', windowPtr, OvalTex3);
  Screen('Flip', windowPtr);
 
  WaitSecs(3);
  Screen('DrawTexture', windowPtr, LineTex);
  Screen('Flip', windowPtr);
 
  KbWait;
 
  %終了処理
  Screen('CloseAll');
  ShowCursor;
  ListenChar(0);
 
catch
  Screen('CloseAll');
  ShowCursor;
  ListenChar(0);
  psychrethrow(psychlasterror);
end