OpenGL関数で三次元図形を描く

最初に、MinimalisticOpenGLDemo を見たことがない方は、先にそちらをご覧ください。

ここでは、GLUTによる「手抜き」OpenGL入門「三次元図形を描く」で解説されている内容をPTBのプログラムの中で行う方法について解説します。またPTBとどのように連動させるのかに重きを置いているので、OpenGLに関する詳細な説明はリンク元をご覧ください。

y軸を中心に25度回転(回転というよりは水平方向の幅が狭まったように見えます)

clear all;
AssertOpenGL;
ListenChar(2);
bgColor = [128 128 128]; % 背景色
screenWidth = 500; % OpenGLで描画する領域(正方形)の幅。
screenNumber=max(Screen('Screens'));
InitializeMatlabOpenGL;
try
    [windowPtr, windowRect] = Screen('OpenWindow', screenNumber, bgColor);
    % スクリーンの中心座標
    [centerPos(1), centerPos(2)] = RectCenter(windowRect);
    
    % OpenGL関数で描画する領域
    myRect = CenterRectOnPoint([0 0 screenWidth screenWidth], centerPos(1), centerPos(2));
    
    % OpenGL関数を使い始めるという宣言
    Screen('BeginOpenGL', windowPtr);
    % PTBの座標系では画面の左上が原点だが、OpenGLでは画面の左下が原点であることに注意。
    glViewport(myRect(1), myRect(2), screenWidth, screenWidth);
    
    glMatrixMode(GL.PROJECTION); % アンダーバーがドットになっていることに注意。
    glLoadIdentity;
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
    glClearColor(1,1,1,1); % 背景色
    glClear;
    
    glRotated(25.0, 0.0, 1.0, 0.0);
    glBegin(GL.POLYGON); % アンダーバーがドットになっていることに注意。
    glColor3d(1.0, 0.0, 0.0); % 赤
    glVertex2d(-0.9, -0.9);
    glColor3d(0.0, 1.0, 0.0); % 緑
    glVertex2d(0.9, -0.9);
    glColor3d(0.0, 0.0, 1.0); % 青
    glVertex2d(0.9, 0.9);
    glColor3ub(255, 255, 0); % 黄色(0から255の値で指定したいときは、glColor3ubを使います)
    glVertex2d(-0.9, 0.9);
    glEnd();
    % OpenGL関数の使用を終わります。
    Screen('EndOpenGL', windowPtr);
    % この段階で、PTBの機能を使って図形を描画することも可能です。
    Screen('FillRect', windowPtr, [255 0 0], [200 300 400 400]);
    
    Screen('Flip', windowPtr);
    KbWait;
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
catch
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
    psychrethrow(psychlasterror);
end

線画を表示する。

clear all;
AssertOpenGL;
ListenChar(2);
bgColor = [128 128 128]; % 背景色
screenWidth = 500; % OpenGLで描画する領域(正方形)の幅。
screenNumber=max(Screen('Screens'));
InitializeMatlabOpenGL;
% 頂点の情報
vertex = [
    0, 0, 0 % A (1)
    1, 0, 0 % B (2)
    1, 1, 0 % C (3)
    0, 1, 0 % D (4)
    0, 0, 1 % E (5)
    1, 0, 1 % F (6)
    1, 1, 1 % G (7)
    0, 1, 1 % H (8)
    ];
% 2つの頂点を結ぶ線分の情報
% MATLABでは行列の参照が0からではなく、1からであることに注意。
edge = [
    1, 2 % ア(A-B)
    2, 3 % イ(B-C)
    3, 4 % ウ(C-D)
    4, 1 % エ(D-A)
    5, 6 % オ(E-F)
    6, 7 % カ(F-G)
    7, 8 % キ(G-H)
    8, 5 % ク(H-E)
    1, 5 % ケ(A-E)
    2, 6 % コ(B-F)
    3, 7 % サ(C-G)
    4, 8 % シ(D-H)
    ];
try
    [windowPtr, windowRect] = Screen('OpenWindow', screenNumber, bgColor);
    % スクリーンの中心座標
    [centerPos(1), centerPos(2)] = RectCenter(windowRect);
    
    % OpenGL関数で描画する領域
    myRect = CenterRectOnPoint([0 0 screenWidth screenWidth], centerPos(1), centerPos(2));
    
    % OpenGL関数を使い始めるという宣言
    Screen('BeginOpenGL', windowPtr);
    % PTBの座標系では画面の左上が原点だが、OpenGLでは画面の左下が原点であることに注意。
    glViewport(myRect(1), myRect(2), screenWidth, screenWidth);
    
    glMatrixMode(GL.PROJECTION); % アンダーバーがドットになっていることに注意。
    glLoadIdentity;
    glOrtho(-2, 2, -2, 2, -2, 2);
    glClearColor(1,1,1,1); % 背景色
    glClear;
    
    glColor3d(0.0, 0.0, 0.0);
    
    glBegin(GL.LINES); % アンダーバーがドットになっていることに注意。
    for i = 1:12 % 12本の線分を描く
        glVertex3dv(vertex(edge(i,1),:));
        glVertex3dv(vertex(edge(i,2),:));
    end;
    glEnd();
    % OpenGL関数の使用を終わります。
    Screen('EndOpenGL', windowPtr);
    % この段階で、PTBの機能を使って図形を描画することも可能です。
    Screen('FillRect', windowPtr, [255 0 0], [200 300 400 400]);
    
    Screen('Flip', windowPtr);
    KbWait;
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
catch
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
    psychrethrow(psychlasterror);
end

透視投影する。

clear all;
AssertOpenGL;
ListenChar(2);
bgColor = [128 128 128]; % 背景色
screenWidth = 500; % OpenGLで描画する領域(正方形)の幅。
screenNumber=max(Screen('Screens'));
InitializeMatlabOpenGL;
% 頂点の情報
vertex = [
    0, 0, 0 % A (1)
    1, 0, 0 % B (2)
    1, 1, 0 % C (3)
    0, 1, 0 % D (4)
    0, 0, 1 % E (5)
    1, 0, 1 % F (6)
    1, 1, 1 % G (7)
    0, 1, 1 % H (8)
    ];
% 2つの頂点を結ぶ線分の情報
% MATLABでは行列の参照が0からではなく、1からであることに注意。
edge = [
    1, 2 % ア(A-B)
    2, 3 % イ(B-C)
    3, 4 % ウ(C-D)
    4, 1 % エ(D-A)
    5, 6 % オ(E-F)
    6, 7 % カ(F-G)
    7, 8 % キ(G-H)
    8, 5 % ク(H-E)
    1, 5 % ケ(A-E)
    2, 6 % コ(B-F)
    3, 7 % サ(C-G)
    4, 8 % シ(D-H)
    ];
try
    [windowPtr, windowRect] = Screen('OpenWindow', screenNumber, bgColor);
    % スクリーンの中心座標
    [centerPos(1), centerPos(2)] = RectCenter(windowRect);
    
    % OpenGL関数で描画する領域
    myRect = CenterRectOnPoint([0 0 screenWidth screenWidth], centerPos(1), centerPos(2));
    
    % OpenGL関数を使い始めるという宣言
    Screen('BeginOpenGL', windowPtr);
    % PTBの座標系では画面の左上が原点だが、OpenGLでは画面の左下が原点であることに注意。
    % 透視投影のときは、glViewportは不要。有効にすると表示が変わる。
    %glViewport(myRect(1), myRect(2), screenWidth, screenWidth);
    
    glMatrixMode(GL.PROJECTION); % アンダーバーがドットになっていることに注意。
    glLoadIdentity;
    
    gluPerspective(30.0, windowRect(3)/windowRect(4), 1.0, 100.0);
    glTranslated(0.0, 0.0, -5.0);
    glClearColor(1,1,1,1); % 背景色
    glClear;
    
    glColor3d(0.0, 0.0, 0.0);
    
    glBegin(GL.LINES); % アンダーバーがドットになっていることに注意。
    for i = 1:12 % 12本の線分を描く
        glVertex3dv(vertex(edge(i,1),:));
        glVertex3dv(vertex(edge(i,2),:));
    end;
    glEnd();
    % OpenGL関数の使用を終わります。
    Screen('EndOpenGL', windowPtr);
    % この段階で、PTBの機能を使って図形を描画することも可能です。
    Screen('FillRect', windowPtr, [255 0 0], [200 300 400 400]);
    
    Screen('Flip', windowPtr);
    KbWait;
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
catch
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
    psychrethrow(psychlasterror);
end

視点の位置を変更する。

clear all;
AssertOpenGL;
ListenChar(2);
bgColor = [128 128 128]; % 背景色
screenWidth = 500; % OpenGLで描画する領域(正方形)の幅。
screenNumber=max(Screen('Screens'));
InitializeMatlabOpenGL;
% 頂点の情報
vertex = [
    0, 0, 0 % A (1)
    1, 0, 0 % B (2)
    1, 1, 0 % C (3)
    0, 1, 0 % D (4)
    0, 0, 1 % E (5)
    1, 0, 1 % F (6)
    1, 1, 1 % G (7)
    0, 1, 1 % H (8)
    ];
% 2つの頂点を結ぶ線分の情報
% MATLABでは行列の参照が0からではなく、1からであることに注意。
edge = [
    1, 2 % ア(A-B)
    2, 3 % イ(B-C)
    3, 4 % ウ(C-D)
    4, 1 % エ(D-A)
    5, 6 % オ(E-F)
    6, 7 % カ(F-G)
    7, 8 % キ(G-H)
    8, 5 % ク(H-E)
    1, 5 % ケ(A-E)
    2, 6 % コ(B-F)
    3, 7 % サ(C-G)
    4, 8 % シ(D-H)
    ];
try
    [windowPtr, windowRect] = Screen('OpenWindow', screenNumber, bgColor);
    % スクリーンの中心座標
    [centerPos(1), centerPos(2)] = RectCenter(windowRect);
    
    % OpenGL関数で描画する領域
    myRect = CenterRectOnPoint([0 0 screenWidth screenWidth], centerPos(1), centerPos(2));
    
    % OpenGL関数を使い始めるという宣言
    Screen('BeginOpenGL', windowPtr);
    % PTBの座標系では画面の左上が原点だが、OpenGLでは画面の左下が原点であることに注意。

% 透視投影のときは、glViewportは不要。有効にすると表示が変わる。

    %glViewport(myRect(1), myRect(2), screenWidth, screenWidth);
    
    glMatrixMode(GL.PROJECTION); % アンダーバーがドットになっていることに注意。
    glLoadIdentity;
    
    gluPerspective(30.0, windowRect(3)/windowRect(4), 1.0, 100.0);
    gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    
    glClearColor(1,1,1,1); % 背景色
    glClear;
    
    glColor3d(0.0, 0.0, 0.0);
    
    glBegin(GL.LINES); % アンダーバーがドットになっていることに注意。
    for i = 1:12 % 12本の線分を描く
        glVertex3dv(vertex(edge(i,1),:));
        glVertex3dv(vertex(edge(i,2),:));
    end;
    glEnd();
    % OpenGL関数の使用を終わります。
    Screen('EndOpenGL', windowPtr);
    % この段階で、PTBの機能を使って図形を描画することも可能です。
    Screen('FillRect', windowPtr, [255 0 0], [200 300 400 400]);
    
    Screen('Flip', windowPtr);
    KbWait;
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
catch
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
    psychrethrow(psychlasterror);
end