opengl チュートリアル
OpenGLを使い始める
サーチ…
備考
OpenGLは、2Dおよび3Dグラフィックスをグラフィックハードウェアを利用してレンダリングするためのオープンスタンダードです。 OpenGLは、さまざまなプラットフォームにまたがって実装されており、OpenGLをターゲットとしたアプリは非常に柔軟性があります。
バージョン
バージョン | 発売日 |
---|---|
1.1 | 1997-03-04 |
1.2 | 1998年03月16日 |
1.2.1 | 1998年10月14日 |
1.3 | 2001-08-14 |
1.4 | 2002年7月24日 |
1.5 | 2003年7月29日 |
2.0 | 2004-09-07 |
2.1 | 2006年7月2日 |
3.0 | 2008年8月11日 |
3.1 | 2009年3月24日 |
3.2 | 2009-08-03 |
3.3 | 2010-03-11 |
4.0 | 2010-03-11 |
4.1 | 2010-07-26 |
4.2 | 2011-08-08 |
4.3 | 2012-08-06 |
4.4 | 2013年7月22日 |
4.5 | 2014-08-11 |
OpenGLの入手
OpenGLに関する最も一般的な誤解の1つは、サードパーティのソースからインストールできるライブラリであるということです。この誤解は、「OpenGLをインストールする方法」または「OpenGL SDKをダウンロードする場所」の形式で多くの質問につながります。
これは、OpenGLがどのようにしてコンピュータシステムへの道を見出すのかではありません。 OpenGL自体は、インプリメンテーションがどのコマンドに従わなければならないかに関する仕様のセットにすぎません。したがって、重要な実装です。そして当面は、OpenGLの実装はGPUドライバの一部です。これは 、新しいGPUプログラミングインタフェースがOpenGLをライブラリとして真に実装できるようになってから将来変更されるかもしれませんが、現在はグラフィックスドライバ向けのプログラミングAPIです。
OpenGLが最初にリリースされたとき、APIは何とか元のSun Irixに加えて、Windows、Solaris、LinuxのABI(Application Binary Interface)契約(LSB-4 Desktop)にもどりました。 AppleはOpenGLをMacOS Xに組み込んでいて、OpenGLのバージョンはMacOS Xのバージョンと密接に結びついています。これは、これらのオペレーティングシステムのシステムプログラミング環境(つまり、これらのシステムをネイティブにターゲットとするコンパイラとリンカーツールチェーン) が OpenGL API定義をも提供しなければならないという顕著な効果があります。このようにOpenGL用のSDKを実際にインストールする必要はありません。ターゲットABIに続くビルド環境がインストールされていることを前提に、専用SDKをインストールする必要なく、これらのオペレーティングシステムでOpenGLをプログラムすることは技術的に可能です。
これらの厳密なABI規則の副作用は、バインディング・インターフェースを介して公開されたOpenGLバージョンが、ターゲット・プラットフォーム上で実行されるプログラムが利用可能であると期待できる最小公約数であることです。したがって、最新のOpenGL機能は、拡張メカニズムを介してアクセスされます。これについては、別途説明します。
Linux
Linuxでは、システムのさまざまな側面の開発パッケージをコンパイルして、個々に更新できるようにするのが一般的です。ほとんどのLinuxディストリビューションでは、OpenGLの開発ファイルは専用パッケージに含まれています。これは通常、デスクトップアプリケーション開発メタパッケージの依存関係です。 Linux用のOpenGL開発ファイルをインストールするには、通常、デスクトップ開発用メタパッケージ/ sのインストールが必要です。
マイクロソフトウィンドウズ
APIバインディングライブラリopengl32.dll
(Windowsの32ビット版と64ビット版の両方で使用されています)は、Windows NT-4とWindows 95B(どちらも1997年)以来、すべてのWindows版で出荷されています。ただし、このDLLは実際のOpenGL実装を提供していません(他のOpenGL実装がインストールされていない場合、プログラムのセーフティネットとして機能するソフトウェアフォールバックは別です)。このDLLはWindowsに属し、変更または移動してはいけません !最新のOpenGLバージョンは、いわゆるInstallable Client Driver (ICD)の一部として出荷され、Windowsの各バージョンにあらかじめインストールされているデフォルトのopengl32.dll
を通じてアクセスされます。しかし、 Windows Updateを通じてインストールされたグラフィックドライバは、OpenGL ICDをインストール/更新しないということは、Microsoftによって内部的に決定されました。自動的にインストールされたドライバを備えたWindowsの新しいインストールは、最新のOpenGL機能のサポートが欠けています。最新の機能を備えたOpenGL ICDを入手するには、グラフィックスドライバをGPUベンダーのWebサイトから直接ダウンロードし、手動でインストールする必要があります。
開発に関しては、特別な手順を講じる必要はありません。 Windows ABI仕様に準拠するすべてのC / C ++コンパイラには、OpenGLを使用する実行可能ファイルをビルドおよびリンクするために必要なヘッダとリンカスタブ(opengl32.lib)が付属しています。
WindowsでのOpenGLの手動設定
最後に完全なサンプルコードが含まれています
OpenGL用のWindowsコンポーネント
WGL
WGL( wiggleと発音することができます)は、Windows APIからOpenGLと通信する一連の関数である「WindowsとOpenGLの間のインターフェイス」のように、「Windows-GL」の略です。 WGL関数にはwgl接頭辞が付き、トークンにはWGL_接頭辞が付きます。
MicrosoftシステムでサポートされているデフォルトのOpenGLバージョンは1.1です。それは非常に古いバージョンです(最近のバージョンは4.5です)。最新のバージョンを入手する方法は、グラフィックドライバを更新することですが、グラフィックスカードは新しいバージョンをサポートする必要があります。
WGL関数の完全なリストは、 ここで見つけることができます 。
グラフィックデバイスインターフェイス(GDI)
GDI(GDI +に今日更新されました)は、Windowsのウィンドウに描画するための2D描画インターフェイスです。 OpenGLを初期化してOpenGLを操作できるようにするには、GDIが必要です(実際にはGDI自体は使用されません)。
GDIでは、各ウィンドウには、関数を呼び出すときに描画対象を特定するためのデバイスコンテキスト(DC)があります(パラメータとして渡します)。ただし、OpenGLは独自のレンダリングコンテキスト(RC)を使用します。したがって、DCはRCを作成するために使用されます。
基本設定
ウィンドウの作成
ですから、OpenGLで作業するにはRCが必要です.RCを取得するにはDCが必要で、DCを取得するにはウィンドウが必要です。 Windows APIを使用してウィンドウを作成するには、いくつかの手順が必要です。 これは基本的なルーチンなので、詳細な説明はWindows APIの使用ではないため、他のドキュメントを参照してください。
これには、WindowsのセットアップでWindows.h
含まれている必要があり、プログラムのエントリポイントがしなければならないWinMain
そのパラメータでプロシージャを。また、プログラムはopengl32.dll
とgdi32.dll
リンクする必要があります(64または32ビットシステムに関係なく)。
まず、 WNDCLASS
構造を使用してウィンドウを記述する必要があります。作成するウィンドウに関する情報が含まれています:
/* REGISTER WINDOW */
WNDCLASS window_class;
// Clear all structure fields to zero first
ZeroMemory(&window_class, sizeof(window_class));
// Define fields we need (others will be zero)
window_class.style = CS_OWNDC;
window_class.lpfnWndProc = window_procedure; // To be introduced later
window_class.hInstance = instance_handle;
window_class.lpszClassName = TEXT("OPENGL_WINDOW");
// Give our class to Windows
RegisterClass(&window_class);
/* *************** */
各フィールドの意味(およびフィールドの完全な一覧)の詳細については、MSDNのドキュメントを参照してください。
CreateWindowEx
を使用してウィンドウを作成できます。ウィンドウが作成されたら、そのDCを取得することができます:
/* CREATE WINDOW */
HWND window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OpenGL window"),
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
instance_handle,
NULL);
HDC dc = GetDC(window_handle);
ShowWindow(window_handle, SW_SHOW);
/* ************* */
最後に、OSからウィンドウイベントを受け取るメッセージループを作成する必要があります。
/* EVENT PUMP */
MSG msg;
while (true) {
if (PeekMessage(&msg, window_handle, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// draw(); <- there goes your drawing
SwapBuffers(dc); // To be mentioned later
}
/* ********** */
ピクセル形式
OpenGLは、色のビット数、バッファリング方法など、ウィンドウに関する情報を知る必要があります。このためには、 ピクセル形式を使用します 。しかし、我々は必要なピクセル形式の種類をOSに提案することができ、OSは最も類似したものを提供し 、直接制御することはできません。それが記述子と呼ばれるのはこのためです。
/* PIXEL FORMAT */
PIXELFORMATDESCRIPTOR descriptor;
// Clear all structure fields to zero first
ZeroMemory(&descriptor, sizeof(descriptor));
// Describe our pixel format
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER | PFD_SWAP_LAYER_BUFFERS;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = 32;
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;
descriptor.cAlphaBits = 8;
descriptor.cDepthBits = 32;
descriptor.cStencilBits = 8;
// Ask for a similar supported format and set it
int pixel_format = ChoosePixelFormat(dc, &descriptor);
SetPixelFormat(dc, pixel_format, &descriptor);
/* *********************** */
dwFlags
フィールドでダブルバッファリングを有効にしていdwFlags
ので、描画後に物を見るためにSwapBuffers
を呼び出す必要があります。
レンダリングコンテキスト
その後、レンダリングコンテキストを簡単に作成できます。
/* RENDERING CONTEXT */
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
/* ***************** */
一度に1つのスレッドしかRCを使用できないことに注意してください。後で別のスレッドから使用したい場合は、 wglMakeCurrent
呼び出して再度アクティブにする必要があります(これは、現在アクティブなスレッドで非アクティブになります)。
OpenGL関数の取得
OpenGL関数は、関数ポインタを使用して得られます。一般的な手順は次のとおりです。
- 何らかの形で関数ポインタ型(基本的に関数プロトタイプ)
- 使用したい各関数を関数ポインタ型で宣言する
- 実際の関数を取得する
たとえば、glBeginを考えてみましょう。
// We need to somehow find something that contains something like this,
// as we can't know all the OpenGL function prototypes
typedef void (APIENTRY *PFNGLBEGINPROC)(GLenum);
// After that, we need to declare the function in order to use it
PFNGLBEGINPROC glBegin;
// And finally, we need to somehow make it an actual function
(「PFN」は「関数へのポインタ」を意味し、OpenGL関数の名前に続き、最後には「PROC」、つまり通常のOpenGL関数のポインタ型名です)。
これはWindows上でどのように処理されるかです。前述のとおり、MicrosoftはOpenGL 1.1のみを出荷しています。まず、 GL/gl.h
することで、そのバージョンの関数ポインタ型を見つけることができます。その後、上記のように使用するすべての関数を宣言します(ヘッダーファイル内でこれを実行し、 "extern"と宣言すると、一度読み込んだ後にすべてを使用することができます)。最後に、OpenGL 1.1の機能をロードするには、DLLを開きます。
HMODULE gl_module = LoadLibrary(TEXT("opengl32.dll"));
/* Load all the functions here */
glBegin = (PFNGLBEGINPROC)GetProcAddress("glBegin");
// ...
/* *************************** */
FreeLibrary(gl_module);
しかし、おそらくOpenGL 1.1よりもほんの少しだけ望むでしょう。しかし、Windowsでは、関数プロトタイプやそれ以上の関数のエクスポートはできません。プロトタイプは、 OpenGLレジストリから取得する必要があります 。 :3つの私たちに興味のあるファイルがあるGL/glext.h
、 GL/glcorearb.h
、およびGL/wglext.h
。
Windowsが提供するGL/gl.h
を完成させるためには、 GL/gl.h
が必要GL/glext.h
。 「OpenGL 1.2以上の互換性プロファイルと拡張インタフェース」(この後のプロファイルと拡張機能については、実際にはこれらの2つのファイルを使用することをお勧めしません )。
実際の関数はwglGetProcAddress
によって取得する必要があります(この男のためにDLLを開く必要はありませんが、そこには存在しません)。これで、OpenGL 1.2以上(1.1ではなく)からすべての関数を取得できます。 OpenGLレンダリングコンテキストが適切に機能するためには、OpenGLレンダリングコンテキストを作成して最新のものにする必要があります 。たとえば、 glClear
:
// Include the header from the OpenGL registry for function pointer types
// Declare the functions, just like before
PFNGLCLEARPROC glClear;
// ...
// Get the function
glClear = (PFNGLCLEARPROC)wglGetProcAddress("glClear");
wglGetProcAddress
とGetProcAddress
両方を使用するラッパーget_proc
プロシージャーを実際に構築することができます。
// Get function pointer
void* get_proc(const char *proc_name)
{
void *proc = (void*)wglGetProcAddress(proc_name);
if (!proc) proc = (void*)GetProcAddress(gl_module, proc_name); // gl_module must be somewhere in reach
return proc;
}
まとめてみると、次のような関数ポインタ宣言でいっぱいのヘッダファイルを作成します。
extern PFNGLCLEARCOLORPROC glClearColor;
extern PFNGLCLEARDEPTHPROC glClearDepth;
extern PFNGLCLEARPROC glClear;
extern PFNGLCLEARBUFFERIVPROC glClearBufferiv;
extern PFNGLCLEARBUFFERFVPROC glClearBufferfv;
// And so on...
次に、 load_gl_functions
ようなプロシージャを作成して、一度だけ呼び出すことができます。
glClearColor = (PFNGLCLEARCOLORPROC)get_proc("glClearColor");
glClearDepth = (PFNGLCLEARDEPTHPROC)get_proc("glClearDepth");
glClear = (PFNGLCLEARPROC)get_proc("glClear");
glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)get_proc("glClearBufferiv");
glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)get_proc("glClearBufferfv");
そして、あなたはすべてセットです!関数ポインタとGLを含むヘッダーだけを含めてください。
より良いセットアップ
OpenGLプロファイル
OpenGLは20年以上もの間開発されてきており、開発者は常に後方互換性(BC)について厳格であった。そのため、新しい機能を追加することは非常に難しいです。したがって、2008年には2つの「プロファイル」に分離されました。 コアと互換性 。コアのプロファイルは、パフォーマンスの向上と新機能の一部を優先してBCを破ります。それはいくつかのレガシー機能を完全に削除します。互換性プロファイルでは、すべてのバージョンが1.0に下がってBCが維持され、いくつかの新機能は利用できません。これは旧式のレガシーシステムでのみ使用されるため、すべての新しいアプリケーションでコアプロファイルを使用する必要があります。
そのため、私たちの基本的なセットアップには問題があります。これは、OpenGL 1.0と下位互換性のあるコンテキストのみを提供します。ピクセル形式も制限されています。拡張機能を使って、より良いアプローチがあります。
OpenGL拡張
OpenGLの元の機能に加えて、拡張機能と呼ばれています。一般的には、これまでとは違うものを合法化したり、パラメータ値の範囲を拡張したり、GLSLを拡張したり、全く新しい機能を追加したりすることができます。
拡張には、ベンダ、EXT、ARBの3つの主要なグループがあります。ベンダー拡張は特定のベンダーから提供され、ベンダー固有のマーク(AMDやNVなど)を持っています。 EXT拡張は、複数のベンダーが協力して行います。しばらくすると、ARB拡張機能になります。これらはすべて正式にサポートされており、ARBの承認を受けています。
すべての拡張機能の関数ポインタ型と関数プロトタイプを取得するには、前述のように、OpenGL 1.2以降のすべての関数ポインタ型を OpenGLレジストリからダウンロードする必要があります 。説明したように、新しいアプリケーションのためには、コアプロファイルを使用することをお勧めしますので、含めてpreferrableだろうGL/glcorearb.h
代わりのGL/gl.h
およびGL/glext.h
使用している場合( GL/glcorearb.h
、その後ドンGL/gl.h
)。
GL/wglext.h
には、WGLの拡張もあります。たとえば、サポートされているすべての拡張機能のリストを取得する関数は、実際には拡張機能自体、 wglGetExtensionsStringARB
(サポートされているすべての拡張機能のスペース区切りのリストを含む大きな文字列を返します)です。
拡張機能の取得はwglGetProcAddress
でも処理されるので、以前と同じようにラッパーを使用することができます。
高度なピクセル形式とコンテキストの作成
WGL_ARB_pixel_format
拡張は、高度なピクセル形式の作成を可能にします。以前とは異なり、私たちは構造体を使用しません。代わりに、必要な属性のリストを渡します。
int pixel_format_arb;
UINT pixel_formats_found;
int pixel_attributes[] = {
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_DRAW_TO_BITMAP_ARB, 1,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_SWAP_LAYER_BUFFERS_ARB, 1,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 32,
WGL_STENCIL_BITS_ARB, 8,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
0
};
BOOL result = wglChoosePixelFormatARB(dc, pixel_attributes, NULL, 1, &pixel_format_arb, &pixel_formats_found);
同様に、 WGL_ARB_create_context
拡張を使用すると、高度なコンテキスト作成が可能になります。
GLint context_attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
HGLRC new_rc = wglCreateContextAttribsARB(dc, 0, context_attributes);
パラメータと関数の詳細については、OpenGL仕様を参照してください。
なぜ彼らと一緒に始めなかったのですか?さて、これは、 拡張が私たちにこれを可能にし、拡張を得るためにはwglGetProcAddress
が必要wglGetProcAddress
、これは有効な有効なコンテキストでのみ機能します。したがって本質的には、私たちが望むコンテキストを作成する前に、すでにいくつかのコンテキストをアクティブにする必要があります 。通常、 ダミーコンテキストと呼ばれます 。
ただし、Windowsでは、ウィンドウのピクセル形式を複数回設定することはできません。そのため、新しいものを適用するには、ウィンドウを破棄して再作成する必要があります。
wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);
// Recreate the window...
完全なコード例:
/* We want the core profile, so we include GL/glcorearb.h. When including that, then
GL/gl.h should not be included.
If using compatibility profile, the GL/gl.h and GL/glext.h need to be included.
GL/wglext.h gives WGL extensions.
Note that Windows.h needs to be included before them. */
#include <cstdio>
#include <Windows.h>
#include <GL/glcorearb.h>
#include <GL/wglext.h>
LRESULT CALLBACK window_procedure(HWND, UINT, WPARAM, LPARAM);
void* get_proc(const char*);
/* gl_module is for opening the DLL, and the quit flag is here to prevent
quitting when recreating the window (see the window_procedure function) */
HMODULE gl_module;
bool quit = false;
/* OpenGL function declarations. In practice, we would put these in a
separate header file and add "extern" in front, so that we can use them
anywhere after loading them only once. */
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
PFNGLGETSTRINGPROC glGetString;
int WINAPI WinMain(HINSTANCE instance_handle, HINSTANCE prev_instance_handle, PSTR cmd_line, int cmd_show) {
/* REGISTER WINDOW */
WNDCLASS window_class;
// Clear all structure fields to zero first
ZeroMemory(&window_class, sizeof(window_class));
// Define fields we need (others will be zero)
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
window_class.lpfnWndProc = window_procedure;
window_class.hInstance = instance_handle;
window_class.lpszClassName = TEXT("OPENGL_WINDOW");
// Give our class to Windows
RegisterClass(&window_class);
/* *************** */
/* CREATE WINDOW */
HWND window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OpenGL window"),
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
instance_handle,
NULL);
HDC dc = GetDC(window_handle);
ShowWindow(window_handle, SW_SHOW);
/* ************* */
/* PIXEL FORMAT */
PIXELFORMATDESCRIPTOR descriptor;
// Clear all structure fields to zero first
ZeroMemory(&descriptor, sizeof(descriptor));
// Describe our pixel format
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER | PFD_SWAP_LAYER_BUFFERS;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = 32;
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;
descriptor.cAlphaBits = 8;
descriptor.cDepthBits = 32;
descriptor.cStencilBits = 8;
// Ask for a similar supported format and set it
int pixel_format = ChoosePixelFormat(dc, &descriptor);
SetPixelFormat(dc, pixel_format, &descriptor);
/* *********************** */
/* RENDERING CONTEXT */
HGLRC rc = wglCreateContext(dc);
wglMakeCurrent(dc, rc);
/* ***************** */
/* LOAD FUNCTIONS (should probably be put in a separate procedure) */
gl_module = LoadLibrary(TEXT("opengl32.dll"));
wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)get_proc("wglGetExtensionsStringARB");
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)get_proc("wglChoosePixelFormatARB");
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)get_proc("wglCreateContextAttribsARB");
glGetString = (PFNGLGETSTRINGPROC)get_proc("glGetString");
FreeLibrary(gl_module);
/* ************** */
/* PRINT VERSION */
const GLubyte *version = glGetString(GL_VERSION);
printf("%s\n", version);
fflush(stdout);
/* ******* */
/* NEW PIXEL FORMAT*/
int pixel_format_arb;
UINT pixel_formats_found;
int pixel_attributes[] = {
WGL_SUPPORT_OPENGL_ARB, 1,
WGL_DRAW_TO_WINDOW_ARB, 1,
WGL_DRAW_TO_BITMAP_ARB, 1,
WGL_DOUBLE_BUFFER_ARB, 1,
WGL_SWAP_LAYER_BUFFERS_ARB, 1,
WGL_COLOR_BITS_ARB, 32,
WGL_RED_BITS_ARB, 8,
WGL_GREEN_BITS_ARB, 8,
WGL_BLUE_BITS_ARB, 8,
WGL_ALPHA_BITS_ARB, 8,
WGL_DEPTH_BITS_ARB, 32,
WGL_STENCIL_BITS_ARB, 8,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
0
};
BOOL result = wglChoosePixelFormatARB(dc, pixel_attributes, NULL, 1, &pixel_format_arb, &pixel_formats_found);
if (!result) {
printf("Could not find pixel format\n");
fflush(stdout);
return 0;
}
/* **************** */
/* RECREATE WINDOW */
wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
ReleaseDC(window_handle, dc);
DestroyWindow(window_handle);
window_handle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
TEXT("OPENGL_WINDOW"),
TEXT("OpenGL window"),
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
instance_handle,
NULL);
dc = GetDC(window_handle);
ShowWindow(window_handle, SW_SHOW);
/* *************** */
/* NEW CONTEXT */
GLint context_attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
rc = wglCreateContextAttribsARB(dc, 0, context_attributes);
wglMakeCurrent(dc, rc);
/* *********** */
/* EVENT PUMP */
MSG msg;
while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// draw(); <- there goes your drawing
SwapBuffers(dc);
}
/* ********** */
return 0;
}
// Procedure that processes window events
LRESULT CALLBACK window_procedure(HWND window_handle, UINT message, WPARAM param_w, LPARAM param_l)
{
/* When destroying the dummy window, WM_DESTROY message is going to be sent,
but we don't want to quit the application then, and that is controlled by
the quit flag. */
switch(message) {
case WM_DESTROY:
if (!quit) quit = true;
else PostQuitMessage(0);
return 0;
}
return DefWindowProc(window_handle, message, param_w, param_l);
}
/* A procedure for getting OpenGL functions and OpenGL or WGL extensions.
When looking for OpenGL 1.2 and above, or extensions, it uses wglGetProcAddress,
otherwise it falls back to GetProcAddress. */
void* get_proc(const char *proc_name)
{
void *proc = (void*)wglGetProcAddress(proc_name);
if (!proc) proc = (void*)GetProcAddress(gl_module, proc_name);
return proc;
}
g++ GLExample.cpp -lopengl32 -lgdi32
とMinGW / Cygwinまたはcl GLExample.cpp opengl32.lib gdi32.lib user32.lib
とMSVCコンパイラでコンパイルします。ただし、OpenGLレジストリのヘッダーがインクルードパスに含まれていることを確認してください。そうでない場合は、コンパイラにどこにあるかを伝えるために、 g++
には-I
フラグ/I
、 cl
は/I
を使用します。
C ++とCocoaでOpenGL 4.1を作成する
注:この例ではObjective-cがいくつかあります。この例ではC ++のラッパーを作成しますので、あまり心配しないでください。
最初にXcodeを起動し、プロジェクトを作成します。
Info.plistファイル以外のすべてのソースを削除してください(あなたのアプリはそれなしでは動作しません)
4つの新しいソースファイルを作成しましょう:Objective-c ++のファイルとヘッダ(私はMacbookと呼ばれています)C ++クラス(私はmine(Application)
左上に(プロジェクト名で)それをクリックし、リンクされたフレームワークとライブラリを追加します。追加:OpenGL.Framework AppKit.Framework GLKit.Framework
あなたのプロジェクトはおそらく次のようになります:
NSApplicationは、MacOSアプリケーションを作成する際に使用するメインクラスです。それはあなたがウィンドウを登録し、イベントをキャッチすることができます。
NSApplicationに(独自の)ウィンドウを登録します。 NSWindowを継承し、 NSApplicationDelegateを実装する目的のC ++ヘッダーを作成します。NSWindowには、C ++アプリケーションへのポインタ、OpenGLビュー、描画ループのタイマーが必要です
//Mac_App_H
#import <Cocoa/Cocoa.h>
#import "Application.hpp"
#import <memory>
NSApplication* application;
@interface MacApp : NSWindow <NSApplicationDelegate>{
std::shared_ptr<Application> appInstance;
}
@property (nonatomic, retain) NSOpenGLView* glView;
-(void) drawLoop:(NSTimer*) timer;
@end
私たちはこれをメインから
int main(int argc, const char * argv[]) {
MacApp* app;
application = [NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
//create a window with the size of 600 by 600
app = [[MacApp alloc] initWithContentRect:NSMakeRect(0, 0, 600, 600) styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask backing:NSBackingStoreBuffered defer:YES];
[application setDelegate:app];
[application run];
}
私たちのウィンドウの実装は実際にはとても簡単です。まず、glviewを合成して宣言し、ウィンドウが閉じるべきときにグローバルなobjective-cブール値を追加します。
#import "MacApp.h"
@implementation MacApp
@synthesize glView;
BOOL shouldStop = NO;
今コンストラクタのために。私の好みは、initWithContentRectを使用することです。
-(id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag{
if(self = [super initWithContentRect:contentRect styleMask:aStyle backing:bufferingType defer:flag]){
//sets the title of the window (Declared in Plist)
[self setTitle:[[NSProcessInfo processInfo] processName]];
//This is pretty important.. OS X starts always with a context that only supports openGL 2.1
//This will ditch the classic OpenGL and initialises openGL 4.1
NSOpenGLPixelFormatAttribute pixelFormatAttributes[] ={
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFAColorSize , 24 ,
NSOpenGLPFAAlphaSize , 8 ,
NSOpenGLPFADoubleBuffer ,
NSOpenGLPFAAccelerated ,
NSOpenGLPFANoRecovery ,
0
};
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]initWithAttributes:pixelFormatAttributes];
//Initialize the view
glView = [[NSOpenGLView alloc]initWithFrame:contentRect pixelFormat:format];
//Set context and attach it to the window
[[glView openGLContext]makeCurrentContext];
//finishing off
[self setContentView:glView];
[glView prepareOpenGL];
[self makeKeyAndOrderFront:self];
[self setAcceptsMouseMovedEvents:YES];
[self makeKeyWindow];
[self setOpaque:YES];
//Start the c++ code
appInstance = std::shared_ptr<Application>(new Application());
}
return self;
}
さて、私たちは実際に実行可能なアプリを持っています。あなたは黒い画面やちらつきを見るかもしれません。
すごい三角形を描き始めましょう。(C ++で)
私のアプリケーションヘッダー
#ifndef Application_hpp
#define Application_hpp
#include <iostream>
#include <OpenGL/gl3.h>
class Application{
private:
GLuint program;
GLuint vao;
public:
Application();
void update();
~Application();
};
#endif /* Application_hpp */
実装:
Application::Application(){
static const char * vs_source[] =
{
"#version 410 core \n"
" \n"
"void main(void) \n"
"{ \n"
" const vec4 vertices[] = vec4[](vec4( 0.25, -0.25, 0.5, 1.0), \n"
" vec4(-0.25, -0.25, 0.5, 1.0), \n"
" vec4( 0.25, 0.25, 0.5, 1.0)); \n"
" \n"
" gl_Position = vertices[gl_VertexID]; \n"
"} \n"
};
static const char * fs_source[] =
{
"#version 410 core \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(0.0, 0.8, 1.0, 1.0); \n"
"} \n"
};
program = glCreateProgram();
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, fs_source, NULL);
glCompileShader(fs);
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, vs_source, NULL);
glCompileShader(vs);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
}
void Application::update(){
static const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, green);
glUseProgram(program);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
Application::~Application(){
glDeleteVertexArrays(1, &vao);
glDeleteProgram(program);
}
今は更新を何度も呼び出す必要があります(移動するものが必要な場合)。目的で実装します-cクラス
-(void) drawLoop:(NSTimer*) timer{
if(shouldStop){
[self close];
return;
}
if([self isVisible]){
appInstance->update();
[glView update];
[[glView openGLContext] flushBuffer];
}
}
そして、このメソッドをあなたのobjective-cクラスの実装に追加してください:
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
[NSTimer scheduledTimerWithTimeInterval:0.000001 target:self selector:@selector(drawLoop:) userInfo:nil repeats:YES];
}
これはあなたのC ++クラスの更新関数を繰り返し呼び出すでしょう(正確にはそれぞれ0.000001秒です)
終了するには、閉じるボタンを押したときにウィンドウを閉じます。
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication{
return YES;
}
- (void)applicationWillTerminate:(NSNotification *)aNotification{
shouldStop = YES;
}
おめでとう、サードパーティーのフレームワークを持たないOpenGLの三角形のすばらしい窓ができました。
クロスプラットフォームOpenGLコンテキストの作成(SDL2を使用)
OpenGLコンテキストでのウィンドウの作成( GLEWによる拡張ロード):
#define GLEW_STATIC #include <GL/glew.h> #include <SDL2/SDL.h> int main(int argc, char* argv[]) { SDL_Init(SDL_INIT_VIDEO); /* Initialises Video Subsystem in SDL */ /* Setting up OpenGL version and profile details for context creation */ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); /* A 800x600 window. Pretty! */ SDL_Window* window = SDL_CreateWindow ( "SDL Context", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_OPENGL ); /* Creating OpenGL Context */ SDL_GLContext gl_context = SDL_GL_CreateContext(window); /* Loading Extensions */ glewExperimental = GL_TRUE; glewInit(); /* The following code is for error checking. * If OpenGL has initialised properly, this should print 1. * Remove it in production code. */ GLuint vertex_buffer; glGenBuffers(1, &vertex_buffer); printf("%u\n", vertex_buffer); /* Error checking ends here */ /* Main Loop */ SDL_Event window_event; while(1) { if (SDL_PollEvent(&window_event)) { if (window_event.type == SDL_QUIT) { /* If user is exiting the application */ break; } } /* Swap the front and back buffer for flicker-free rendering */ SDL_GL_SwapWindow(window); } /* Freeing Memory */ glDeleteBuffers(1, &vertex_buffer); SDL_GL_DeleteContext(gl_context); SDL_Quit(); return 0; }
MacOS上の最新のOpenGL 4.1をセットアップする(Xcode、GLFW、およびGLEW)
1. GLFWをインストールする
最初のステップは、OpenGLウィンドウを作成することです。 GLFWはOpenGLを使用してウィンドウを作成するためのオープンソースのマルチプラットフォームライブラリで、GLFWをインストールするにはまずwww.glfw.orgからファイルをダウンロードします
GLFWフォルダを抽出すると、その内容は次のようになります
GLakeをビルドするためにCMakeをダウンロードしてインストールします。 www.cmake.org/download/に進み 、CMakeをダウンロードしてMAC OS X用にインストールしてください
Xcodeがインストールされていない場合Mac App StoreからXcodeをダウンロードしてインストールします。
新しいフォルダを作成するGLFWフォルダ内にビルドする
CMakeを開き、[ ソースの参照 ]ボタンをクリックしてGLFWフォルダを選択します(CMakeLists.txtがそのフォルダ内にあることを確認してください)。その後、[ ビルドの参照 ]ボタンをクリックし、前の手順で新しく作成したビルドフォルダを選択します。
今すぐ[ 設定 ]ボタンをクリックし、[ デフォルトのネイティブコンパイラを使用する]オプションを使用して Xcodeをジェネレータとして選択し、[ 完了 ]をクリックします。
BUILD_SHARED_LIBSオプションをオンにして、 Configureボタンをもう一度クリックし、最後にGenerateボタンをクリックします。
世代の後CMakeはこのように見えるはずです
Finderを開いて/ usrに移動し、まだ存在しない場合はローカルのフォルダ名を作成します。 ローカルフォルダを開き、2つのフォルダとlibがまだ存在しない場合は作成します。
GLFWフォルダを開き、 Build (CMakeがファイルをビルドした場所)に移動します。 XcodeでGLFW.xcodeprojファイルを開きます。
「 インストール」>「Mac」を選択して、「 実行」をクリックします。
これで正常にインストールされます(警告は無視されます)。
Open Finderと/ usr / local / libフォルダと3つのGLFWライブラリファイルがすでにそこに存在することを確認するには(GLFWフォルダ内のBuildフォルダを開き、 src / Debugに移動してすべてのファイルを/ usr / local / libにコピーします)
Finderを開いて/ usr / local / includeに移動すると、 glfw3.hとglfw3native.hという名前でその中に2つのヘッダファイルがあるGLFWフォルダが既に存在します
2. GLEWをインストールする
GLEWは、OpenGL拡張のクエリと読み込みに役立つクロスプラットフォームのライブラリです。ターゲットプラットフォーム上でどのOpenGL拡張がサポートされているかを決定する実行時のメカニズムを提供します。最新のOpenGL(OpenGLバージョン3.2以降では、実行時に関数を決定する必要があります)のみです。インストールするには、最初にglew.sourceforge.netからファイルをダウンロードしてください
GLFWフォルダを抽出すると、その内容は次のようになります。
ターミナルを開き、GLEW Folderに移動し、次のコマンドを入力します
make
sudo make install
make clean
今すぐGLEWが正常にインストールされました。インストールされているOpen Finderを確認するには、 / usr / local / includeに移動します.GLWフォルダにはすでに3つのヘッダファイルが存在し、その中にglew.h 、 glxew.h 、 wglew.h
Finderを開いて/ usr / local / libに移動し 、GLEWライブラリファイルが既にそこに存在するはずです
3.テストと実行
GLFWとGLEWを正常にインストールしました。コードする時間。 Xcodeを開き、新しいXcodeプロジェクトを作成します。 コマンドラインツールを選択し、次へ進み、 C ++を言語として選択します。
Xcodeは新しいコマンドラインプロジェクトを作成します。
プロジェクト名をクリックし、 ビルド設定タブで基本 パス から全 パス へ 、 検索パスのセクションでヘッダー検索パスに/ usr / local / includeを追加し、ライブラリ検索パスに/ usr / local / libを追加します
プロジェクト名をクリックし、 ビルド段階タブでバイナリライブラリとのリンクで OpenGL.frameworkを追加し、最近作成されたGLFWとGLEWライブラリを/ usr / local / libから追加します
これで、C ++とXcodeを使用して、MacOS上のModern Open GL 4.1でコーディングする準備が整いました。次のコードは、空白の画面出力でGLFWを使用してOpenGLウィンドウを作成します。
#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;
}
JavaとLWJGL 3.0を使ってOpenGLコンテキストを作成する
このサンプルコードでは、LWJGL 3.0+を使用して空のOpenGLウィンドウを作成しますが、IDEにプロジェクトを作成する手順は含まれていません
- スクリーン上にOpenGLコンテキストウィンドウを作成するためのボイラープレートコードをすべて含むクラス名WindowManagerを作成します
WindowManager.java
import org.lwjgl.glfw.*;
import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.system.MemoryUtil.*;
/**
* Class Containing code related to inflating Opengl Window
*/
public class Displaymanager {
private static long window;
public static void createDisplay(){
// Setup an error callback. The default implementation
// will print the error message in System.err.
GLFWErrorCallback.createPrint(System.err).set();
// Initialize GLFW. Most GLFW functions will not work before doing this.
if ( !glfwInit() )
throw new IllegalStateException("Unable to initialize GLFW");
// Configure our window
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
int WIDTH = 300;
int HEIGHT = 300;
// Create the window
window = glfwCreateWindow(WIDTH, HEIGHT, "Hello World!", NULL, NULL);
if ( window == NULL )
throw new RuntimeException("Failed to create the GLFW window");
// Setup a key callback. It will be called every time a key is pressed, repeated or released.
glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
glfwSetWindowShouldClose(window, true); // We will detect this in our rendering loop
});
// Get the resolution of the primary monitor
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
// Center our window
glfwSetWindowPos(
window,
(vidmode.width() - WIDTH) / 2,
(vidmode.height() - HEIGHT) / 2
);
// Make the OpenGL context current
glfwMakeContextCurrent(window);
// Enable v-sync
glfwSwapInterval(1);
// Make the window visible
glfwShowWindow(window);
}
public static boolean isCloseRequested(){
return glfwWindowShouldClose(window);
}
public static void updateDisplay(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
glfwSwapBuffers(window); // swap the color buffers
// Poll for window events. The key callback above will only be
// invoked during this call.
glfwPollEvents();
}
public static void destroyDisplay(){
// Terminate GLFW and free the error callback
cleanUp();
glfwTerminate();
glfwSetErrorCallback(null).free();
}
private static void cleanUp() {
// Free the window callbacks and destroy the window
glfwFreeCallbacks(window);
glfwDestroyWindow(window);
}
}
- 次に、メインレンダリングループを含むクラスを作成します。このクラスは、作成されたすべての関数を呼び出します
OpenGlMain.java
import org.lwjgl.opengl.GL;
import renderEngine.Displaymanager;
import static org.lwjgl.opengl.GL11.glClearColor;
/**
* Class to test the opengl Window
*/
public class OpenGlMain {
public static void main(String[] args) {
Displaymanager.createDisplay();
// This line is critical for LWJGL's interoperation with GLFW's
// OpenGL context, or any context that is managed externally.
// LWJGL detects the context that is current in the current thread,
// creates the GLCapabilities instance and makes the OpenGL
// bindings available for use.
GL.createCapabilities();
while (!Displaymanager.isCloseRequested()){
// Set the clear color
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
Displaymanager.updateDisplay();
}
Displaymanager.destroyDisplay();
}
}
詳細なチェックアウトの詳細については、公式LWJGLガイド