Loading [MathJax]/extensions/tex2jax.js

2015年6月14日日曜日

HD Graphics 3000 でコンピュートシェーダーを使う

DirectX 10.1 のハードでのコンピュートシェーダーを試したくて Sandy Bridge なマシン(ThinkPad T420, i5-2540M)をゲットしたんですが、 どうもちょっと古いビデオドライバでないと使えないようでした。いくつかのバージョンを試した中で使えたのはこれのみでした。

Windows Vista 64 ビット版用インテルR HD グラフィックス・ドライバー (exe 実行形式)
ファイル名: Win7Vista_64_152254.exe
バージョン: 15.22.54.64.2622
日付: 2012/01/21 
サイズ: 83.17 MB 
言語: マルチ・ランゲージ
オペレーティング・システム: Windows Vista 64

以下のは全部ダメでした。

Windows 7 / 8 / 8.1 64 ビット版用インテルR HD グラフィックス・ドライバー
ファイル名: win64_152822.exe
バージョン: 15.28.22.64.3517
日付: 2014/04/10 
サイズ: 138.68 MB 
言語: マルチ・ランゲージ
オペレーティング・システム: Windows 7 (64-bit), Windows 8, 64 ビット, Windows 8.1, 64 ビット

Windows 7 / 8 / 8.1 64 ビット版用インテルR HD グラフィックス・ドライバー
ファイル名: win64_152823.exe
バージョン: 15.28.23.64.4101
日付: 2015/02/04 
サイズ: 125.03 MB 
言語: マルチ・ランゲージ
オペレーティング・システム: Windows 7 (64-bit), Windows 8, 64 ビット, Windows 8.1, 64 ビット

IntelR HD Graphics Driver for Windows 7/8/8.1 64-bit
ファイル名: win64_152824.exe
バージョン: 15.28.24.64.4229
日付: 2015/06/05 
サイズ: 125.67 MB 
言語: マルチ・ランゲージ
オペレーティング・システム: Windows 7 (64-bit), Windows 8, 64 ビット, Windows 8.1, 64 ビット

2015年3月24日火曜日

Ctrl-Caps, Alt-Win 入れ替え

Ctrl と Caps, 左右の Alt と Win を入れ替えるためのレジストリです。 Bootcamp 環境で Apple のキーボードを使うにつかってます。
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,07,00,00,00,1d,00,3a,00,3a,00,1d,00,5b,e0,38,00,38,00,5b,e0,5c,e0,38,e0,38,e0,5c,e0,00,00,00,00

2015年3月19日木曜日

やり直しのための信号数学: 第 2 章 正規直交基底とディジタル信号解析

2.1 正規直交基底とは

今度は 4 個のサンプルから成るサンプル列を扱う場合、つまり 4 次元の場合の話。 ここでは N 次元のノルムの定義に \[ \| \boldsymbol{x} \| = \sqrt{ \frac{1}{N} \sum_{i=0}^{N-1}{x_i}^2 } \] を使う。こうしておくと次元数に関わらず全ての要素が 1 のベクトルは大きさ(ノルム)が 1 として扱えて便利だかららしい。 また、このノルムの定義を使う場合、内積の定義は \[ \langle \boldsymbol{x}, \boldsymbol{y} \rangle = \frac{1}{N} \sum_{i=0}^{N-1}x_i y_i \] を使う。こうしておくと内積とノルムの一般的な関係 \[ \langle \boldsymbol{x}, \boldsymbol{x} \rangle = {\| \boldsymbol{x} \|}^2 \] が成り立つ。

とにかく、この前提のもとでは次のベクトルの組 \[ \begin{align*} \boldsymbol{\phi}^{(0)} &= \{1, 1, 1, 1 \} \\ \boldsymbol{\phi}^{(1)} &= \{1, 1, -1, -1 \} \\ \boldsymbol{\phi}^{(2)} &= \{1, -1, -1, 1 \} \\ \boldsymbol{\phi}^{(3)} &= \{1, -1, 1, -1 \} \end{align*} \] が正規直交基底となる。計算してみればこれらのベクトルのノルムは 1, 相異なる 2 つのベクトルの内積は 0 になる。 この 4 つのベクトルはもちろん適当に選んだわけではなく、"アダマール変換"に関連するものらしい。

2.2 正規直行規定によるディジタル信号分解

何かを測定して 4 個のディジタル値のサンプル \( \{ f_0, f_1, f_2, f_3 \} \) を得たとする。 これらを成分とするベクトル \( \boldsymbol{f} \) は(もちろん)先の正規直交基底ベクトルの線形結合として表すことができ、 \[ \boldsymbol{f} = F_0 \boldsymbol{\phi}^{(0)} + F_1 \boldsymbol{\phi}^{(1)} + F_2 \boldsymbol{\phi}^{(2)} + F_3 \boldsymbol{ \phi}^{(3)} \] となったする。ここで \( F_k (k = 0, 1, 2, 3) \) は正規直交基底ベクトルとの内積で \[ F_k = \langle \boldsymbol{f}, \boldsymbol{\phi}^{(k)} \rangle (k = 0, 1, 2, 3) \tag{1} \] から求められる。このように 1 次結合で表すことを「直行展開する」という。この意味深な正規直交基底ベクトルで直行展開することが「ディジタル信号の分解」ということになるらしい。

式 (1) につして \( k = 0 \) の場合、 \[ \begin{align*} F_0 &= \langle \boldsymbol{f}, \boldsymbol{\phi}^{(0)} \rangle \\ &= \langle \{ f_0, f_1, f_2, f_3 \}, \{ 1, 1, 1, 1 \} \rangle \\ &= \frac{1}{4} ( 1 \cdot f_0 + 1 \cdot f_1 + 1 \cdot f_2 + 1 \cdot f_3 ) \\ &= \frac{1}{4} ( f_0 + f_1 + f_2 + f_3 ) \end{align*} \] となる。同様に、 \[ \begin{align*} F_1 &= \frac{1}{4} ( f_0 + f_1 - f_2 - f_3 ) \\ F_2 &= \frac{1}{4} ( f_0 - f_1 - f_2 + f_3 ) \\ F_3 &= \frac{1}{4} ( f_0 - f_1 + f_2 - f_3 ) \\ \end{align*} \] となる。

2.3 正規直交基底によるディジタル信号合成

自明だが、直交展開した係数がわかれば、 \[ \boldsymbol{f} = F_0 \boldsymbol{\phi}^{(0)} + F_1 \boldsymbol{\phi}^{(1)} + F_2 \boldsymbol{\phi}^{(2)} + F_3 \boldsymbol{ \phi}^{(3)} \] よりもとのベクトル、つまりもとのディジタル信号を合成できる。これは \[ \boldsymbol{f} = \langle \boldsymbol{f}, \boldsymbol{\phi}^{(0)} \rangle \boldsymbol{\phi}^{(0)} + \langle \boldsymbol{f}, \boldsymbol{\phi}^{(1)} \rangle \boldsymbol{\phi}^{(1)} + \langle \boldsymbol{f}, \boldsymbol{\phi}^{(2)} \rangle \boldsymbol{\phi}^{(2)} + \langle \boldsymbol{f}, \boldsymbol{\phi}^{(3)} \rangle \boldsymbol{\phi}^{(3)} \] とも表される。この \( \boldsymbol{f} \) の各成分 \( f_k (k = 0, 1, 2, 3) \) は \[ f_k = \langle \boldsymbol{f}, \boldsymbol{\phi}^{(0)} \rangle \phi_k^{(0)} + \langle \boldsymbol{f}, \boldsymbol{\phi}^{(1)} \rangle \phi_k^{(1)} + \langle \boldsymbol{f}, \boldsymbol{\phi}^{(2)} \rangle \phi_k^{(2)} + \langle \boldsymbol{f}, \boldsymbol{\phi}^{(3)} \rangle \phi_k^{(3)} \] となる。( \( \phi_k^{(n)} \) はスカラーであることに注意。)

2.4 波形の類似性と相関値

1 章で軽く触れた相関値について再び。ここからは二つの N サンプルのディジタル信号 \( \boldsymbol{f} = \{ f_0, f_1, \cdots, f_{N-1} \} \) と \( \boldsymbol{g} = \{ g_0, g_1, \cdots, g_{N-1} \} \) の相関値を \[ R^{(fg)} = \frac{ \langle \boldsymbol{f}, \boldsymbol{g} \rangle }{ \|\boldsymbol{f}\| \|\boldsymbol{g}\| } \] と表す。(繰り返しになるがこれは \( \boldsymbol{f} \) と \( \boldsymbol{g} \) のなす角の \( cos(\theta) \) と同じ。) これに(この本が使っている)内積、ノルムを代入すると \[ \begin{align*} R^{(fg)} &= \frac{ \frac{1}{N} \sum_{i=0}^{N-1} f_i g_i }{ \sqrt{ \frac{1}{N} \sum_{i=0}^{N-1}{f_i}^2 } \sqrt{ \frac{1}{N} \sum_{i=0}^{N-1}{g_i}^2 } } \\ &= \frac{ \sum_{i=0}^{N-1} f_i g_i }{ \sqrt{ \sum_{i=0}^{N-1}{f_i}^2 } \sqrt{ \sum_{i=0}^{N-1}{g_i}^2 } } \end{align*} \] となる。

周期関数の一周期分の信号(サンプル値のベクトル) \( \boldsymbol{f} = \{ f_0, f_1, \cdots, f_{N-1} \} \) とこれを N 倍した信号 \( \boldsymbol{g} = N \boldsymbol{f} \) の相関係数は 1 になるが、定数 C を加えた信号 \( \boldsymbol{h}: h_i = f_i + C \) との相関係数は(同じ形の信号なのに) 1 にならない。 これが 1 になるようにするには、各サンプル値からサンプル値の平均を引いたベクトルを使って相関係数をもとめればいい。 (単に \( \boldsymbol{f} \) も \( \boldsymbol{g} \) 波形の震央が 0 になるように調整してから相関係数を求めれば OK という話。)

2.5 相関値の見方

\( \boldsymbol{R}^{(fg)} = 1 \) 同相
\( \boldsymbol{R}^{(fg)} > 0 \) 進み位相 ( \( \boldsymbol{g} \) が進んでいる)
\( \boldsymbol{R}^{(fg)} = 0 \) 相関なし (位相が \( \pm \frac{\pi}{2} \) ずれている)
\( \boldsymbol{R}^{(fg)} < 0 \) 遅れ位相 ( \( \boldsymbol{g} \) が遅れている)
\( \boldsymbol{R}^{(fg)} = -1 \) 逆相

2.6 相互相関係数

二つの似た波形についてどれだけ位相がずれているかを評価するには、相互相関係数 \[ \tilde{R}_n^{(fg)} = \frac{ \sum_{i=0}^{N-1} f_i g_{i+n} }{ \sqrt{ \sum_{i=0}^{N-1}{f_i}^2 } \sqrt{ \sum_{i=0}^{N-1}{g_{i+n}}^2 } } \] を使う。これは n サンプル分を位相をずらしてみた相関係数ということになる。これを \( n = 0, \dots, N - 1 \) まで N 個求めてみて、値が一番大きく(理想的には 1)なったときの n が位相のずれ幅。

2.7 自己相関係数

ある信号に周期性があるのか、あるならばその周期がどれだけなのかしりたい場合は \( \boldsymbol{f} = \{ f_0, f_1, \cdots, f_{N-1} \} \) と n サンプルずらした \( \boldsymbol{\tilde{f}} = \{ f_{0+n}, f_{1+n}, \cdots, f_{N-1+n} \} \) について自己相関係数 \[ \begin{align*} \tilde{R}_n^{(ff)} &= \frac{ \frac{1}{N} \sum_{i=0}^{N-1} f_i f_{i+n} }{ \sqrt{ \frac{1}{N} \sum_{i=0}^{N-1} {f_i}^2 } \sqrt{ \frac{1}{N} \sum_{i=0}^{N-1} {f_{i+n}}^2 }} \\ &= \frac{ \frac{1}{N} \sum_{i=0}^{N-1} f_i f_{i+n} }{ \frac{1}{N} \sum_{i=0}^{N-1} {f_i}^2 } \\ &= \frac{ \sum_{i=0}^{N-1} f_i f_{i+n} }{ \sum_{i=0}^{N-1} {f_i}^2 } \end{align*} \] の n を 0 から N-1 まで変化させながら求めてみる。その結果に周期的な極大が現れれば、周期関数であり、その周期がもとの信号の周期になる。

余談

MathJax すげー!と思ってこの本の理解を整理するために書き始めたけど、やっぱり数式打つのが面倒になってきた...

それでも Web の世界で(画像を貼り付けるような面倒で残念な方法をつかったり、環境依存な手段をつかわずとも)まっとうに数式を記述できるようにした MathJax は偉大だと思う。 逆になぜ今まで科学論文から始まった Web の世界にまっとうな数式記述手段がなかったんだろう? Web の世界が急速に成長を始めたころには既にアカデミックなコミュニティはニッチな世界になってたから?

2015年3月13日金曜日

やり直しのための信号数学: 第 1 章 信号数学の準備

本業で必要になって...

1.3 信号数学の予備知識

ある信号 \( x(t), y(t) \) を 2 回サンプリングしてサンプル列 \( (x_0, x_1), (y_0, y_1) \) を得たとする。 これは 2 次元のベクトル \( \boldsymbol{x} = (x_0, x_1), \boldsymbol{y} = (y_0, y_1)\) を得たと考えることができる。 これらの信号の相関、つまりこれらのベクトルの相関を考える。 これらのベクトルの特徴の一つとして大きさを考えることができる。 この大きさの差 \[ d(\boldsymbol{x}, \boldsymbol{y}) = \|\boldsymbol{x} - \boldsymbol{y}\| = \sqrt{(x_0 - y_0)^2 + (x_1 - y_1)^2} \] がこれらのベクトル、つまり信号の相関を表す量の一つということになる。 (この縦 2 本線の絶対値はノルムといい、N 次元ベクトルのより一般化した大きさに相当する量になる。 ここでは通常の絶対値と同じ定義を使っているが、ノルムの要件を満たせば異なる、より都合のいい定義を使うこともできる。実際、後で違う定義が出てくる。)

さて、この 2 つのベクトルの成す角度もこれらのベクトル、2 つの信号の相関と考えることができる。 (同じ方向を向いていれば完全に相関がある、\( \pi / 2 \) 違う方向を向いていれば全く相関がないと考える。) 内積の定義 \[ \langle \boldsymbol{x}, \boldsymbol{y} \rangle = \|\boldsymbol{x}\| \|\boldsymbol{y}\| cos(\theta) \] より \[ cos(\theta) = \frac{ \langle \boldsymbol{x}, \boldsymbol{y} \rangle }{ \|\boldsymbol{x}\| \|\boldsymbol{y}\| } \] がこの相関を表す量ということになる。 この量を \( r \) と置き、相関係数と呼ぶ。 \( r \) が 1 なら完全な相関, 0 なら相関なし、-1 なら負の相関ということになる。

任意のベクトル \( \boldsymbol{x} \) を正規直交基底ベクトル \( { \boldsymbol{e_1}, \boldsymbol{e_2} } \) の線形結合 \( \boldsymbol{x} = x_1\boldsymbol{e_1} + x_2\boldsymbol{e_2} \) として表すには \( (x_1, x_2) \) を \[ x_1 = \langle \boldsymbol{x}, \boldsymbol{e_1} \rangle \\ x_2 = \langle \boldsymbol{x}, \boldsymbol{e_2} \rangle \] として求めればよい。

プログラミング言語 C++ 第 5 章

メモ_φ(・_・

第 5 章 C++ を探検しよう : 並列処理とユーティリティ

プログラミング言語 C++ 第 4 章

メモ_φ(・_・

第 4 章 C++ を探検しよう : コンテナとアルゴリズム

  • こんな書き方が!これは捗る:
    vector phone_book = {
      {"David Hume", 123456"},
      {"Karl Popper", 234567},
      {"Bertrand Arthur William Russell", 345678}
    };
  • std::map はキーを大小比較することで目的の要素を探す。std::unordered_map はキーのハッシュ値を使って目的の要素を探す。

2015年3月6日金曜日

プログラミング言語 C++ 第 2 章、第 3 章

メモ_φ(・_・

第 2 章 C++ を探検しよう : 基本

  • これが新しい初期化構文か:
    double d2 {2.3};
  • コンパイラはどうやってコンパイル時に constexpr 関数を実行するんだろうか?クロスコンパイルの場合にはライブラリのオブジェクトファイル内の実装を実行してみることもできないし。インライン関数みたいにヘッダファイル内に実装も書いておくんだろうか?
  • 宣言時に使用する、&、*、[] などの演算子は、宣言演算子と呼ばれる。
  • enum class はメンバ関数を持てる。
  • 確かに: 厳密に言えば、分割コンパイルの仕組みは、言語そのものとは無関係であって、...

第3章 C++ を探検しよう : 抽象化のメカニズム

  • 初期化構文は std::initializer_list 型で受け取る。
  • "ムーブ"ってそういうことか。
  • =delete という関数修飾をつけると暗黙的に作成される関数を削除できる。
  • using を使う typedef の新しい構文ができた。
  • 実際、標準ライブラリのすべてのコンテナは、自身の保持する値の型の名前として value_type を提供する。

2015年3月5日木曜日

プログラミング言語 C++ 第 1 章

値段も厚さもすごいけど、今メインで使っているのが C++ なので買わずにいられなかった。

まずは「第1章 本書の読み進め方」を読んだ。気になった点として:

  • C99 の可変長配列は意図的に C++11 には取り込まれなかった。
  • 1980年の "C with Classes" には既にタスクライブラリがあった(!)が、C++11 で並行処理ライブラリが復活するまで 30 年もかかった!
  • 例外指定が obsolete になってた。
  • (メジャーなコンパイラは実装してないのでお目にかかったことはないけど)外部テンプレートも obsolete になってた。
  • iostream に Norihiro Kumagai さんという日本人がからんでる。(シャープの人?)
  • コンセプトなるものが C++17 で標準入りを目指している。
  • counted_ptr なんてあったの!?
  • Linux の主要部分が C++ で書かれているというのはちょっと違うんじゃないでしょうか?

旧版と比べると(今の所)訳がまっとうになってる感じで安心。

2015年3月4日水曜日

GLSL のコンパイルエラーメッセージにファイル名を含める

ソースコードの頭に #line ディレクティブでファイル名を書いておくと:

#version 430 core
#line 3 "append.fs.glsl"

layout(binding = 0, offset = 0) uniform atomic_uint fill_counter;
layout(binding = 0, r32i) coherent uniform uimage2D heap_pointer;

struct list_item {
 vec4 color;
 float depth;
 int facing;
 uint next;
};

layout(binding = 0, std430) buffer list_item_block {
 list_item item[];
}

in VS_OUT {
 vec4 pos;
 vec4 color;
} fs_in;

void main(void)
{
 ivec2 P = ivec2(gl_FragCoord.xy);
 uint index = atomicCounterIncrement(fill_counter);
 uint old_head = imageAtomicExchange(heap_pointer, P, index);
 item[index].color = fs_in.color;
 item[index].depth = gl_FragCoord.z;
 item[index].facing = gl_FontFacing ? 1 : 0;
 item[index].nex = old_head;
}

glGetShaderInfoLog() の出力にファイル名が出るようになる。

append.fs.glsl(5) : error C1318: can't apply layout(r32i) to image type "uimage2D"
append.fs.glsl(18) : error C0000: syntax error, unexpected reserved word "in" at token "in"
append.fs.glsl(21) : error C0000: syntax error, unexpected '}' at token "}"

#line の次の数値は #line ディレクティブの次の行がソースコード中の何行目に当たるかを指定するもの。

2015年2月26日木曜日

テクスチャ補間方法

GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER を変えながら tunnel サンプルを動かしてみた。

GL_TEXTURE_MIN_FILTER: GL_NEAREST,
GL_TEXTURE_MAG_FILTER: GL_NEAREST

GL_TEXTURE_MIN_FILTER: GL_LINEAR,
GL_TEXTURE_MAG_FILTER: GL_LINEAR

GL_TEXTURE_MIN_FILTER: GL_NEAREST_MIPMAP_NEAREST(ミップレベル間際近接、テクセル間際近接),
GL_TEXTURE_MAG_FILTER: GL_NEAREST

GL_TEXTURE_MIN_FILTER: GL_NEAREST_MIPMAP_LINEAR(ミップレベル間線形補間、テクセル間最近接),
GL_TEXTURE_MAG_FILTER: GL_NEAREST

GL_TEXTURE_MIN_FILTER: GL_LINEAR_MIPMAP_NEAREST(ミップレベル間最近接、テクセル間線形補間),
GL_TEXTURE_MAG_FILTER: GL_LINEAR

GL_TEXTURE_MIN_FILTER: GL_LINEAR_MIPMAP_LINEAR(ミップレベル間線形補間、テクセル間線形補間),
GL_TEXTURE_MAG_FILTER: GL_LINEAR

本に通り GL_LINEAR_MIPMAP_LINEAR が一番画質がよく、GL_LINEAR_MIPMAP_NEAREST もまあ使えて、GL_NEAREST_MIPMAP_NEAREST と GL_NEAREST_MIPMAP_LINEAR は NG な感じですね。

静止画ではわかりませんが、ミップマップを使わない GL_NEAREST, GL_LINEAR は画面が動く(このサンプルでは奥へ進んでいく)とテクスチャがギラギラ光るようなアーティファクトが出ます。

ktxview が動かない

OpenGL SuperBible 6th Edition のサンプルプログラムの ktxview を動かすには少し修正が必要だった。

--- ktxview.cpp.orig 2015-02-26 00:19:32.007575700 +0900
+++ ktxview.cpp 2015-02-26 00:20:30.933946100 +0900
@@ -61,7 +61,7 @@
     "                                                                               \n"
     "uniform sampler2D s;                                                           \n"
     "                                                                               \n"
-    "uniform float exposure;\n"
+    "layout (location = 0) uniform float exposure;\n"
     "\n"
     "out vec4 color;                                                                \n"
     "                                                                               \n"

テクスチャを float で持たせる意義がわかるサンプルでした。

2015年2月18日水曜日

Parallel NSight をつかってみた

NVIDIA の Parallel Nsight をつかってみた。CUDA プログラムのデバッグができることを売りにしてるけど、OpenGL のシェーダーのデバッグにも使えます。VisualStudio からシェーダーにブレークポイント張って、ステップ実行したり、変数の中身を確認したりできて便利。お察しの通り使うには NVIDIA の GPU が必要です。

uniform block のサンプル

OpenGL Super Bible 6th Edition にはサンプルプログラムがいっぱいついているけど、それでも解説されていることに対応するサンプルがけっこうないことに気づいてきた。なのでいくつか自分で作ってみている。
https://github.com/orchely/cg_lesson/tree/master/opengl

uniform block もそうしたサンプルがないもののひとつ。

There is a complete example of the alignments of various types in the original ARB_uniform_buffer_object extension specification.
とあるだけでサンプルプログラムはついていない。一応そのドキュメントのサンプルを動かしてみることはできたけど、OpenGL 2.x 時代のサンプルでいろいろ今と違うし、uniform block の使い方も少し違うので今風に書き直してみた。
https://github.com/orchely/cg_lesson/blob/master/opengl/11_uniform_block_std_layout/uniform_block_std_layout.cpp?ts=4

まだ OpenGL 自体がよくわかっていないので試行錯誤したけど、なんとかそれっぽく動いた。もとのサンプルでは

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(60.0, wf/hf, 0.1, 100.0);
となっていたところを
 projection_matrix = glm::perspective(60.0f, 4.0f / 3.0f, 0.1f, 100.0f);
ではなく
 projection_matrix = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
にしないといい感じにならなかったのかはよくわかっていない。

ちなみに行列計算には Super Bible 付属のライブラリではなく、この本を卒業したあとも使い続けられそうな GLM を使いました。

2015年2月16日月曜日

Chapter 5: Data, Buffers

OpenGL Super Bible 6th Edition, Chapter 5: Data, Buffers のメモ

  • バッファは汎用の GPU メモリ上のただのメモリブロック。特に使い方は決まっていない。
  • 名前という名の識別子(実際のところ数値)で識別する。
  • 使用するには
    void glGenBuffers(
        GLsizei n,
        GLuint * buffers);
    で作成したあと
    void glBindBuffer(
        GLenum target,
        GLuint buffer);
    でバインディングポイント(ターゲットと呼ぶこともある)にアタッチする。バインディングポイントは以下のものがある:
    • GL_ARRAY_BUFFER (5章)
    • GL_ATOMIC_COUNTER_BUFFER (5章)
    • GL_COPY_READ_BUFFER (5章)
    • GL_COPY_WRITE_BUFFER (5章)
    • GL_DISPATCH_INDIRECT_BUFFER (10章)
    • GL_DRAW_INDIRECT_BUFFER (7章)
    • GL_ELEMENT_ARRAY_BUFFER (7章)
    • GL_PIXEL_PACK_BUFFER (9章)
    • GL_PIXEL_UNPACK_BUFFER (13章)
    • GL_QUERY_BUFFER (非解説、OpenGL 4.4 で導入)
    • GL_SHADER_STORAGE_BUFFER (5章)
    • GL_TEXTURE_BUFFER (5章)
    • GL_TRANSFORM_FEEDBACK_BUFFER (7章)
    • GL_UNIFORM_BUFFER (5章)
  • OpenGL ではバッファに種類はない。glBindBuffer() した後でも、そのバッファを違うバインディングポイントにバインドすることもできる。
  • 各バッファのメモリはアタッチしたあと
    void glBufferData(
        GLenum target,
        GLsizeiptr size,
        const GLvoid * data,
        GLenum usage);
    で割り当てる。usage 引数は確保した領域をどう使うつもりか OpenGL に対しヒントを与えるためのもの。data は確保したメモリに書き込むデータで NULL でもよい。
  • void glBufferSubData(
        GLenum target,
        GLintptr offset,
        GLsizeiptr size,
        const GLvoid * data);
    で後からデータを書き込むこともできる。
  • void *glMapBuffer(
        GLenum target,
        GLenum access);
    で GPU メモリをメインメモリにマップし、普通のメモリと同様に書き込むこともできる。
  • バッファを一様な値で塗りつぶすには
    void glClearBufferSubData(
        GLenum target,
        GLenum internalformat,
        GLintptr offset,
        GLsizeiptr size,
        GLenum format,
        GLenum type,
        const void * data);
    を使う。
  • バッファ間でコピーを行うには
    void glCopyBufferSubData(
        GLenum readTarget,
        GLenum writeTarget,
        GLintptr readOffset,
        GLintptr writeOffset,
        GLsizeiptr size);
    を使う。コピー元/先ともバインディングポイントで指定するので同じバインディングポイントにバインドしたバッファ間でコピーはできない。一つのバインディングポイントに同時に複数のバッファをバインドすることはできないため。コピーするための一時的なバインド先として GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER バインディングポイントが使用できる。
  • (復習) vertex array object: P20 より
    a vertex array object (VAO), which is an object that represents the vertex fetch stage of the OpenGL pipeline and is used to supply input to the vertex shader.
  • (復習) vertex attribute: シェーダーへのデータ入出力に使うこういうやつ
    // "offset" and "color" are input vertex attributes
    layout (location = 0) in vec4 offset;
    layout (location = 1) in vec4 color;
  • バッファから頂点属性にデータを渡すには、まず、
    void glVertexAttribPointer(
        GLuint index,
        GLint size,
        GLenum type,
        GLboolean normalized,
        GLsizei stride,
        const GLvoid * pointer);
    でどの頂点属性が、バッファ中のどこのデータを使うかを指定する。index は上の layout(location = x) で指定した値。引数名とは裏腹に pointer はバッファ中の開始オフセット。バッファ中の整数データをその整数型の最大値で割って 0.0f - 1.0f の float/doubleに変換してシェーダーに渡す場合は normalized を GL_TRUE にする。次に
    void glEnableVertexAttribArray(GLuint index);
    で拡張点属性が glVertexAttrib*() で渡されたデータではなく、バッファ中のデータを使うようにする。
  • 二つの頂点属性に対してことなるバッファからデータを渡すには、一つ目のバッファを glBindBuffer() した状態で、glVertexAttribPointer(), glEnableVertexAttribArray() を呼び、次に二つ目のバッファを glBindBuffer() した状態で、glVertexAttribPointer(), glEnableVertexAttribArray() を呼ぶ。
  • 二つの頂点属性(例えば座標と色)が交互に並んだバッファからデータをわたすには、その共通のバッファを glBindBuffer() を呼んだ後、stride と pointer を適切に設定して、glVertexAttribPointer() と glEnableVertexAttribArray() をそれぞれ 2 回呼ぶ。

2015年2月11日水曜日

3D CG 座標空間

最近 OpenGL の勉強をしているんだけど、別名がいろいろ出てきて混乱してくるのでまとめみる。

オブジェクト空間

  • 別名: モデリング空間、ローカル空間
  • 次数: 3
  • 原点: どこでもかまわないが、通常は原点を中心に回転させたときに妥当な振る舞いになるよう中心を原点にとる。
  • 各モデルに固有空間。モデルを作成するときにはこの座標系で作業する。

ワールド空間

  • 次数: 3
  • 原点: どこでもかまわない。
  • 全てのオブジェクトを配置するためのグローバルな絶対座標をを提供するための空間。ライティング、物理計算はこの座標で行われることが多い。

カメラ空間

  • 別名: 視野空間 (view space)、視点空間 (eye space)
  • 次数: 3
  • 原点: カメラの位置
  • 原点だけでなく、向きも大事。右手座標系ではカメラが向いている方向を \( -z \) 方向(手前ほど大きな値で奥ほど小さな値)、カメラマンにとっての上と右をそれぞれ \( +y, +x \) 方向にとる。

クリップ空間

  • 別名: 正準視体積空間
  • 次数: 4 (同次座標の \( w \) 成分が \( 1 \) ではなく、意味のある値を持つという意味で)
  • 原点: 中心
  • 最終的に見えるオブジェクトを決定するための空間。OpenGL の場合、この座標空間に変換後 \( -w \le x \le w, -w \le y \le w, -w \le z \le w \) になっている点が最終的に映し出される空間に含まれるとして処理される。つまり視錐台の 6 面が \( x = \pm w, y = \pm w, z = \pm w \) の 6 面になる。

正規化デバイス座標空間

  • 別名: NDC (Normalized Device Coordinate) space
  • 次数: 3 (同次座標の \( w \) 成分は \( 1 \) で、もう意味はない)
  • クリップ空間の各点について \( x, y, z, w \) 成分をそれぞれ \( w \) 成分で割って正規化した点が入っている空間。したがって視錐台の 6 面は \( x = \pm 1, y = \pm 1, z = \pm 1 \) の 6 面になる。

ウィンドウ空間

  • 次数: 3 (2ではない。 \( z \) 成分は深度テストで使うため意味のある値を持っている)
  • 正規化デバイス空間の各点の \( x, y \) 成分を最終的な画像を表示するウィンドウのピクセル単位のサイズに合わせてスケールしたもの。正規化デバイス空間では視錐台に含まれる各点の \( x, y \) 成分は \[ -1 \le x \le 1, \\ -1 \le y \le 1 \] に含まれたがこれが \[ -window\_width / 2 \le x \le window\_width / 2, \\ -window\_height /2 \le y \le window\_height / 2 \] になるようにスケールする。