OpenGL関数で陰影付け

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

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

実行するとアニメーションが開始されます。左矢印キーを押すたびに、アニメーションの有効と無効が切り替わります。アニメーションが無効な状態で右矢印キーを押すと、立方体が1度だけ回転します。エスケープキーで終了します。

clear all;
AssertOpenGL;
ListenChar(2);
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)
    ];
face = [
    1, 2, 3, 4
    2, 6, 7, 3
    6, 5, 8, 7
    5, 1, 4, 8
    5, 6, 2, 1
    4, 3, 7, 8
    ];
normal = [
    0 0 -1
    1 0 0
    0 0 1
    -1 0 0
    0 -1 0
    0 1 0
    ];
light0pos = [0 3 5 1];
light1pos = [5 3 0 1];
green = [0 1 0 1];
red = [0.8 0.2 0.2 1];
try
    [windowPtr, windowRect] = Screen('OpenWindow', screenNumber);
    % スクリーンの中心座標
    [centerPos(1), centerPos(2)] = RectCenter(windowRect);
        
    % OpenGL関数を使い始めるという宣言
    Screen('BeginOpenGL', windowPtr);
    glEnable(GL.DEPTH_TEST);
    glEnable(GL.CULL_FACE);
    glCullFace(GL.FRONT);
    
    glEnable(GL.LIGHTING);
    glEnable(GL.LIGHT0);
    glEnable(GL.LIGHT1);
    glLightfv(GL.LIGHT1, GL.DIFFUSE, green);
    glLightfv(GL.LIGHT1, GL.SPECULAR, green);
    
    glMatrixMode(GL.PROJECTION); % アンダーバーがドットになっていることに注意。
    glLoadIdentity;
    
    gluPerspective(30.0, windowRect(3)/windowRect(4), 1.0, 100.0);
    
    glMatrixMode(GL.MODELVIEW);
    
    r = 0; % 回転角の初期値
    flag = 1; % flagが1のときrが自動的に加算される。(アニメーション)
    
    while KbCheck; end; % いずれのキーも押していないことを確認
    while 1 % while 文の中をぐるぐる回ります。
        [ keyIsDown, keyTime, keyCode ] = KbCheck; % キーが押されたか、そのときの時間、どのキーか、の情報を取得する
        if keyIsDown
            if keyCode(KbName('ESCAPE')) % エスケープキーでプログラムを終了
                break;
            end
            if keyCode(KbName('LeftArrow'))
                flag = 1-flag; % アニメーションを有効にしたり、無効にしたり。
            end;
            
            if keyCode(KbName('RightArrow'))
                r = r + 1; % 手動で回転角度を増やす。
                if r >= 360
                    r = 0;
                end;
            end;
            while KbCheck; end;                    
        end;
        
        glClearColor(1,1,1,1); % 背景色
        glClear(GL.COLOR_BUFFER_BIT);
        glClear(GL.DEPTH_BUFFER_BIT);
        glLoadIdentity;
        gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); % 視点位置と視線方向
        
        % 光源の設定
        glLightfv(GL.LIGHT0, GL.POSITION, light0pos);
        glLightfv(GL.LIGHT1, GL.POSITION, light1pos);
  
        glRotated(r, 0, 1, 0); % 図形の回転
        
        % 図形の色
        glMaterialfv(GL.FRONT_AND_BACK, GL.AMBIENT_AND_DIFFUSE, red);
        
        % 図形の描画        
        glBegin(GL.QUADS); % アンダーバーがドットになっていることに注意。
        for j = 1:6
            glNormal3dv(normal(j,:));
            for i = 1:4
                glVertex3dv(vertex(face(j,i),:));
            end;
        end;
        glEnd();
        
        % OpenGL関数の使用を終わります。
        Screen('EndOpenGL', windowPtr);
        % この段階で、PTBの機能を使って図形を描画することも可能です。
        Screen('FillRect', windowPtr, [255 0 0], [200 300 400 400]);
        Screen('Flip', windowPtr);
        
        % 次の繰り返しのために
        Screen('BeginOpenGL', windowPtr);
        
        if flag % flagが1のときはアニメーション
            r = r + 1;
            if r >= 360
                r = 0;
            end;
        end;
    end;
    
    % OpenGL関数の使用を終わります。
    Screen('EndOpenGL', windowPtr);
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
catch
    Screen('CloseAll');
    ShowCursor;
    ListenChar(0);
    psychrethrow(psychlasterror);
end