Welcome to Mashykom WebSite




OpenGL によるコンピュータ・グラフィックス入門

 OpenGL(Open Graphics Library)はオープンソースのグラフィックスAPI(アプリケーションプログラミングインターフェイス)で、グラフィックスハードウェア向けの2次元/3次元コンピュータグラフィックスライブラリです。OpenGLは、Linux、FreeBSDなどのPC UNIXに加え、Windows、macOS等で使用できるクロスプラットフォームなグラフィックスAPIです。また、スマホ、タブレットなどへの組み込み用途向けのバージョンであるOpenGL ES (OpenGL for Embedded Systems) 規格も存在します。2006年9月21日以降からは、100以上の企業で構成される標準化団体クロノス・グループ (The Khronos Group) へ管理が移行し、OpenGL ARB Working Group (OpenGL ARB WG) となった。現在では、OpenGL ESから派生したWebGL というHTML5 に対応した3Dグラフィックス API も開発されています。

 OpenGLはプログラマが挙動を指示するために使うインターフェースを定義するものです。つまり、OpenGLは単にAPIを規定した"仕様"であり、実際の処理はintelとかNVIDIAとかのハードウェアベンダーが独自に実装することになる。コンピュータ上でグラフィックを描画する作業はOSが管理してる。 ユーザーがプログラムからグラフィックを描画するには、OSに「こんな画面描いて」と指示を出す必要があります。 ところが、Windows、macOS、LinuxなどのOSでは、グラフィックの扱い方に違いがあるため、OSへの指示の出し方がそれぞれ異なります。 OSごとに指示の出し方が違うのは面倒だということで、共通の規格として定められたのがOpenGLです。

 OpenGLはあくまでレンダリングエンジンのAPIだけを規定したものであり、プログラム実行時にウィンドウを表示したり、そこにOpenGLのコンテキストを紐付けたり、マウスやキーボードの入力を受け付けたりといった機能は入っていません。 これらの機能は自分の環境のウィンドウシステムに合わせて個別に実装しなければなりません。この実装を代わりにやってくれるのが、GLFW、GLEW、GLM などのUtility Toolkitです。OpenGLを使うためには、これらのToolkitをインストールする必要があります。

 OpenGL version2.0 以前では、リアルタイム3Dコンピューターグラフィックスは、OpenGLのAPIを通してグラフィックスカード上のチップ(GPU)にあらかじめ用意された固定のレンダリングパイプライン上で、固定機能のシェーダー(頂点トランスフォームや陰影計算を専門に担当するユニット)を組み合わせることで実現されていた。

 OpenGL version2.0以降は、グラフィックスカードの進化・性能向上に伴い、ハードウェア実装による固定機能ではなく、アプリケーション開発者がソフトウェアプログラム(プログラマブルシェーダー)によって頂点レベル・フラグメントレベル(ピクセルレベル)での制御・カスタマイズを行うようになった。OpenGL ARBは、グラフィックス処理を行うプログラミングをより直感的・効率的にできる方法として、OpenGL Shading Languageを作り出した。GLSL (OpenGL Shading Language) はGLslangとしても知られ、C言語をベースとした高レベルシェーディング言語である。現在、GLSLはOpenGLに組み込まれています。

 このページでは、GLFW、GLEW、および、GLMを用いてOpenGLを利用してグラフィックスを作成する初歩的な手法を説明します。プラットフォームとして、MacOS version 10.14(現在では、MacOS Big Sur)を使います。このMacOS にはOpenGL 4.1がインストールされています。Mac OS version 10.14からOpenGLが非推奨となっているので、本来ならば、Metalに変更すべきかもしれませんが、このページでは OpenGL 使用法を取り上げます。MacOS 10.14 MojaveにおけるOpen GL /GL ESとOpenCLの扱いは、あくまで非推奨になったというだけで、Mojave あるいは Big Sur にアップデートしたら即、動作しなくなるというわけではありません。ただし、Metalに移行することを推奨する多数の警告等が出ます。OpenGLのコードが正常に機能する限りは、これらの警告は無視してください。

 Visual Studio や Xcode などの統合環境を用いないで、ターミナルのコマンドラインからMakefileを用いてOpenGLのソースコードをビルドする方法についても説明します。この方法は Linux 、MacOs 、Windows というプラットフォームに依存せずに、OpenGL のソースコードをビルドできます。C++ に関するある程度の知識が必要です。

 なお、このページでは、OpenGLおよびGLSLのコーディングの具体的な方法について解説を省略します。参考書として、床井浩平著『「グラフィックス・アプリ」制作のためのOpenGL入門 』(I・O BOOKS、工学社) がお薦めです。Webでのチュートリアルは、opengl-tutorial.orgがお勧めです。

Last updated: 2020.12.20



OpenGL の環境設定と Xcode でソースコードのビルド


 上で触れた通り、OpenGL はどのプラットフォームでもGPUに対応したバージョンが標準で組み込まれています。改めてインストールする必要はありません。GPUの情報は本体のシステム情報から、MacOSに組み込まれているOpenGLのバージョンはAppleのサイトを見るとわかります。

 現時点でのMacOS XでインストールされているOpenGLのバージョンは4.1、対応するGLSLのバージョンは4.1です。OpenGLのCoreの部分はOpenGL v3.2以降同一で、拡張機能の部分が異なります。OpenGL v3.2に対応するGLSLはバージョン1.5ですが、OpenGL v3.3 以降はGLSLのバージョン名はOpenGLのバージョンと同じになりました。2012年以降のMacのIntel GPUはOpenGL v4.1をサポートしています。OpenGLは後方互換性を持っているので、例えば、OpenGL v4.1がインストールされているMac OSの場合でも、OpenGL v1.0 で書かれたソースファイルを実行できます。

 OpenGLを利用するためにGLFW(OpenGL Frameworkの略)というライブラリを使用します。 以下では、MacOSでの開発環境の設定方法について説明します。Homebrewを利用するときは、


$ brew install glfw3

とコマンドを入力して、インストールします。

 GLFWをソースコードからコンパイルしてインストールする場合には、 GLFWのソースコードをこの公式ページからダウンロードできます。2019年1月でのバージョンは glfw-3.2.1 です。「ターミナル」を開いて、以下のスクリプトを1行1行実行していきます。

$ git clone https://github.com/glfw/glfw.git    # gitHubからソースコードのダウンロードするとき
$ cd glfw                                       # ダウンロードしたソースのディレクトリに移動
$ mkdir build && cd build                       # ビルド用のディレクトリを作成して、そこに移動
$ cmake ..                                      # CMakeを利用したビルドの準備
$ make                                          # ビルド
$ sudo make install                             # インストール

 ファイルは /usr/local/include にインストールされます。

 高度な操作でソースコードを動かすためには, 最近のOpenGLの機能を扱うためのライブラリが必要です。 GLEW (OpenGL Extension Wrangler Library) を使ってプログラムを作る必要があります。ベクトルや行列の計算を簡単に扱うためのライブラリとしてGLM (OpenGL Mathematics) も導入します。

 GLEW、GLMともにソースコードのzip ファイルをダウンロードし、GNU Makeあるいは CMakeを使用してビルド、インストールを行います。まず、GLEWの公式Webページ または、このページからソースコードのzipファイルをダウンロードして、ビルドとインストールを行います。ターミナルを開いて、次のコマンドを実行してください。

$ git clone https://github.com/nigels-com/glew.git glew
$ cd glew
glew $ make
glew $ sudo make install
glew $ make clean

 ファイルは /usr/local/include にインストールされます。最新バージョンはglew-2.1.0 です。

 次に、GLMの公式ページからソースコードを ダウンロードして、ビルドとインストールを行います。GLEWの時と同様に、 次のコマンドをターミナルで実行してください。

$ git clone https://github.com/g-truc/glm.git
$ cd glm
$ mkdir build && cd build
$ cmake ..
$ make
$ sudo make install

 GLMのファイルは /usr/local/include にインストールされます。 glm は C++ の座標系ベクターの取り扱いを中心とした数学系のライブラリーです。基本的には3DCG向けの、特にOpenGLとの親和性の高いグラフィックス用途のライブラリーですが、その機能はよく整理されて実装されており、比較的低次のベクター処理に汎用に扱えるものとなっています。これで必要なOpenGL環境のインストールは完了です。

 通常、MacOSではXcodeを用いて OpenGL の(C++)ソースコードをビルドします。XcodeはVisual Studioよりも 機能的には若干劣るものの、よくできた統合開発環境です。XcodeのインストールはApp Storeから行います。最新バージョンは、Xcode12.3 ですが、各バージョンは、Appleの公式websiteからダウンロードできます。ただし、Metalへの移行を推奨するために、多数の警告が出ます。ビルドが成功する間は、とりあえず、無視してください。Xcodeを用いないでビルドする方法については、後段で説明します。

 プログラムを作成するために、Xcode の設定を行います。インストールが完了したらXcodeを起動します。起動すると[Welcome to Xcode]という画面が表示されます。「Create a new Xcode Project」をクリックします。

Xcode10_1.png

すると、どのようなプロジェクトを作成するのかを指定する画面が表示されます。「macOS」の「Command Line Tool」を選択して、右下の「Next」をクリックします。

Xcode10_2.jpg

すると、次はプロジェクトの詳細を設定する画面が現れます。ここは、どのように設定しても 基本は問題ないのですが、project name を例えば GLsample にして、一番下の「Language」を「C++」にするのだけは忘れないようにしてください。新規作成するファイルのフォルダーを選択します。このファルダーにxcodeのファイルが作成されます。

 次にXcodeでGLFWなどを使うための設定をします。まずはGLFWのインクルードディレクトリと ライブラリディレクトリの設定です。上記の通りにGLFW、GLEW、GLMをインストールしている場合には、それぞれが以下のようなパスになっています。インクルードディレクトリは

/usr/local/include

ライブラリディレクトリは

/usr/local/lib

です。

 Xcodeの画面左側にあるプロジェクト名GLsampleをクリックすると、 設定画面が現れるので、その設定画面の「Build Settings」をクリックして開きます。検索窓で「search」として、この画面を下にスクロールしていくと「Search Paths」という項目が見つかるので、 その中にある"Header Search Paths"および"Library Search Paths"を以下のように編集します。“Header Search Paths”の左側をダブルクリックすると、入力ウインドウがポップアップしますので、

/usr/local/include

と入力します。次に、"Library Search Paths"をクリックして、Debug の右側のプラスをクリックする。入力ウインドウがポップアップしますので、

/usr/local/lib

と入力します。

 MacOSでGLFWやGLEWなどを使うためには、いくつかのフレームワーク(ライブラリの集合みたいなもの)をプロジェクトに 追加する必要があります。リンクするライブラリとフレームワークを設定します。検索窓で"linker"を入力して、"Other Linker Flags"という項目を探して、その左側をクリックします。Debug のラインの入力ウインドウにある"+"をクリックして、以下の内容を入力します。

 
-lglfw3

この項目、"-lglfw3"は必須です。GLEWを使用するときは、"-lGLEW"が必要です。それ以外については、以下のように設定することもできます。 先ほどの設定画面上部で「Build Settings」を選んでいた箇所の一番左にある「General」を選択します。すると、画面下部に「Linked Frameworks and Libraries」という項目があるので、こちらに使用する フレームワークを追加していきます。ここで使用するフレームワークは最小限の4種類で「OpenGL」、「Cocoa」、「CoreVideo」、「IOKit」を追加します。 いずれも「Linked Frameworks and Libraries」項目の下側にある「+」ボタンを押すと入力のポップアップが現れるので、 その画面で検索することにより追加できます。「Linked Frameworks and Libraries」項目に以下の項目が並びます。

 Xcodeの場合には、上記のやり方でプロジェクトを作成すると、すでに「main.cpp」という ファイルが作成されています。 以下のファイルのコードを、main.cppにコピペ等で修正します。

//
//  main.cpp
//  GLsample
//

#include <cstdlib>
#include <iostream>
#include <GLFW/glfw3.h>

int main()
{
  // GLFW を初期化する
  if (glfwInit() == GL_FALSE)
  {
    // 初期化に失敗したとき
    std::cerr << "Can't initialize GLFW" << std::endl;
    return 1;
  }

  // プログラム終了時の処理を登録する
  atexit(glfwTerminate);

  // OpenGL Version 3.2 Core Profile を選択する
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

  // ウィンドウを作成する
  GLFWwindow *const window(glfwCreateWindow(640, 480, "Hello! OpenGL", NULL, NULL));
  if (window == NULL)
  {
    // ウィンドウが作成できなかったとき
    std::cerr << "Can't create GLFW window." << std::endl;
    return 1;
  }

  // 作成したウィンドウを OpenGL の処理対象にする
  glfwMakeContextCurrent(window);


  // 作成したウィンドウに対する設定
  glfwSwapInterval(1);

  // 背景色を指定する
  glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

  // ウィンドウが開いている間繰り返す
  while (glfwWindowShouldClose(window) == GL_FALSE)
  {
    // ウィンドウを消去する
    glClear(GL_COLOR_BUFFER_BIT);

    //
    // ここで描画処理を行う
    //

    // カラーバッファを入れ替える
    glfwSwapBuffers(window);

    // イベントを取り出す
    glfwWaitEvents();
  }
}

 ソースコードのコンパイルと実行は簡単です。projectの main.cpp をクリックして、上部にある実行アイコン▶️をクリックします。白色に描画されたウインドウがポップアップします。「'glClearColor' is deprecated: first deprecated in macOS 10.14 - OpenGL API deprecated. (Define GL_SILENCE_DEPRECATION to silence these warnings)」という警告が表示されますが、無視してください。

 ソースコードの説明を少しします。ソースプログラムの先頭でGLFWのヘッダファイル「GLFW/glfw3.h」をincludeし、main関数の最初でglfwInit()関数を実行します。glfwInit()関数による初期化が成功すれば、戻り値としてGLFW_TRUEとなり、失敗するときはGLFW_FALSEが返されます。

 GLFWの初期化が成功したら、glfwCreateWindow()関数を用いて、描画のウインドウを作成します。ウインドウの作成に失敗すると、NULLを返します。成功すれば、ハンドル(window)を戻り値として返します。glfwCreateWindow()が返したハンドル(ポインター)をglfwMakeContextCurrent()関数の引数にして、ウインドウのレンダリング・コンテキストの処理対象にします。

 glfwWindowShouldClose(window)関数はウインドウが閉じられたか否かを調べる関数です。ウインドウが閉じられる命令があるまで、while文を用いて描画の表示を維持します。glClear(GL_COLOR_BUFFER_BIT)はカラー・バッファだけを、glClearColor()関数で指定された色で塗りつぶす命令です。glfwSwapBuffers(window)はウインドウのカラー・バッファを入れ替える命令です。この関数を実行しないと描画した図形がウインドウに表示されません。glfwSwapInterval(1)とglfwWaitEvents()については無視してください。


OpenGL 2.xのソース・プログラム



 例えば、以下のコードはOpenGL 3.3がインストールされたOSで実行できるソースですが、OpenGL 2.1用のコードで書かれています。つまり、OpenGL 2.1バージョンを使っています。

//
//  main.cpp
//  OpenGL 2.1
// 引用先 https://tatsy.github.io/OpenGLCourseJP/sections/animation/one_cube.html

#include <cstdio>
#include <cmath>

#define GLFW_INCLUDE_GLU  // GLUライブラリを使用するのに必要
#include <GLFW/glfw3.h>

static int WIN_WIDTH   = 500;                       // ウィンドウの幅
static int WIN_HEIGHT  = 500;                       // ウィンドウの高さ
static const char *WIN_TITLE = "OpenGL Course";     // ウィンドウのタイトル
static const double fps = 30.0;                     // FPS

static const double PI = 4.0 * atan(1.0);           // 円周率の定義

static float theta = 0.0f;

static const float positions[8][3] = {
    { -1.0f, -1.0f, -1.0f },
    {  1.0f, -1.0f, -1.0f },
    { -1.0f,  1.0f, -1.0f },
    { -1.0f, -1.0f,  1.0f },
    {  1.0f,  1.0f, -1.0f },
    { -1.0f,  1.0f,  1.0f },
    {  1.0f, -1.0f,  1.0f },
    {  1.0f,  1.0f,  1.0f }
};

static const float colors[6][3] = {
    { 1.0f, 0.0f, 0.0f },  // 赤
    { 0.0f, 1.0f, 0.0f },  // 緑
    { 0.0f, 0.0f, 1.0f },  // 青
    { 1.0f, 1.0f, 0.0f },  // イエロー
    { 0.0f, 1.0f, 1.0f },  // シアン
    { 1.0f, 0.0f, 1.0f },  // マゼンタ
};

static const unsigned int indices[12][3] = {
    { 1, 6, 7 }, { 1, 7, 4 },
    { 2, 5, 7 }, { 2, 7, 4 },
    { 3, 5, 7 }, { 3, 7, 6 },
    { 0, 1, 4 }, { 0, 4, 2 },
    { 0, 1, 6 }, { 0, 6, 3 },
    { 0, 2, 5 }, { 0, 5, 3 }
};

// OpenGLの初期化関数
void initializeGL() {
    // 背景色の設定 (黒)
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    
    // 深度テストの有効化
    glEnable(GL_DEPTH_TEST);
}

// キューブの描画
void drawCube() {
    glBegin(GL_TRIANGLES);
    for (int face = 0; face < 6; face++) {
        glColor3fv(colors[face]);
        for (int i = 0; i < 3; i++) {
            glVertex3fv(positions[indices[face * 2 + 0][i]]);
        }
        
        for (int i = 0; i < 3; i++) {
            glVertex3fv(positions[indices[face * 2 + 1][i]]);
        }
    }
    glEnd();
}

// OpenGLの描画関数
void paintGL() {
    // 背景色と深度値のクリア
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    // ビューポート変換の指定
    glViewport(0, 0, WIN_WIDTH, WIN_HEIGHT);
    
    // 座標の変換
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (float)WIN_WIDTH / (float)WIN_HEIGHT, 0.1f, 1000.0f);
    
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(3.0f, 4.0f, 5.0f,     // 視点の位置
              0.0f, 0.0f, 0.0f,     // 見ている先
              0.0f, 1.0f, 0.0f);    // 視界の上方向
    
    glRotatef(theta, 0.0f, 1.0f, 0.0f);
    
    // キューブの描画
    drawCube();
}

void resizeGL(GLFWwindow *window, int width, int height) {
    // ユーザ管理のウィンドウサイズを変更
    WIN_WIDTH = width;
    WIN_HEIGHT = height;
    
    // GLFW管理のウィンドウサイズを変更
    glfwSetWindowSize(window, WIN_WIDTH, WIN_HEIGHT);
    
    // 実際のウィンドウサイズ (ピクセル数) を取得
    int renderBufferWidth, renderBufferHeight;
    glfwGetFramebufferSize(window, &renderBufferWidth, &renderBufferHeight);
    
    // ビューポート変換の更新
    glViewport(0, 0, renderBufferWidth, renderBufferHeight);
}

// アニメーションのためのアップデート
void animate() {
    theta += 2.0f * PI / 10.0f;  // 10分の1回転
}

int main(int argc, char **argv) {
    // OpenGLを初期化する
    if (glfwInit() == GL_FALSE) {
        fprintf(stderr, "Initialization failed!\n");
        return 1;
    }
    
    // Windowの作成
    GLFWwindow *window = glfwCreateWindow(WIN_WIDTH, WIN_HEIGHT, WIN_TITLE,
                                          NULL, NULL);
    if (window == NULL) {
        fprintf(stderr, "Window creation failed!");
        glfwTerminate();
        return 1;
    }
    
    // OpenGLの描画対象にWindowを追加
    glfwMakeContextCurrent(window);
    
    // ウィンドウのリサイズを扱う関数の登録
    glfwSetWindowSizeCallback(window, resizeGL);
    
    // OpenGLを初期化
    initializeGL();
    
    // メインループ
    while (glfwWindowShouldClose(window) == GL_FALSE) {
        // 描画
        paintGL();
        
        // アニメーション
        animate();
        
        // 描画用バッファの切り替え
        glfwSwapBuffers(window);
        glfwPollEvents();
    }
}

このコードをXcodeを用いて'run'すると、ウインドウに立方体が回転するCGが表示されます。多数のwarningがでます。例えば、'glClearColor' is deprecated: first deprecated in macOS 10.14 - OpenGL API deprecated. (Define GL_SILENCE_DEPRECATION to silence these warnings)、など。 このコードでは、シェーダファイルは利用されていませんので、main.cpp ファイル一つだけで済みます。興味のある人はファイルをコピペして、実行して見てください。OpenGL 2.1バージョンを利用する場合、GLUTなどのAPIが使えるので、より簡易にコーディングが可能となります。その代わりに、高度なCGはできません。


OpenGL 3.x のソース・プログラム



 OpenGL 2.0以前では glBegin() で描画する基本図形を指定し, glEnd() までの間で glVertex*() や glNormal*(), glTexCoord*() などで頂点情報を送ることができました。 OpenGL 3.0 以降バージョンにおいても、このコマンドは使用可能ですが、OpenGL Version 3.2 Core Profileを選択すると、つまり、前方互換を指定すると, これらは使えなくなります。代わりに, 図形の描画には頂点配列 (vertex array) や頂点配列オブジェクト (vertex array object, VAO), あるいは頂点バッファオブジェクト (vertex buffer object, VBO) を使用します。描画する基本図形 (primitive) の種類を指定した後, 図形を構成する頂点情報をGPUに送って図形を描画します。描画を行うためには、GLSLという言語(シェーダ言語)で書く必要があります。これが結構大変なのです。

 最も簡単で可能な設定では、2つのシェーダが必要となります。一つは頂点シェーダで、各頂点で実行されます。もう一つはフラグメントシェーダで各サンプルで実行されます。シェーダファイルの作成とシェーダの実行に関する説明は省略します。

 OpenGL 3.x バージョンのコーディングを取り上げてみましょう。以下のソース・コードは、バーテックス・シェーダとフラグメント・シェーダの配置例を明示していますが、上記のGLsampleと類似した最もシンプルなOpenGL 3.xのプログラムです。Xcodeを開いて、OpenGL向けのプロジェクトを作成して、以下のソース・コードをmain.cppにコピペしてください。


//
//  main.cpp
//

#include <GLFW/glfw3.h>

    /* ここにバーテックス・シェーダのシェーダオブジェクトを作成し、オブジェクトに組み込むコードを置く */

    /* ここにフラグメント・シェーダのシェーダオブジェクトを作成し、オブジェクトに組み込むコードを置く */

  /* プログラムオブジェクトを作成する 
  const GLuint program(createProgram(vShader, fShader)); 
  */

int main(void)
{
    GLFWwindow* window;

    /* GLFWを初期化*/
    if (!glfwInit())
        return -1;

    /* ウインドウを作成する */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* ウインドウを 引数windowの context current にする*/
    glfwMakeContextCurrent(window);

    /* ユーザーが停止を指示するまでウインドウを繰り返し表示する */
    while (!glfwWindowShouldClose(window))
    {
        glClear(GL_COLOR_BUFFER_BIT);

  /* ここに、バーテックス・シェーダとフラグメント・シェーダのソースプログラムを置く */

    /* シェーダプログラムの使用開始 
    glUseProgram(program); */

    //
    //ここで描画処理を行う
    //

        /* カラーバッファを入れ替える */
        glfwSwapBuffers(window);

        /* イベントを取り出す */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

 projectの main.cpp をクリックして、上部にある実行アイコン▶️をクリックします。バーテックス・シェーダとフラグメント・シェーダのプログラムが実装されていませんので、「Hello World」という黒色のウインドウのみがポップアップします。なお、XcodeでLibrary Search Pathsに「-lGLEW」を設定していると、ビルドは成功します。

 OpenGLの使用に関するチュートリアルやサンプルコードは、websiteに多数あります。OpenGL 3.3 に対応したopengl-tutorial.orgのサイトにあるサンプルは便利です。このソースコードをダウンロードします。解凍して、適当なディレクトリに展開します(例えば、フォルダー名を「OpenGLTutorials」という名前にします)。CMakeがインストールされていることが前提です。インストールされていないときは、CMakeのサイトからダウンロードしてください。以下の説明は、Xcode 11 バージョンを用いたときのものですが、Mac OS Big Sur でも正常に使用できることを確認しています。

 Xcode を使用するケースについて説明します。CMake(Applications->CMake)を起動してください。最初の項目(Where is the source code)に解凍したディレクトリ(例えば、~/OpenGLTutorials)を指定します。次の項目(Where is to build the binaries)にコンパイラ関係のものを置く場所を指定します。例えば、~/OpenGLTutorials/XCode_bin/と指定します。必ずしもこの名前でなくても大丈夫です。

 次に、Configureボタンをクリックしてください。プロジェクトを設定するのが初めてなので、CMakeはどのコンパイラを使うか聞いてきます。Xcodeを選らびます。赤いラインが消えるまでConfigure をクリックして下さい。Configuring doneと表示されて、処理が終了します。次に、Generateをクリックしてください。Generating done と表示され、これで、Xcodeのプロジェクトが作成されます。

 Finderから~/OpenGLTutorials/XCode_bin/を開いてください。Tutorials.xcodeproj ファイルが見つかるので、それをダブルクリックして開きます。Xcodeのproject panel(Tutorialsという名前のプロジェクト)の中から実行したいチュートリアルを選びます。例えば、「tutorial04_colored_cube」を選択して、ソースファイルのtutorial04.cppをクリックします。そして、RunのメニューボタンのALL_BUILDの項目をクリックして、「tutorial04_colored_cube」を選択します。最後に、Runボタンをクリックして、コンパイルと実行をします。すると、以下のグラフィック画像がポップアップします。

colored_cube.png

 なお、tutorial17のファイルが正常に画像を表示するとは限りませんので、ご注意ください。


 OpenGLのコーデイングを説明した書籍では、床井浩平著『「グラフィックス・アプリ」制作のためのOpenGL入門 』(I・O BOOKS、工学社) がお薦めです。付属のサンプルコードはXcode 11 以前のバージョンで実行可能なコードですが、Xcode 12.0 バージョン以降ではXcodeを用いて実行可能なコードになっていません。古いバージョンのXcode では、各stepごとに配置しているファイル'glfw3.xcodeproj'をクリックしてXcodeを立ち上げると、'run'できます。ただし、C++ファイルのソースはShift_JIS形式でコーディングされているので、文字化けを起こします。UTF-8などの形式に変換して下さい。

 ちなみに、最終章のstep40に配置されているXcodeの起動ファイル'glfw3.xcodeproj'をクリックすると、Xcodeの画面が開きます。projectの main.ccp をクリックして、上部にある実行アイコン▶️をクリックします。ビルドが成功して、 以下のグラフィックス画像が表示されます。

rotation.png

 上に付記した通り、これらのサンプルコードは Xcode 11 までのバージョンでは正常に機能しますが、Mac OS Big Sur の Xcode 12 バージョン以降では正常に作動しません。


Makefileを用いたビルドの方法:Mac OS



 最新版のXcodeでは警告やエラーが相当出るようなので、Xcodeを使用せずに、Makefileを活用してソースファイルをビルドすることを考えます。以下のMakefileを作成してください。


# コンパイラの設定
CC          := clang
CXX         := clang++

# その他のコマンドの設定
RM          := rm
SH          := bash

# ソースコードの設定 
SOURCES	:= $(wildcard *.cpp)
HEADERS	:= $(wildcard *.h)
OBJECTS := $(patsubst %.cpp, %.o, $(SOURCES))

TARGET	= sample

# コンパイラ引数の設定 (インクルード・ディレクトリ等)
CFLAGS      := -Wall -g -O2 -I/usr/include -I/usr/local/include 
CXXFLAGS    := -Wall -g -O2 -std=c++11 -I/usr/include -I/usr/local/include 

# フレームワークの設定 (Mac特有のもの)
#FRAMEWORKS  := -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo

# ライブラリ引数の設定
LDLIBS     := -L/usr/lib -L/usr/local/lib -lglfw3 -lGLEW -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo



.PHONY: clean

$(TARGET): $(OBJECTS)
	$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@

$(TARGET).dep: $(SOURCES) $(HEADERS)
	$(CXX) $(CXXFLAGS) -MM $(SOURCES) > $(TARGET).dep

clean:
	-$(RM) $(TARGET) *.o *~ .*~ a.out core

 このMakefileは、床井『「グラフィックス・アプリ」制作のためのOpenGL入門 』のサンプル・プログラムの中で使用されているコードを若干修正したものです。次に、下記のコードをコピペしてOpenGL sampleを作成してください。上記のMakefileをOpenGL sampleと同一のディレクトリに配置してください。


//
//  main.cpp
//  OpenGL sample
//

#include <GL/glew.h>
#include <GLFW/glfw3.h>

// Define main function
int main()
{
    // Initialize GLFW
    glfwInit();

    // Define version and compatibility settings
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    // Create OpenGL window and context
    GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", NULL, NULL);
    glfwMakeContextCurrent(window);

    // Check for window creation failure
    if (!window)
    {
        // Terminate GLFW
        glfwTerminate();
        return 0;
    }

    // Initialize GLEW
    glewExperimental = GL_TRUE; glewInit();

    // Event loop
    while(!glfwWindowShouldClose(window))
    {
        // Clear the screen to black
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // Terminate GLFW
    glfwTerminate(); return 0;
}

ターミナルを起動して、シェルプロンプトをこのディレクトリに移動させて


$ make

と打ち込んでください。実行ファイル「sample」が作成されるので、


$ ./sample

と実行してください。「OpenGL」というタイトル名の黒色のウインドウがポップアップします。

 ここで、opengl-tutorial.orgのサイトにあるサンプルを上記のmakefileを用いてビルドしてみましょう。

 beginners-tutorialsのtutorial02_red_triangle ディレクトリには、tutorial02.cpp、SimpleFragmentShader.fragmentshader、および、SimpleVertexShader.vertexshaderの3種類ファイルがあります。tutorial02.cppのソースは以下の内容通りです(修正した部分もあります)。main.cppという名称でコピペしてください。



// opengl-tutorials:no.2

// Include standard headers
#include <stdio.h>
#include <stdlib.h>

// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <GLFW/glfw3.h>
GLFWwindow* window;

// Include GLM
#include <glm/glm.hpp>
using namespace glm;

#include "shader.hpp"

int main( void )
{
	// Initialise GLFW
	if( !glfwInit() )
	{
		fprintf( stderr, "Failed to initialize GLFW\n" );
		getchar();
		return -1;
	}

	glfwWindowHint(GLFW_SAMPLES, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	// Open a window and create its OpenGL context
	window = glfwCreateWindow( 1024, 768, "Tutorial 02 - Red triangle", NULL, NULL);
	if( window == NULL ){
		fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
		getchar();
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	// Initialize GLEW
	glewExperimental = true; // Needed for core profile
	if (glewInit() != GLEW_OK) {
		fprintf(stderr, "Failed to initialize GLEW\n");
		getchar();
		glfwTerminate();
		return -1;
	}

	// Ensure we can capture the escape key being pressed below
	glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);

	// Dark blue background
	glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

	GLuint VertexArrayID;
	glGenVertexArrays(1, &VertexArrayID);
	glBindVertexArray(VertexArrayID);

	// Create and compile our GLSL program from the shaders
	GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" );


	static const GLfloat g_vertex_buffer_data[] = { 
		-1.0f, -1.0f, 0.0f,
		 1.0f, -1.0f, 0.0f,
		 0.0f,  1.0f, 0.0f,
	};

	GLuint vertexbuffer;
	glGenBuffers(1, &vertexbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

	do{

		// Clear the screen
		glClear( GL_COLOR_BUFFER_BIT );

		// Use our shader
		glUseProgram(programID);

		// 1rst attribute buffer : vertices
		glEnableVertexAttribArray(0);
		glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
		glVertexAttribPointer(
			0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
			3,                  // size
			GL_FLOAT,           // type
			GL_FALSE,           // normalized?
			0,                  // stride
			(void*)0            // array buffer offset
		);

		// Draw the triangle !
		glDrawArrays(GL_TRIANGLES, 0, 3); // 3 indices starting at 0 -> 1 triangle

		glDisableVertexAttribArray(0);

		// Swap buffers
		glfwSwapBuffers(window);
		glfwPollEvents();

	} // Check if the ESC key was pressed or the window was closed
	while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
		   glfwWindowShouldClose(window) == 0 );

	// Cleanup VBO
	glDeleteBuffers(1, &vertexbuffer);
	glDeleteVertexArrays(1, &VertexArrayID);
	glDeleteProgram(programID);

	// Close OpenGL window and terminate GLFW
	glfwTerminate();

	return 0;
}

 シェーダ関係のファイルは、

SimpleFragmentShader.fragmentshader
SimpleVertexShader.vertexshader
shader.cpp
shader.hpp

の4つです。shader.cppとshader.hppは、beginners-tutorialsの中のcommonというディレクトリにありますので、これらのファイルをコピーして、main.cppソースファイルと同じディレクトリに配置します。SimpleFragmentShader.fragmentshader、と、SimpleVertexShader.vertexshaderもコピーして、同じディレクトリに配置します。上記のmakefileも、同じディレクトリにコピーして、ターミナルのシェルプロンプトをこのディレクトリに移動します。$ make を実行します。


$ ./sample

を実行すると、以下のグラフィックス画像が表示されます。

triangle.png


 OpenGLでgameを作成するコードの構築に関する説明は、沼田 哲史さんのQuitaのWebsiteが参考になります。ただし、アップされているサンプルコードやそれぞれの説明において、各サイトごとにそれぞれOpenGLのバージョンが異なっていますので、注意が必要です。


このページの先頭へ戻る
WebGLのページへ行く
トップ・ページに行く