hpprc/jawiki-books huggingface dataset:
OpenGLプログラミング/モダンOpenGL チュートリアル 06

テクスチャをロードするには、JPEGやPNGのような、特定の形式で画像をロードするコードが必要です。通常、最終的なプログラムは、様々な画像フォーマットをサポートする、SDL_image、SFML、Irrlicht、などのような一般的なライブラリを使用するので、画像読み込みコードを自前で記述する必要はありません。 SOIL(下記参照)などの特化したライブラリも興味深いかもしれません。
最初のステップでは、基本を理解するために低レベルで画像を操作する必要があるので、トリックを使っていきます:GIMPは、画像をC言語のソースコードとしてエクスポートすることができ、私たちのプログラムからそのまま読むことができます! 右のGIMPのスクリーンショットのsaveオプションを使用しました。
需要があれば、PNMのようなシンプルな形式、またはBMPやTGAのサブセットを読み込むための、特別なチュートリアルを提供するかもしれません(これら2つもシンプルですが、圧縮や様々な形式をサポートしているので、すべてのオプションをサポートするのは難しくなります)。
注:Cコードとして画像をバンドルすることはメモリ効率がひどく悪いので、それを一般化しないでください。 技術的には:プログラムのBSSセグメントではなくヒープに保存されるので、解放することができません。
注2:コードリポジトリでres_texture.xcfとしてGIMPのソースを見つけることができます。
res_texture.cを修正したときに自動的にアプリケーションを再構築するには、Makefileにこれを追加します:
バッファは、基本的にはグラフィックカード内部のメモリスロットなので、OpenGLは非常にすばやくそこにアクセスすることができます。
さて、各頂点をテクスチャのどこに配置するかを指示する必要があります。 このために、 v_color属性を置き換えて、 texcoordを使用した頂点シェーダにします:
今、マッピングしていくのはテクスチャのどの部分に、例えば前面の左上隅になるのでしょうか? まあ、それは場合によります:
複数のテクスチャポイントが同じ頂点にくっついていることがわかります。 頂点シェーダはどちらを選べばいいかを判断できません。
なので面あたり4つの頂点でキューブを書き換える必要があり、頂点の再使用はしません。
スタートのために、前面だけを扱っていきます。 簡単です! 私たちは2つの最初の三角形(6つの最初の頂点)だけを表示する必要があります:
したがって、私たちのテクスチャ座標は[0、1]の範囲内にあり、x軸は左から右に、そしてy軸は下から上になります。
頂点シェーダ:
フラグメントシェーダ:
おっと何が起こっているのでしょうか? テクスチャが逆さまです!
OpenGLの規約(左下隅が原点)は、2Dアプリケーション(左上隅が原点)とは異なります。 これの修正は、次のいずれかで実行できます:
ほとんどのグラフィック·ライブラリは、2D規約におけるピクセルの配列を返します。 しかし、 DevIL は、原点に配置するオプションを持ち、この問題を回避できます。 あるいは、BMPやTGAのようないくつかの形式は、ネイティブで下から上にピクセルラインを格納し(これがTGA形式の重さにもかかわらず3Dの開発者の間で一定の人気がある理由といえるかもしれません)、カスタムローダーを書く場合には便利です。
ピクセルラインの入れ替えも、実行時にCコードで行えます。 Pythonのようなハイレベルな言語でプログラムするのであれば、1行で行うことさえできます。 欠点は、この余分なステップが原因で、テクスチャのロードが幾分遅くなるということです。
テクスチャ座標を逆にすることは、私たちにとって最も簡単な方法で、フラグメントシェーダでそれを行えます:
OK、技術的には最初は他の方向のテクスチャ座標で書くこともできました - しかし他の3Dアプリケーションは私たちが記述したような動作をする傾向があります。
説明してきたように、それぞれの面ごとに独立した頂点を指定します:
F各面について、頂点は反時計回りに追加されます(見る人がその面を向いているとき)。 その結果として、テクスチャマッピングは、すべての面で同一になります。
ここでは、前面についてマッピングを指定し、それを残りの5面すべてにコピーしました。
I面が反時計回りではなく時計回りの場合、テクスチャはミラーされて表示されます。 方向には規約は無く、テクスチャ座標が正しく頂点にマップされていることを確認する必要があります。
キューブ要素も同様に、インデックス(x, x+1, x+2), (x+2, x+3, x) を持つ2つの三角形で書かれます:

付加的な楽しみのために、そして底面をチェックするために、 NeHe's flying cube tutorialで説明している3回転の動きを onIdleで実装してみましょう:
できあがりです!
WIP
SOIL provides a way to load an image file in PNG, JPG and a few other formats, designed for OpenGL integration. It's a pretty minimal library with no dependency. It's used under the hood by SFML (although SFML also uses libjpeg and libpng directly).
Install it (look for a package named libsoil, libsoil-dev, or something similar).
Reference it in your Makefile:
SOILは、PNG、JPG、その他いくつかの形式の画像ファイルを読み込む方法を提供し、OpenGLとの統合のために設計されています。依存関係はなく、非常にシンプルなライブラリです。SFML( Simple and Fast Multimedia Library ) で使用されています(SFML は libjpeg と libpng を直接使用します)。
インストールします(libsoil、libsoil-dev などの名前のパッケージを探します)。
Makefile で参照します。
One high-level function allows you to upload it directly to the OpenGL context:
ある高度な機能を使えば、OpenGLのコンテキストに直接アップロードすることができます。
Note that with this method, you do not have access to the image dimensions. Do get them, you need to use a lower-level API:
このメソッドでは、画像の大きさにはアクセスできないことに注意しましょう。寸法を取得するには、より低レベルのAPIを使用する必要があります。
テンプレート:OpenGL Programming BottomNav
OpenGLプログラミング/Modern OpenGL Tutorial Load OBJ

とても手っ取り早く、既存のモデルをロードすることで、手製で作成するかわりにしたいと思います。 Blenderからモデルをインポートしてみましょう。
どうやら直接.blenderファイルをロードする簡単な方法はないようですが、次のいずれかの方法で行えます:
OBJローダーを書くことは良いエクササイズになると思うので、その方法で始めましょう。
テンプレート:Wikibooks
スザンヌは、Blenderのテストモデルです。 これは500ポリゴンを持っていて、私たちのテストにも適しています。
それを作成するため、Blenderを実行し(バージョン2.58を使用しています)、その後:
Blenderは2つのファイル、suzanne.objとsuzanne.mtlを作成します:
今からメッシュをロードしていきます。
.objファイルをテキストエディタで調べてみましょう。 フォーマットは非常にシンプルであることがわかります:
C言語の配列をいくつか移入する必要があります:
このフォーマットは他にも特徴を持っていますが、今のところそれらは脇に残しておきます。
ここにあるのは最初の、荒削りな実装ですが、私たちのオブジェクトには役目を果たしてくれるはずです。
私たちのパーサには制限がありますが(複数のオブジェクトのサポートもなく、別の頂点フォーマット、ポリゴンなども)、私たちの当面のニーズのためには十分です。
C++のベクターを用いて、メモリ管理をシンプルにしています。 引数は参照で渡していて、その主な理由はベクターへのポインタにアクセスするための構文が恐ろしいことになるからです ((*elements)[i])
.objファイルはこのような方法でロードすることができます:
そして以下を使用してOpenGLに渡します:
最後に、適宜見え方を調整し、Y-is-top座標系にして、カメラがスザンヌ向くようにします:
私は少し抜けがけをしてグロー照明モデルを実装しました。 これはこの先で少し取り上げます。
texturing tutorialで説明したように 、時には同じ頂点が使用される面に応じて異なる値になることがあります。 これが当てはまるのは、法線を共有したくない場合です(そして上記したように、頂点の法線を計算するときに任意の面を選択する)。 その場合は、別の法線と一緒に使用されるごとに頂点を複製し、そのあと要素配列を再生成する必要があります。 こうするとロードにかかる時間は多くなりますが、OpenGLの長期的な処理では速くなります。 OpenGLに送信される頂点は少ないほうがベターです。 または、先に述べたように、この例では、それらが表示される時間の頂点だけを複製することもできます。次からは要素の配列なしで作業を進めることができます。
このセットアップをつかえば、フラットシェーディングを得ることができます: varying変数は実際にはフラグメントシェーダ内の頂点の間で変化することはなく、その理由は法線がすべての三角形の3つの頂点で同じになるからです。
私たちのアルゴリズムは機能していますが、二つの面が同じベクトルを参照する場合、最後の面がその頂点の法線を上書きしてしまいます。 これは、面の順番に応じてオブジェクトが全く異なって見えることを意味します。
この問題の解決法は、2つの面の間の法線を平均化することです。 2つのベクトルを平均化するには、最初のベクトルの半分に2番目のベクトルの半分を加えたものを求めます。 ここではnb_seenを使用してベクトル係数を格納するので、ベクトルのリストが満杯まで格納されなければ、新しいベクトルを何度でも平均することができます:
TODO: improve the parser to support .obj normals
Obj形式は事前計算法線をサポートしています。 興味深いことにそれらは面に指定されているので、頂点がいくつかの面に存在している場合、別の法線になってしまうことがあるので、上述の頂点重複のテクニックを使用しなければならないことを意味します。
例えば、基本的なエクスポートのスザンヌが、2つの異なる法線#1と#7といっしょに#1の頂点を参照するとき:
比較すると、MD2/MD3フォーマット(とりわけQuakeなどで使用される)は事前計算法線を含みますが、それらは頂点ではなく面に接続されています。
戸籍法第10条の3

法学>民事法>コンメンタール戸籍法
【交付請求の際の本人確認】

市区町村の窓口にて対面で戸籍謄抄本等の交付を受ける場合に市町村長が行う本人確認について規定されている。本人確認の方法は戸籍法施行規則第11の2に規定され、請求者の身分によってその方法が異なる。
個人が請求している場合には顔写真付き身分証明書の提示を市町村長は求める。
個人が請求している場合で、顔写真付き身分証明書を提示できない場合は、本人のみが所持しているであろう書類を2つ提示させる。 このとき下記のイから2つ提示させるか、イとロを組み合わせて本人確認する。ロを2つは認められない。
有効期限が設定されている身分証は、その有効期限内でなければならない。
個人が請求している場合で、身分証明書をなにも提示できない場合は、戸籍の記載事項について本人であれば当然に知っているであろう事項(父母の旧姓や、続柄)を質問し回答させる方法で本人確認を行う。また、市区町村の職員と面識がある場合は、これを利用して本人確認とすることができる。聴聞による本人確認であれば質問内容と回答を記録し、面識による本人確認であればその職員の氏名を記録する。
その機関の発行した顔写真付き身分証明書を提示させる。これ以外の方法(職員との面識等)は認められない。
弁護士、司法書士、土地家屋調査士、税理士、社会保険労務士、弁理士、海事代理士若しくは行政書士であることを証する顔写真付き身分証を提示させる。加えて、弁護士等の所属する会が発行した統一請求書に当該弁護士等の職印が押されたものによって請求させる。
戸籍法施行規則
OpenGLプログラミング/Glescraft 1

現代のCPUとGPUで利用可能な処理能力があれば、小さなキューブから構成される3Dの世界を完全にレンダリングすることができます。 これを行うよく知られているゲームは Minecraft (次いでそれに触発されたInfiniminer) と Voxatronです。 これらのゲームが備える独自の外観のほかにも、それ自体をグリッド上のキューブに制限することで、かなりの単純化を可能にしています。 このチュートリアルシリーズでは、膨大な数のキューブを管理できる方法、それらを非常に効率的に描画できる方法について説明していきます。
最初に行う重要なことは、レンダリングするボクセル世界を、管理しやすいチャンクに細分化することです。 この方法なら、どのチャンクを画面上に表示するかを決定でき、そして見えないチャンクのレンダリングをスキップすることができます。 また、メモリ·リソースをこの方法で管理することもできます。例えば、見えないチャンク頂点バッファオブジェクトをGPUメモリに保持する必要はありません。 しかし、チャンクの追跡にほとんどの時間を費やすわけにはいかないので、十分な大きさでなければなりません。 チャンクのサイズを変更可能にしていきますが、始めは比較的小さな16x16x16(4096)ブロックの塊にしましょう。 ブロックの種類を格納するためにbyteを使用します。 そのようなチャンクを表す構造体は次のようになります:
blk配列は、ブロックタイプを保持します。 get()とset()の関数は、どちらかといえば取るに足らないものですが、後で便利になるはずです。 set()関数が呼び出されると、変更フラグがtrueに設定されます。 チャンクがレンダリングされているとき内容が変更されると、これがupdate()関数の呼び出しをトリガーしてVBOを更新します。
他のチュートリアルでは、GLfloat座標を頂点、テクスチャ、座標、色、などのためにも使用していました。 OpenGLは、他のタイプも同様に使用することができます。 私たちのボクセル世界では、すべてのキューブは同じ寸法を有しています。 したがって、座標の表現に整数を使用することができます。 世界は無限にできるにもかかわらず、1チャンク内であれば、可能性のあるすべての座標を表現するために、非常に小さな整数しか必要となりません。 GLbytesを使用する場合、-128から+127までの範囲の座標を、持つことができ、16x16x16のチャンクには十分すぎます!
シェーダでは4つのコンポーネントまでのベクトルを使うことができ、X、Y、Zの座標のほかにも、 情報の別のバイトを追加することができます。 私たちは、この "座標 "内にブロックの種類を格納します。 後のチュートリアルでは、テクスチャ座標を導き出すためにこれを使用しますが、今のところは、それぞれのタイプに色を与えるために使用します。
頂点ごとに4バイトの場面では、IBOを使用してもそれほど恩恵は多くありません。 立方体の各面に異なる色や風合いを出すときや、IBOを使用するとき、実際にメモリ使用量が増加します。
エクササイズ:
私たちは、バイトの4次元ベクトルで作業していくことになります。 残念なことに、それに利用するための事前に定義された型はありませんが、GLMは他のベクトル型と同様に、その役割を果たすものを手早く作成することができます:
さて、すべての頂点を保持するのに十分な大きさの配列を作成できているので、そこにつめ込んでいきましょう。 キューブを作る方法はすでに知っているはずです。 正しい順序で頂点を置けば、 glEnable(GL_CULL_FACE)を使用することで、立方体の内部の面の描画を回避することができます。
エクササイズ:
何かを描画する前には、ボクセルを描画するためのシェーダがここで必要になります。 まず、頂点シェーダ:
頂点は、attribute coordを通して頂点シェーダに入ります。 model-view-projection行列を作成する必要があり、これはuniform mvpとして渡されます。 頂点シェーダは、varying texcoordを通じて、入力の座標を無変更でフラグメントシェーダに渡します。 基本的なフラグメントシェーダは次のようになります:
GL_BYTEsを使用していることに留意して、 "w" の座標は0 .. 255の範囲にしましょう。 OpenGLは、これを魔法のように0 .. 1の範囲にマップすることはないので、フラグメントの色に使用可能な値を得るためにそれを割り算する必要があります。
エクササイズ:
チャンク全体のレンダリングは、今は非常に簡単です。 グラフィックスカードにVBOを指し示して、すべての三角形を描画してみましょう:
エクササイズ:
さて、1チャンクを描画する方法がわかったので、いっぱいチャンクを描画してみたくなります。 チャンクのコレクションを管理するには多くの方法があります。ただの三次元配列にしたり、または octree 構造にしたり、 または任意のチャンクを保持するデータベースを持つこともできます。 例えば、 Minecraftは、ハードディスク上にチャンクを格納し、チャンクの座標をファイル名にエンコードして、基本的にファイルシステムをデータベースとして使用しています。
"superchunk"という、基本的には通常のチャンクへのポインタの3次元配列を作成してみましょう。 非常に簡素にするなら、次のようになります:
基本的には、スーパーチャンクも通常のチャンクと同様に get(), set() および render() 関数を備え、そしてそれらの関数を適切なチャンク(複数可)に委譲します。 上記の例で render()関数は重要な機能を欠いています: 各チャンクをレンダリングする前にモデル行列を変更する必要があり、そのようにして正しい位置に変換しないと、重なって描画されてしまいます:
エクササイズ:
OpenGLプログラミング/Glescraft 2

previous tutorialでは、ボクセルのチャンクをレンダリングする方法を見てきました。 ただし、たとえ見えなかったものがあっても、すべてのボクセルが描画されていました。 また、隣接するボクセルが同じ色やテクスチャを共有している場合、いくつかの三角形をマージすることが可能です。 このパートでは、見えないものを除去することによって必要な頂点の量を減らすことを試みます。
一般に、三角形が不可視であるかをすべての可能なカメラ位置において判断することは非常に困難です。 しかし、私たちのボクセル世界では、その側のすぐ隣に別のボクセルがあれば、ボクセルの片側が見えないことが確認できます。 その場合、そのボクセルを構成する2つの三角形の描画を省略できます:
この実装では、1つのチャンク内の視認性しかチェックしないことに注意しましょう。 複数のチャンクがある場合で、 {{{1}}}の場合、隣接するチャンクに視界を遮るボクセルがあるかどうかチェックする必要があります。
エクササイズ:
隣接する三角形をマージすることを考えた様々なアルゴリズムがありますが、簡単な方法は、目に見えるボクセルが同じタイプの行に2つあるかを確認することです。 それが真であれば、その後2つの新しい三角形を追加する代わりに、前の2つの三角形を変更して現在のボクセルを同様にカバーします。 それを行える方法がこれです:
visibleというフラグは、以前のボクセルが表示されていたかどうかを記録します。 もしそうなら、頂点バッファ内の前の2つの三角形がそのボクセルに全く属さないことを確認できます。 さて、内側のループ変数はほとんどが zなので、z座標だけが異なる2つのボクセルを見ています。 なので、前のボクセルの3つの頂点を拡張して、その境界線を現在のボクセル上にし、現在のボクセルをカバーする必要があります。 3つはその中の"z + 1"を持ちます。
エクササイズ
OpenGLプログラミング/Glescraft 3

前の2つのチュートリアルでは、ボクセルはとても退屈な外見で、ボクセルを区別しづらくなっていましたが、それは単一の色しか持たず、照明効果にまったく気を使ってこなかったからです。 このチュートリアルでは、1つのテクスチャ座標だけを使用して、ボクセルに別個のテクスチャを与えることができる方法について説明していきます。 さらに、フラグメントシェーダを微調整して、シーンの照明において小さな方法で非常に大きな改善を達成していきます。
ボクセルにテクスチャを入れたいとき、チャンク内のすべてのボクセルを同じテクスチャにしたくはありません。 しかし、一度にチャンク内のすべての三角形をレンダリングする場合、ボクセル間のテクスチャを切り替えることはできません。 そこで、 texture atlasを使用して、ひとつのOpenGLテクスチャのなかにボクセルにペイントしたいすべての画像を保存する必要があります。 利用できるテクスチャ座標はひとつだけで、可能な値は256あります。 テクスチャアトラス内の可能なサブイメージ256のうちひとつを指すように使用するとよいでしょう。
16のサブイメージをもつテクスチャアトラスがあると仮定します。 すべてのサブイメージは同じサイズ(SW x SH)を持っていますが、正確な大きさは気にしなくてかまいません。 テクスチャアトラスはひとつの行にあるすべてのサブイメージを持つことになるので、テクスチャアトラスは(SW * 16)×SHピクセルを持つことになります。 blk[x][y][z]配列は今0〜15の範囲の値を含む必要があります。 フラグメントシェーダでは、頂点シェーダから受け取る varying vec4 texcoordから実際のテクスチャ座標を作成する必要があります。 明らかに、0〜15の整数値だけでは不十分です。 しかし、ともに役目を果たしてくれるx、y、z座標を持っています。 これらは"varying"なので、VBOからの整数値は含まれていませんが、フラグメントが頂点の間でどれだけ離れているかに応じて、整数値の間の任意の値を持つことができます。 特に、(0, 0, 0)から(1, 1, 0)まで四角形を描画する場合、z座標はどこも0になりますが、yとzの座標は間の任意の値を取ることができる。 この四角形にテクスチャをつけるために、次のフラグメントシェーダを使用することができます:
16で除算するのは、テクスチャの行で16のサブイメージを持っているという事実からのものです。 また、wの座標はクワッド内のすべての頂点に対して同じなので、フラグメントシェーダの定数値を保持します。 MVP行列が適用される前は、 texcoordは単なる uniform coordのコピーなので、テクスチャはMVPの変化によって影響を受けないことを覚えておきましょう。
もちろん、このシェーダは、他にありうる座標の四角形のほとんどで機能しないことに、すでにお気づきでしょう。 まず、(X, Y, *)から(X + 1, Y + 1, *)までの角部をもつ四角形を処理するとき、xおよびyは整数座標で、*は任意のとりうるzの意味で、0〜1の範囲に戻してx座標をマッピングするために fract()関数を使用することができます:
texcoord.yでfract()を使用する必要がないのは、私たちのテクスチャアトラスが単一の行の画像だけを持ち、そしてOpenGLが垂直方向のテクスチャラッピングを取り仕切ってくれるからです。 このシェーダがうまく機能するのは、任意のボクセルの面が正または負のz方向を指しているときです。 しかし、これらの面では、面のすべての頂点がz座標の同じ/整数/値を持ちます。 したがって、 fract()関数を適用する前に、安全にx座標にそれを追加することができます:
同じ引数が正または負のy方向をさすボクセル面を保持するので、これらの面に同じシェーダーを使用することができます! しかし、そこにもy座標を配置することはできません。 また、正または負のy方向に向いた面を正しくレンダリングするための唯一の方法は、2つのフラグメントシェーダを持たせて、xとzに向いている面とは別にyに向いた面をレンダリングするか、または追加的な情報を加えて、頂点が2つの場合の間でフラグメントシェーダでの区別をできるようにするかのどちらかです。 私たちのテクスチャでは16のサブイメージしか使用しないで、W座標で使用するのは4ビットですみます。 実際には非常に基本的な "normal"ベクトルとして別のビットを使用することもできます。 y方向に向いた面を示すときには、負のw座標を使用します:
w座標の負の値を心配する必要はなく、VBOを作成するときに限れば、 blk[x][y][z]の値から16の倍数を引けば、それを負にすることができます。 その方法だと、テクスチャ座標の範囲は0 .. 1の外になりますが、OpenGLによって正しくラップされてテクスチャアトラスの正しい位置になります。
エクササイズ:
テクスチャがついていても、ボクセルを区別するのが難しいこともあります。 シーンをさらに自然な外観にし、ボクセルのどちら側を見ているのか区別しやすくなるように、 前のセクションで紹介した "法線" をちょっぴり使用してボクセルの側面を少し暗くします。 これは現実の世界でいう正午の、太陽が真上にあるときのシェーディングをシミュレートします。
現実の世界では、遠くのオブジェクトは、すぐ目の前にあるオブジェクトよりもかすみがかり、色も不鮮明になって見えます。 これは、大気による光の散乱に起因します。 それはほとんど霧と同じ効果ですが、大きな違いは強さです。 これをフラグメントシェーダで次のように実装することができます:
フラグメントシェーダの上部で、2つの定数を定義します。 fog colorは、非常に遠くにあるときにオブジェクトが持つ色です。 fog densityは霧効果の強さを制御します。 とても小さい方の値は大気の散乱や光のぼやけを表し、大きいほうの値は霧の濃さを表しています。
フラグメントからカメラまでの距離は、 gl_FragCoord.z by gl_FragCoord.wによって割ることで算出できます。 霧の影響は距離の指数関数になります。 変数 fogは霧が適用された後に"left"実際の色の割合を表します。 最終的なフラグメントの色は元の色とフォグの色のミックスです。
最後に、透明なピクセルを持つテクスチャを作ることができます。 透明テクスチャの適用にブレンドを使用することもできますが、フラグメントシェーダで完全な透明ピクセルをシミュレートすることも可能です。 colorを計算したすぐ後に、アルファ値に基づいてフラグメントを破棄することができます:
discardキーワードは、フラグメントプログラムを起動させて、以降の処理を停止させるためのものです (C言語でいう "return"文のようなものです )。 このover blendingの利点は、Zバッファの値が透明ピクセルで更新されないということです。 blendするときで、カメラの近くにある透明な三角形をレンダリングする場合、かつその背後にある不透明なものがある場合、深度テストに失敗するので、不透明なものが描画されません。
エクササイズ:
OpenGLプログラミング/Glescraft 4

3Dシーンのビュー操作にはいくつかの方法があります。 コンピュータ支援設計(CAD)ソフトウェアの場合、通常はカメラのポイントが固定で、(3D)マウスやトラックボールを使用して関心のあるオブジェクトを回転または移動させます。多くのゲーム、特にファーストパーソンシューティング(FPS)では、ワールドが固定で、カメラをワールドのあちこちに移動させます。 グラフィックスカードは、これらの二つの方法を区別せず、あなたが用意する model-view-projection matrix がそのまま適用されます。 主な違いは、MVP行列をマウスおよび/またはキーボードで操作する方法です。 一人称視点のカメラでは、MVP行列を2つのベクトルから導出します。カメラの位置とビューの角度です。
GLUTには、マウスの動きをキャプチャするための2つのコールバックがあります。 ひとつは、少なくとも1つのマウスボタンが押されている間にマウスが移動すると呼び出されるもので、もうひとつはマウスボタンが押されていない場合に呼び出されるものです。 私たちの場合は、2つのケースを区別しなくてもよいので、両方のコールバックに同じ関数を登録することができます:
アプリケーションやゲームは一人称モードになっているときは、通常マウスカーソルを表示したくありません。 この方法でそれを無効にすることができます:
一人称モードになっていない場合、たとえば、メニューを表示しているときや、またはゲームが一時停止している場合、は glutSetCursor(GLUT_CURSOR_INHERIT)で再びデフォルトのマウスカーソルを表示することができます。
motion()コールバック関数は、ウィンドウの左上を基準とした(またはウィンドウがフルスクリーンモードにある場合、画面の左上を基準とした)、現在のマウス座標を取得します。 しかし、知りたいのは現在の座標ではなく、関心があるのはマウスがどのくらい移動されたかを知ることだけです。 もちろん、前の motion()呼び出しから現在のものへの座標を引き算することもできますが、マウスカーソルがウィンドウや画面の端にあると、うまく動作しません! GLUTでの解決策は、マウスが移動するたびに、 glutWarpPointer()関数を使用してマウスカーソルをウィンドウの中心に戻すことです。 ただし、この機能を使用すると、モーション·コールバックを再び呼び出すためにGLUTを起動するので、 motion()への毎秒の呼び出しを無視しなければなりません:
上記の関数では、 dx と dy変数が、マウスカーソルが移動した距離をピクセル単位で保持します。
人間は惑星の上で暮らしているので、水平面内で周りを見わたすことと、上下を見ることの間には大きな区別があります。 最も興味深いものが私たち自身がいる地上と同じレベルで起こるというのも理由ですが、それだけでなく(垂直)軸を中心に見回すのは簡単で望むままにできても、頭を上げたり下げたりは限られるという理由もあります。 FPSゲームでは、垂直軸周りの回転はいくらでも好きなだけできますが、上下には+/- 90度に制限されます 。 この制限とは別に、視野角の変化はマウスの移動量にスケーリング係数をかけたものに等しくなります:
anglesから、単純な三角法を使用して見ている方向を計算することができます:
位置ベクトルと lookatが与えられると、ビュー行列を次のように作成することができます:
エクササイズ:
マウスはすでに視点の角度の決定に使用しているので、カメラ位置の移動に残されているのはキーボードです。 コンピュータは、マウスをどこまで移動させたかを伝えることができますが、キーは押されているか押されていないかのどちらかだけです。 キーが押されるたびに一定量でカメラの位置を移動させるキーボードのコールバックは簡単に登録することができますが、この結果は、カメラの動きが非常にぎくしゃくしてしまいます。 位置を直接制御する代わりに、キーボードを使用して、私たちの速度を変更するようにしたいところです。 キーがまったく押されていない場合、速度がゼロになります。 上矢印キーが押された場合、前方向に一定の速度を持ちます。 下矢印キーが押された場合、前方向に対して負の速度を持ちます。 右矢印が押された場合、横方向に一定の速度を持ち、等々。 glutSpecialFunc()でコールバックを登録することができ、 これは "特別な"キー(例えばカーソルキーなど)が押されるたびに呼び出されます。 しかし、そのキーが再び解放されたかどうかも知る必要があります。 そのために、 glutSpecialUpFunc()コールバックを登録できます:
2つのコールバック関数は次のようになります:
move変数はその後、現在押されている移動キーのビットマスクを収容します。 カメラの位置は、定期的に、好ましくはフレームごとに一回、更新する必要があります。 何もすることがないときに呼び出されるGLUT関数を登録することもできます:
その後、その関数内でカメラ位置を更新し、シーンを再描画するようGLUTに伝えます。 カメラ位置ベクトルを更新するために、どの方向が"前方", "右"等を知る必要があります。 ほとんどのゲームでは、 "前方"は私たちが見ている方向ですが、水平面に限られます。 通常、この理由はあなたが地面の上に立っているからで、たとえ歩き回っていて少し上下に目を向けても、床にとどまります。 "前"ベクトルから、 "右"ベクトルも導くことができ、そして"上"ベクトルは単に正のy方向を指します。 結果は次のようになります:
エクササイズ:
OpenGLプログラミング/Glescraft 5

ひとつめのチュートリアルでは、 多数のキューブをレンダリングする方法を見てきました。 ふたつめのチュートリアルでは、 潜在的に見えるキューブだけの面を描画する方法を見てきました。 それでも、すべてのチャンクが描画されているとき、三角形の多くは、画面の外にあるか、後ろ側をカメラに向けて処理されています(したがって、カリングされます)。 三角形が画面の外にあるか、カリングされている場合は、描画するピクセルが存在しないため、フラグメントシェーダが呼び出されることはありません。 三角形が画面の外にあるか、カリングされている場合は、描画するピクセルが存在しないため、フラグメントシェーダが呼び出されることはありません。 世界がさらに大きなると、もっと多くの時間が頂点シェーダに費やされます。 したがって実際に画面に描画される頂点のみをグラフィックスカードに送信したほうがベターです。
ほぼすべての大規模な3Dシーンでは、約半分の三角形は前を向いていて、他の半分は後ろを向いています。 潜在的に前を向く三角形だけを頂点シェーダにを送信することによって、そこに費やされる時間を効果的に半分も削減できます。 In our voxel world, our cubes have six faces, two for each axis. x軸に焦点を当てていきましょう。 キューブのx座標がカメラのx座標よりも小さい場合、 カメラが向いている方向は関係なくなり 、 、キューブの面のうちx軸の正の方向を向いているものだけが表示されます。 同様に、キューブのX座標がカメラより大きければ、x軸の負の方向に向いている面だけが見えます。 カメラのX座標が立方体の"内側 "である場合、どちらの面も表示されません。
しかしながら、これを個々のボクセルで行うことは困難です。 チャンク全体のVBOを2つに分割することをお勧めします。一方の部分は正のx方向を指す面で、もう一方が負のx方向を指す面です。 カメラがチャンクの正のx軸側にある場合、VBOの最初の部分だけをレンダリングすればよく、負側にある場合、ふたつめの部分だけをレンダリングすればよくなります。 カメラのx位置がチャンク"内"にある場合、問題が起きます。 その場合、VBO全体をレンダリングすることで安全を保てます。
y軸およびz軸でも同じように行えます。
エクササイズ:
カメラに360度のフィールド・オブ・ビューを持たせることは原理的には可能ですが(例えば魚眼レンズのものなど)、ほとんどの3Dアプリケーションやゲームはカメラに自身を制限してFOVを90度だけにしています。 この主な理由は、3Dの世界を投影するフラットスクリーンというのは、少なくとも目の前にある程度の距離があるからです。 スクリーンに詰め込みたい視野がより広くなるほど、さらなる歪みにつながります。 非常に大きな球形のスクリーンがある場合や、周りすべてにわたる複数の画面があるなら状況は異なりますが、ほとんどの人々の予算外です。 画面が1つだけの場合は、90度のFOVは歪みを無視できます。 しかし、これは他の270度が画面外にあることを意味します。 画面の外にあるものをレンダリングしようとして、時間を浪費しています。 個々の三角形の可視性を決定しようとする場合、それも同様にGPUにやらせることもあります。 しかし、チャンク全体の可視性を決定してみることもでき、そのうちどの部分も画面に表示されないことが確実なのもののレンダリングをスキップすることができます。
チャンクの可視性をチェックするためには、その中心の座標を見ます。 model-view-projection行列を使用して、画面上のどこに中心が現れるかを決定することができます:
MVPを中心の座標に適用した後、結果は clip coordinates内にあります。 その後xとyの座標をz座標で割ると、xおよびy座標の値は、 "正規化されたデバイス座標 "になり、点(-1, -1)はウィンドウの左下隅になり、そして(1, 1)は右上隅になります。 なのでxおよびy座標がその範囲外であれば、ウィンドウの外になります。 z座標の場合は、クリップ座標のままにしたほうが便利です。 zの負の値は、カメラの後ろであることを意味し、表示されません。
ここでは無視したことは、たとえチャンクの中心が見える窓の外にあるかもしれなくても、チャンクの一部がまだ目に見えることもあるということです。 この問題を解決するために、bounding sphereの直径によって決定される安全マージンを使用し、チャンク全体を保持するのに十分な大きさにします:
また、算出直径をwの座標によって割り、xおよびy座標と同じ座標空間にする必要があることに注意しましょう。
この技術は目に見えないチャンクを描画スキップするのに便利なだけでなく、見えるチャンクに対してチャンクに関連する他の作業を行うときにも使用できます。 カメラが急に旋回して、表示されているシーン全体が別の部分になるようなときは、多数のVBOsを急に更新する必要があります。 これだと無視できないくらい時間がかかってしまうので、各フレームで1つか少数のVBOsを更新して、フレームレートが低下しないようにすることは有意義です。 また、カメラに近いチャンクのVBOsを最初に更新することも有意義です。 カメラとチャンクの距離は、 coordsベクトルの長さを計算することによって簡単に決定できます:
なので優先順位は、最小 距離のチャンクに与えられるべきです。
OpenGLプログラミング/Glescraft 6

さて、ボクセルの世界を動きまわれるようになったので、ボクセルを追加、削除または変更したくなります。 ひとつめのチュートリアルでは、 シンプルな set()関数を実装して、任意のボクセルの内容を変更できるようにしました。 しかし、このトリックは、見ているのがどのブロックかを正確に判別するためのもので、より具体的にいえば、そのブロックのどの面を見ているかを判別します。
object selectionチュートリアルで見てきたように、ウィンドウ内の任意のピクセルの深度値を取得することができ、そして元のオブジェクト座標にその座標をunprojectできます。 現在のウィンドウの幅と高さ、 ww と wh、およびビュー行列と投影行列を考えて、これを中心にあるピクセルに対して次のように行います:
objcoordは中心ピクセルの座標を保持しますが、シンプルに浮動小数点値を切り捨てて最も近い整数にしてボクセルの座標を取得します。 ユーザーが現在どのボクセルを見ているかを明確にするために、その周りに bounding boxを描画することができます。 ワールドとの相互作用を許可するために、マウスボタンの1つがクリックされたときに呼び出されるコールバック関数を登録することができ、そして適切なチャンクに set()を使用することで、現在選択されているボクセルを変更することができます。 set()関数はチャンクをchangedとしてマークし、次のフレームがレンダリングされるとき、これが自動的にVBOを更新して変更を反映します。
既存のボクセルを変更したり削除することはうまくいっていますが、新しいボクセルを追加することもあります。 ボクセルを追加する場合はかなり論理的で、現在選択されているボクセルの隣に、どの面を見ているかに応じて追加されます。 これを行う1つの方法は、私たちは常にボクセルの表面上の点を見ることになるので、X、Y、Z座標のいずれかが常に正確に整数値を有するべきであることを認識することです。 実際には、これが本当に問題になることはありませんが、x、y、zのどれが整数値に 最も近いかを確認することができます。 x座標が最も近い場合、2つの面のいずれかがx方向に向いていることがわかります。 x座標がカメラのX座標よりも小さい場合、正のx方向に向く面を見ていることがわかり、そしてX座標がさらに小さい場合は、他の面を見ていることになります。 なので、新しいボクセルの座標を決定するために、まず最も近い整数の距離をみちびきだす関数を定義します:
その後、それを次のように使用します:
この方法には非常に遠く離れているボクセルでもうまく機能するという利点があります。 欠点は、時々、丸め誤差に起因して間違ったボクセルを選択することです。 この方法のもう一つのプロパティでは、部分的に透明なテクスチャを通してボクセルを見る場合、そして透明ピクセルがフラグメントシェーダでは破棄され、テクスチャの不透明な部分の一部を正確に指していない場合、部分的に透明なボクセルの背後に見えるボクセルを選択することになります。 あなたが求めるものによっては、これは機能でもありバグでもあります。
もうひとつのテクニックは、カメラから始まってあなたが見ている方向に進む直線を想像することです。 その線に沿って、ボクセルにあたるまで進むことができます。
この方法の利点は、よりいっそう正確だということです。 すべてのボクセルを不透明なものとして扱うので、部分的に透明なボクセルは見通すことができません。 欠点は、多くの計算を必要とすることで、計算量は見ているボクセルが遠くにあるほど増加します。 最大距離を制限して、近くボクセルだけを選択することが最善の方法です。
OpenGLプログラミング/Glescraft 7

見えるキューブ面をだけ描画することによって、さらには隣接する面をマージすることによって、ボクセル世界で描画する頂点の数を大幅に減らせることはすでに見てきました。 さらに、ジオメトリシェーダを使うことで、GPUに送信するデータ量を低減することができます。 このアイデアは、ジオメトリシェーダーにボクセル面の最もコンパクトな表現を送信し、そして6頂点(面を構成する2つの三角形のために)と他の必要になるかもしれないデータを生成させることです。 1つの頂点でボクセル全体を表すこともできますが、それではジオメトリシェーダーがどちらの側面をレンダリングしたらよいか判断できないことを意味し、なのでそれらが隠されているかどうかにかかわらす、6つの面すべてをレンダリングしてしまいます。 隠された面の描画にかかる時間は、ジオメトリシェーダーなどで頂点を扱うことで節約したぶんよりもGPU時間がかかってしまう可能性があります。 より良い方法は、その面の正反対の2つのコーナーから、2つの頂点(下図のAとC)の各面を頂点シェーダに送信することです。 この方法なら、マージされた面を表現することもできます。 面が矩形であり、x、yまたはz平面にあることがわかれば、他の2つの角(BとD)を再構築することができ、そして4つの角からはぎ取って2つの三角形(BACとACD)を作成することができます。 この方法で、面の法線を再構築することも可能で(ラインACとABの外積を使用して)、ライティング計算のために使用することもできます。

以前は、面の6つの頂点すべてに同じテクスチャ座標を渡す必要がありました。 ジオメトリシェーダーを使用するとき、シェーダは両方の入力頂点へのアクセス権を同時に持っているので、そのうちのひとつのテクスチャ座標だけを渡す必要があります。 シェーダは、6つの出力頂点すべてにそれをコピーすることができます。 また、wの座標を何か他のもののための第2の入力頂点として、例えば強度情報として使用できることも意味します。
ジオメトリシェーダーを使用する前に、GPUがそれをサポートしているのかを、GLEWを使ってチェックすることができます:
どんな種類の入力をジオメトリシェーダーが期待しているのか、そしてどのような出力を生成するのかということを、OpenGLに伝える必要があることを除けば、頂点シェーダやフラグメントシェーダの場合と同じようにジオメトリシェーダーをコンパイルしてリンクします。 私たちの場合では、入力としてLINESを期待し、出力としてTRIANGLE_STRIPSを生成します。 これは次のように行われます:
描画するときには、ちょうどGL_LINESを描いたようにすればよく、GPUが残りの面倒をみてくれます。
以前に、update()関数で、以下のような6つの頂点を生成する必要がありました(負のx方向から見た面において):
シンプルにコードのその部分を変更することで、ジオメトリシェーダ用の2つの頂点を生成することができます:
2つめの頂点で強度情報を渡す方法に注目しましょう。
ジオメトリシェーダーは次のとおりです:
頂点シェーダは何もする必要はありませんが、ジオメトリシェーダによって計算された頂点を通り過ぎます:
フラグメントシェーダは次のとおりです:
運転免許試験

運転免許試験(うんてんめんきょしけん)とは、日本において自動車を運転するのに必要な免許(国家資格)である。
自動車やオートバイを運転するのに必要な資格試験である。運転免許試験場で受験する一発試験や指定自動車教習所で受講して卒業検定に合格し、試験場で学科試験を受けて取得する試験である。
各免許区分(仮免許含む)の年齢および経歴制限は、次の通りとなる。
これ以外にも、視力・聴力・深視力(原付・普通などを除く)が一定以上の要件が必要となる。
PHP/入門/変数と値

変数は、値に名前をつけてプログラム中から参照できるようにする仕組みです。 変数は必ず名前を持ち、名前は識別子のルールに従います。
変数の名前は、$ で始まり識別子が続きます。
識別子は、先頭が _ または英字、それに 0 文字以上の _ または 英数字が続きます。
また、PHPでは、変数名の大文字小文字を区別します。
関数、ラベル、定数、クラス、トレイト、インターフェース、名前空間なども名前を持つことができますが、それぞれ識別子の規則に従います。
変数を使ったプログラム。
ほかの例も下記に見ていきましょう。
これは、変数の文字列への埋込み機能を使うと次のようにも書けます。
print は上位互換で短縮表記もある echo があるので殆ど使われませんが、Cのprintf()/sprintf()と同じ機能の、 printf()/sprintf()がPHPにはあり、書式化出力に便利です。
PHPでは他のプログラミング言語同様、数学風の演算子式で計算を行います。
整数除算は、intdiv(被除数, 除数) です
PHPも、多くのプログラミング言語と同じく演算子に優先順位があります。
は
ではなく
の順で評価されます(それぞれの演算子の優先順位については、後ほど表にまとめます)。
異なる優先順位の演算子であれば、優先順位に従い評価すればよいのですが、同じ優先順位の演算子が続いた場合はどうでしょう。
...これは交換則が成り立つので良い例ではないですね。
は
ではなく
の順で評価されます。このような評価順序の演算子を左結合の演算子と呼びます。
演算子は概ね左結合ですが、少数の例外があります。
これ(代入演算子)は、
の順(右結合)で評価されます。
また、
(冪乗演算子)も
の順(右結合)で評価されます。
リテラルとは、ハードコードされた値のことです。リテラルはスクリプトの中で特定の値を表現する手段となります。例えば代入の右辺には次のようなものがあります。
PHPの型と型名とリテラルの例を示します。
PHPには、$で始まる変数とは別に、イミュータブルなオブジェクト=定数を宣言することができます。
組込み関数 define() を使っても定義できますが
というバグ級の仕様上の問題(8.0.0で一部是正)があります。
const が使えるのであれば、define()は使うべきではありません。
const と似た仕組みに、PHP 8.1.0 以降のクラスのプロパティのreadonly修飾子があります。 ただし、readonly修飾子はプロパティにしか使えません。
また、クラスはクラススコープの定数「クラス定数」を定義することができます。
PHPには9つのマジカル定数( Magic constants )があり、それらは使用される場所によって変化します。 たとえば、__LINE__ の値は、スクリプトのどの行で使用されるかに依存します。 これらの「魔法の」定数は、実行時に解決される通常の定数とは異なり、すべてコンパイル時に解決されます。 これらの特殊な定数は大文字と小文字を区別しません。
今後に使う予定のない変数に unset() 関数を適用することで、明示的にその変数を使わないことを表明できます。 また、unsetした変数に束縛されていたメモリーオブジェクトのリファレンスカウントが一つ減るので、メモリーが開放される可能性があります。
unsetの適用後、変数を参照すると、言語処理系が警告をしてくれるので、バグなどを発見しやすくなります。
ためしに下記コード例では、unsetの適用後、変数を参照しています。
PHPでは、ループ変数のスコープはループではなく関数スコープ(あるいはグローバルスコープ)なので、ループを抜けたあと悪さをしないように、unset() しましょう(ループから脱走したリファレンスを使って代入すると発見困難なバグになります)。
ドメインによっては、 $ループ変数 = null; で標準化していることもありますが趣旨は同じです。
null は、変数の束縛を解く時につかわれ、その意味では unset() と似ています。 NULLが入った変数は、isset()はfalseを返します。
2022年12月現在の最新の安定バージョン v8.1.13 では、未定義(Undefined)の変数参照すると警告( Warning )が出ます。
エラー制御演算子(@)は、名前と機能がやや乖離していて、「メッセージ抑制演算子」程度の機能しかありません。 エラー制御演算子には、トラブルシューティングに役立つエラーや警告を表示させないという害悪があるので、他の方法(例えば例外処理)を検討するべきです。
OpenGLプログラミング/Motion Blur

カラーバッファ、デプスバッファ、ステンシルバッファとは別に、ほとんどのグラフィックスカードには、アキュムレーションバッファといわれるオフスクリーンのフレームバッファが用意されています。 これらは基本的に、1色につき16ビット以上の精度を持つカラーバッファです。 しかし、アキュムレーションバッファに直接描画することはできません。 その代わりに、アキュムレーションバッファ全体を一度に処理する演算がいくつかあります。
l glAccum(GL_MULT, value): アキュムレーションバッファ内のすべてのピクセルに valueを乗算する。
すべての場合において、 valueは浮動小数点数(GLfloat)です。 これらの関数を使うと、複数のフレームの(重み付けされた)和や平均を簡単に計算することができます。 このチュートリアルでは、この関数を使って、ほとんどのOpenGLプログラムにモーションブラーを簡単に追加する方法を紹介します。
モーションブラーは、オブジェクトが(カメラに対して)非常に速く動いたり、カメラの露光時間が非常に長くなったりして、露光中に一部の物体が半ピクセル以上動いてしまい、それが不鮮明に見えることで発生します。 モーションブラーは通常、好ましいものではありませんが、実際のカメラでは避けるのが難しい場合があります。 なぜなら、露光時間はシーン内の光の量に大きく依存するからです。 光量が少なければ露光時間が長くなり、ブレの影響が強くなります。 屋外でビデオカメラを使って撮影した映像と、室内で同じカメラを使って撮影した映像の「感じ」が違うのは、このためです。
アキュムレーションバッファを使ったモーションブラー効果は、実はとても簡単に作ることができます。
ここで、関数 do_time_evolution() は、シーン内の移動するオブジェクトの座標や、カメラ自体の動きの更新を行います。 シーンが描画された後、glSwapBuffers()によって画面に表示されますが、オプションとしてフレームレートを制限するためにしばらく待ちます。
多くのフレームを蓄積することで最高の効果が得られますが、GPUの能力によってすぐに制限されてしまいます。 蓄積するフレーム数を設定できるようにするか、1回のtimestepでレンダリングできるフレーム数を自動的に決定するようにするのがよいでしょう。
b:en:OpenGL Programming/Motion Blur
OpenGLプログラミング/Supersampling

白い背景の上に黒い線を描画するときに、コンピュータやGPUは、最も基本的なレベルにおいて、どのピクセルを黒にするべきかを決定します。 これは、水平または垂直のラインなら非常にうまくいきます。 しかし、ラインが斜めである場合は、ラインがスムーズにならず、ギザギザになることがすぐにわかります。 しかし、黒と白だけを使用するのではなく、グレーのピクセルを戦略的に配置すれば、目を欺いてラインがよりスムーズに見えるようにできます。 これは、アンチエイリアシングと呼ばれています。 アンチエイリアスする方法には様々なものがあり、ライン、他の形状、あるいはテキストへのものもあります。 この本の中で最古のトリックは、倍の大きさでラインを描き、その後結果の白黒画像を元のサイズに縮小して、2×2ピクセルの各グループの平均を取ることです。 結果として得られる画像は、グレーの5段階の明暗になり(黒と白を含む)、大きく改善されるはずです。 もちろん、3倍、4倍またはそれ以上の太さの線を引くこともできます(10、17またはそれ以上の明暗のグレーにも)。 このテクニックは、スーパーサンプリングと呼ばれています。 かなり大きな画像をレンダリングする必要があるため、非常に時間を食い、限られた量の明暗しか与えません。 しかし、大きな利点は、この手法が非常にシンプルで、ライン、テキスト、または3Dシーンを問わず、 *あらゆる*種類の画像で動作するということです。
アキュムレーションバッファを使用して同じテクニックを実装することもできます。 しかし問題は、アキュムレーションバッファが通常のカラーバッファより大きくなく、ぴったり同じ大きさしかないということです。 その代わりに、同じシーンを複数回レンダリングして、そのたびごとにほんの少しづつシフトさせることができます。 次のコードを使用して model-view-projection 行列を設定するところから始め、その後フレームをレンダリングするとします:
2x2のアンチエイリアスを行いたい場合、シーンを(0, 0)、(0.5, 0)、(0, 0.5)、(0.5, 0.5)ピクセルそれぞれシフトさせます。 これは簡単にできます。頂点に model-view-projection 行列を適用した後、私たちはスクリーン座標をもち、(0, 0)が左下、そして(1, 1)が右上のビューポートに対応します。 なので(0.5, 0.5)ピクセルだけシフトさせるために、(0.5 / W, 0.5 / h)単位の変換を適用する必要があり、ここでwとhはビューポートのピクセル単位での幅と高さです。 これが結果です: