「 2014年01月 」一覧

ESXi 5.5について


Realtek の NIC を有効にしたまま ESXi 5.5 を試してみようとがんばってみました。先人の情報があるのでこの部分については楽にできました。

ESXi 5.0 を USBメモリに展開してインストール

まず ESXi 5.0や 5.1 をインストールします。光学ドライブを非搭載だったので USB メモリからインストールしました。
その後、sshで他のPCからログインして操作したいので、sshを有効化します。
5.0からはパスワードログインできなくなったので、ESXiにて Alt+F1でshellに入って設定を変更することが必要です。

/etc/ssh/sshd_config を開いて、PasswordAuthentication no の行を yes に変更。
その後、 /etc/init.d/SSH restart で sshの再起動でOKです。

ESXi 5.5 をインストール(アップグレード)

sshなり管理用コンソールなりで下記コマンドを実行して、5.5へアップグレードします。

ESXi 5.5でわかったこと

仮想マシンのバージョンが 10 が使用可能になり、このバージョンにあげてしまうと無料のvSphere Client でマシン構成の変更ができなくなるという情報があります。これがとても気になっており、不安だったのですが試してみてわかったことがあります。それは、デフォルトで作成した仮想マシンはまだバージョン8のままであるということでした。明示的に仮想マシンのアップグレードを行わない限りはまだ運用できそうです。
 続いて GPU パススルーが簡単にできるようになったという情報がありましたが、手元で試した RADEON 6850や7750では正常に Windows7ゲストにパススルーできませんでした。起動時にエラーが出るのですが VMK_MEM_ADMIT_FAILED というもので、例のメモリホールの話じゃなかったのでここでひとまず詰みでした。もしかすると CPU やチップセット側に問題があるのかもしれません。最近の IvyBridge以降の対応CPUを使って、廉価版ではないチップセットならば正常に動作するのかもしれません。

最後に1点わかったこととして、VMware Workstation 10 を持っていれば、仮想マシンバージョンを10に上げてしまったとしても vSphere Client の代わりとして Workstation 10 を使って編集することができます。これでも注意点があって、PCIデバイスのパススルーに関しては設定ができないようです。単純な仮想マシンならばこれで可能なのですが・・・同様にUSBデバイスのパススルーに関しても同様。vSphere Client がないと設定はできないようでした。

感想としては、ESXi 5.5 は通常運用はできないかなと。全てがWorkstaion 10から操作できるのであればまだよかったのですが、vSphere Client がほしい場面がありそうですし、設定項目が全て見えてこないという点でも難があります。


テクスチャ配列の活用について (OpenGL)


テクスチャ配列の活用について考えてみました。昔はマテリアルに付随する各マップ(ディフューズ、スペキュラ、ノーマル)などを1つにまとめて使うのかなと思っていましたが、また別の使い道もあることがわかってきました。

その活用法というのが、テクスチャアトラスとして使うというものです。テクスチャアトラスとは複数の小さいテクスチャをまとめあげて大きなテクスチャを作成して、各描画ではその一部分を使うという物です。これの狙いはテクスチャの切り替えをなくして、1回の描画コールにまとめ上げることで描画負荷を減らす(特にCPU側)というものです。

さて、やり方ですが、2Dテクスチャ配列に各テクスチャ画像を詰め込んでいきます。このため各テクスチャは同じ解像度である必要はあります。図示するとこんな感じです。これを glTexImage3D関数にて転送しておきます。

texatlas_with_texture_array

そして各テクスチャを利用するポリゴンには、テクスチャ配列内でのインデックス値を頂点情報のどこかに格納しておきます。一番都合がいいのはテクスチャUVの3要素目(w)にいれておくことです。頂点情報をこのように作ると、ピクセルシェーダー(フラグメントシェーダー)で簡単に対象となるテクスチャから画素を参照することができます。

example_texture_array_atlas

これらの作業により、この例では1回の描画コマンド発行で4つのテクスチャを参照して描画することができるようになりました。同じ解像度である必要がある点を除けば、テクスチャ配列を活用して、お手軽なテクスチャアトラスの代わりとさせることができそうな気がします。


OpenGL でテクスチャ配列を使う


OpenGLでもテクスチャ配列が使用可能になっています。以前DirectX10のテクスチャ配列を使うには、という項目で記事を書いたのですが、あれっきりOpenGLではどうやるのかを放置してしまいました。今回は OpenGL でテクスチャ配列を使うコードを説明したいと思います。

結果

4つの2Dテクスチャをテクスチャ配列としてセットして、UV値によって参照先を変更しています。

gl_texture_array

説明(GLSL)

GLSLのシェーダーはこのようなものを使用しています。texture2D( tex, uv ) で参照していた箇所が、どのテクスチャから参照するかを指定するため、3次元目にそのインデックスを格納したパラメータでサンプルするようになっています。

説明(C++)

C++側では、従来の GL_TEXTURE_2D を指定した部分が GL_TEXTURE_2D_ARRAY を設定するようになりました。
またサンプラーオブジェクトも併用可能です。1つ違う点は2Dのテクスチャ配列は、データの転送時には glTexImage3D 関数を用いる必要があるというところです。配列になった分、1次元上のデータ転送関数が必要っぽいです。
 当然ながら、配列間での画像イメージでの補間はできないようです。やりたければシェーダーで個別にサンプルしてブレンドすることが必要となります。(このような補間をしたい場合には3Dテクスチャを使えってことでしょう)

最初のサンプル画像では4つの画像イメージを GL_TEXTURE_2D_ARRAY の1つのオブジェクト内にいれてみました。


新しめのTransform feedbackの使い方


OpenGL transform feedbackの使い方で最近は少し変わって便利に使えるようになったようです。前回、書き込んだプリミティブ数をCPUで取得していましたが、これが不要となるようです。いわゆるDirectX の DrawAuto っぽいものがOpenGLでも実現できるようになりました。

使い方は、以下のような感じです。ポイントは GL_TRANSFORM_FEEDBACK のオブジェクトを使うというところです。ここに対してバッファの制御をさせるようなそんな感じです。バッファのバインドが GL_TRANSFORM_FEEDBACK_BUFFER に対して行うところもポイントです。

ここの transformFeedback 変数は、 glGenTransformFeedbacks 関数で準備しておきます。
クエリを発行する部分が消え去って、すっきりとした印象を受けます。
 ただこのglDrawTransformFeedback関数ですが、最近のOpenGL 4.0 をサポートするドライバがインストールされていないと使えないようです。4.0をサポートしていても使えないことがあるとか。ただ GL_ARB_transform_feedback2 拡張に本関数は定義されているようです。


Transform Feedback で GPU Particle っぽいもの


OpenGLの transform feedback を使って GPU パーティクルっぽいものにチャレンジしてみました。以前、transform feedback を試していたときは、ストリームアウトばかり気にしていて、せっかくのGPUで演算が完了できるという点を見落としていました。

今回は VBOを2つ用意してこれをピンポンすることで頂点および情報の更新を行っています。
CPUからは初期情報だけは送り込むものの、その後の頂点の情報に関しては無関係です。 Transform feedback バッファに書き込まれた個数を取得して、描画命令の発行を行うくらいにとどまっています。

実装で大変だったこと

各1スプライト単位でカラー情報を保持させていたのですが、32bitのUINT でデータを送り込んでいました。しかし、feedback バッファに書き込む際には float4 になっており、2度目以降のカラー情報がおかしな状況となっていました。これに気づくまで結構かかりました。transform feedbackを使ってデータを書き込む際には1要素はfloatである、ということにしておいて、統一をとっておいた方がよさそうです。
結局、位置(vec3)、カラー(vec4)、速度(vec3) という情報を書き込むことにして、なんとなく実現できました。

そのほかの注意点としては、シェーダーのリンク前に glTransformFeedbackVaryings で出力変数を指定しておくことでしょうか。

更新&描画時の処理としてはこんな感じです. 更新フェーズではピクセルシェーダーで書き込みを行わないので無効化したり、頂点数を知るためにクエリを発行していたりします。

やっていることは、ストリームアウトした物を描画指示しているだけです。
今までのブログの中では常にストリームアウトしたものを描画しているだけで、今回はこのストリームアウト先が描画フレーム毎に入れ替わるのが新しい点になります。だからこそシェーダーだけで位置更新できるのですが。

補足

どうやらこのようなTransfeedback の使い方は、レガシーな部類なんだとか。最近はもっと使いやすいようにGL拡張が追加されているとのことなので、これもちょっと調べてみようと思います。
 古くさいやり方だからなのかもしれませんが、意外とCPUの占有率が高かったことが気になりました。しかもカーネル時間のほうだったので、書き込み数取得のところが負荷となっているのかも?と思っている次第です。

今までのOpenGL ストリームアウト記事

OpenGLでのストリームアウト その1
OpenGLでのストリームアウト その2
OpenGLでのストリームアウト その3
OpenGLでのストリームアウト その4
OpenGLでのストリームアウト その5


ジオメトリシェーダーでポイントスプライト(OpenGL)


OpenGLでテセレーションとかインスタンシングとか試している割に、基本的なジオメトリシェーダーでポイントスプライトを実装してみるということをやっていなかったので、改めて試してみます。

方針

とりあえず四角形の4頂点をポイントスプライトとして描画することを考える。DirectXであれ最近のOpenGLであれ、頂点そのものを描画する機能はシェーダーを使って描画しなくてはいけなくなっているようなので。また、ポイントスプライトといっているけど、テクスチャ準備は今やりたいことから考えると余計なので、頂点カラーをつかってその頂点を描画する方向で考える。

動作結果

先に動いているのを示します。こんな状態になってます。単に四角形を回転させているだけなのですが、その頂点だけを描画すると、不思議と四角形が回転しているようには見えない気がします。

実装

四角形の4頂点を用意して、描画の際には glDrawArrays( GL_POINTS )を使って描画命令を発行する。
他にもワールド、ビュー、プロジェクションの行列は必要なのでこれらはシェーダーに送る。これらのC++側の実装コードはこんな感じです。

シェーダープログラムの実装

各シェーダープログラムは以下のような感じに実装しています。ジオメトリシェーダーで頂点を4つの頂点に増やしてトライアングルストリップ化しています。またこのときのスプライトの大きさは適当です。本来なら視点からの距離で拡大縮小すると使い物になるんでしょう、たぶん。

おまけ

今回は単に4頂点に拡張して四角形をそのまま描画していますが、中心点と四隅の距離を計算して一定の範囲内なら描画、範囲外ならピクセルを棄却(discard命令)とすると、丸い形状を描画することができます。


最近でのワイヤフレーム描画 (OpenGL 4)


前回のテセレーションの試作において、OpenGLの関数にてワイヤフレームを描画していたのですが、動画公開時によくよく見てみると、あるタイミングでワイヤフレームとテセレーション結果が一致していないという妙な症状が出ていることがわかりました。
 そこでワイヤフレームの描画について見直しをしてみようと思いました。OpenGL 4.0 Shading Language Cookbook という書籍にて、アンチエイリアスがかかったワイヤフレーム描画を行うサンプルがあったのでこれを導入してみました。サンプルではVS, GS, PS でしたが、ここではさらに TES, TCS も有効化して、シェーダーをフル動員してみました。

結果はこの動画のようになりました。フレームを見ていても妙なところはなく、それなりにアンチエイリアスされたワイヤフレームで描画が行われています。以前のワイヤフレームよりは、ギザギザ感がなくなりました。

拡大してみるとこんな感じになってます。それなりにアンチエイリアス処理っぽいものがされているため、普通に動かしているときにはなめらかに見えている感じです。拡大したこの図を見ている限りでは、ちょっと妙なところはあるかもしれません。
antialiased_wireframe

補足

詳しい実装方法は書籍の方を参考にして下さい。
ただ書籍の中であまり丁寧に書かれていなかった部分について、ここで触れておきたいと思います。

ビューポート行列というものが出てきます。これはビュー行列ではなくビューポート変換をするための行列を示しており、下記のようなコードで生成することができます。

感想

ジオメトリシェーダーで辺と内部の判定を行うための変数(係数)を計算しています。あまりジオメトリシェーダーの活躍をみなかったのですが、地味なところで実は活躍できるそんなシェーダーなのではないかと思いました。ポイントスプライト以外にもちゃんと役立てられるということが印象深かったです。


定数バッファ(Uniform Block)について


DirectXのサンプルを見ているとC++側とHLSL側とで同じ並びの構造体を作ってデータを送っているように見えます。データのレイアウト規則は同じになるのが保証されるのか少々疑問です。一応 D3Dの関数でシェーダーリフレクションが使えるので、調査することはできますが、そこまでやってC++側の定数バッファを作成している例を見かけたことがありません。
 一方、OpenGLでは定数バッファ内の変数についてのレイアウトルールは実装依存となることがドキュメント記載されています。これが使いづらいという理由のためか、最近では標準レイアウトルールというものができたようです。uniform ブロックの前に layout(std140) をつけることで使用できます。

ただこのstd140レイアウトルールは使えない場合もある。OpenGL 3.x で定数バッファが導入されているため、ドライバ(やハードウェア)によっては使えない状況というものが生まれてしまう。こういうときをサポートするんであれば、定数バッファ内のどこに何という変数が割り当てられているかをC++側で把握する必要が出てきます。
 割り当てられている場所がわかれば、glBufferSubData の関数を用いてデータをUBOにセットしていきます。

さて、D3DReflect と同じことをやるためには、OpenGLではどのような手順で調べるかを書いておきます。OpenGLでももうちょっとシェーダーリフレクションがやりやすくなればいいのにと少し思うくらい手間が多めです。

  1. glGetProgramiv( GL_ACTIVE_UNIFORM_BLOCKS,… ) で定数バッファの個数を取得
  2. 以降定数バッファの数だけループ
  3. glGetActiveUniformBlockName で名前を取得
  4. 取得した名前を元にブロックのインデックスを取得(blockIndex)
  5. glGetActiveUniformBlockiv( GL_UNIFORM_BLOCK_DATA_SIZE,…) で定数バッファのサイズを取得
  6. glGetActiveUniformBlockiv に blockIndex, と GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS をセットして、定数バッファ内にある変数の個数を取得
  7. glGetActiveUniformBlockiv( GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,…) を用いて、定数バッファ内変数のインデックス値を取得
  8. glGetActiveUniformsiv( GL_UNIFORM_OFFSET,…) を用いて各変数のオフセットを取得
  9. 変数の名前を求めるために下記を実行する.
  10. 各変数のインデックス値をglGetActiveUniformの引数にセット
  11. ↑変数の名前やデータタイプも取得できる

OpenGL でテセレーションのシェーダー(TCS,TES)を使う


OpenGLの4.x世代でテセレーションのシェーダーが使えるようになり、DirectX11相当になりました。前回は簡単な三角形や四角形の再分割は作ってみたので、今回はモデル形状について適用してみたいと思います。
 そして割とテセレーションのサンプルでは定番の PN Triangles の方法で OpenGLのシェーダー Tessellation Control Shader(TCS), Tessellation Evaluation Shader(TES) を作成して描画してみたいと思います。

PN Trianglesについて

PN Triangles は、位置と法線の情報から曲面での再分割の位置を求めるためのアルゴリズムです。詳しくは論文の Curved PN Triangles を参考にしてください。
 DirectX での実装例はよく見かけるのですが、OpenGLでの実装についてはあまりやられているのを見かけませんでした。今回やってみて感じたのは特にOpenGLだから難しいということはない、ということです。それなのにサンプルが少ないのは残念ですね。

DirectX と OpenGL でのシェーダーの違い

基本的には、ハルシェーダー=Tessellation Control Shader、 ドメインシェーダー=Tessellation Evaluation Shader と対応しています。しかし、ハルシェーダー部分が DirectX と OpenGL でちょっと違います。DirectX ではハルシェーダーと表現している部分の処理の中に、テセレーション係数を求めるためのパッチ係数フェーズとコントロールポイント出力フェーズの2つが含まれています(コントロールポイント出力フェーズでは後段へのデータ出力の役割もある模様)。
 OpenGLのTCSでは、パッチ係数フェーズとコントロールポイント出力フェーズを分けずに TCS内で一緒くたに記述してしまうのが作法のようです。一部の例では、パッチ係数を求めるときは下記のように gl_InvocationID で1回だけ実行されるようにしていたりするようです。

図示するとこんな感じでしょうか。

tcs-tes-diagram

PN Trianglesを実装してみる

PN Trianglesを実装してみました。上記のDirectXでのシェーダーとGLでの対応関係がわかってしまえば、DirectXのサンプルを読み解いて、GLで実装し直すのもそこまで難しい話ではないように思います。
 また描画に関しては以前に説明したとおりの内容でモデル描画を行えばよいのでここでは実装したシェーダーを公開してみたいと思います(シェーダー内容は長めなコードになるので末尾を参照)。またプロジェクション変換は頂点が確定した後で行う必要があるので、今までは頂点シェーダーでやっていましたが、これからは TES(ドメインシェーダー) で行う必要があります。

描画結果

動画でキャプチャしてみました。

立方体をPN Trianglesしてみた。確かに割れてます

立方体だけど、8つの頂点の法線は隣接面の頂点と共有できるように合成したものを使用。このときちょっと丸みを帯びていきます。

モデルとして定番のteapot で PN Triangles を適用してみました。

続きを読む


OpenGL 4.x でのテセレーション


描画方法についてはキューブを回すところまでできて一段落したので、しばらくは追加された機能について試していきたいと思います。今回は OpenGL 4.x で追加されたハードウェアのテセレーションについてです。DirectX 11 でいうところの、ハルシェーダーだったりドメインシェーダーだったりに相当します。OpenGL ではこれらを、テセレーションコントロールシェーダーとテセレーションエバリュエーションシェーダーと呼びます。なかなかOpenGLでテセレーションの簡単なサンプルを見かけなかったので、ちょっと大変でしたが何となく最小限のものができたので今回はこれを説明&公開します。

テセレーションとは

テセレーションとは、ポリゴン面をさらに分割してよりなめらかな曲面を作り出すのに使用されます。近年のOpenGLやDirectXでは、テセレーションを行うハードウェアが搭載されており、これらをテセレーションコントロールシェーダー(Tessellation control shader)とテセレーションエバリュエーションシェーダー(Tessellation evaluation shader) によって制御します。DirectXではこれらのシェーダーを別名で呼び、ハルシェーダー、ドメインシェーダーと呼んでいます。

続きを読む