画像表示についての説明の 2 ページ目です。
本当は早く文字表示についてのページを書いてしまいたかったため、最初は「画像の表示」の説明を 1 ページだけで終わらせるつもりでした。
ですが、今まで説明していなかったこと, 画像の表示に関する最低限必要な技術(個人的に)の紹介について、今まで全く書いていなかったので、ここでページを割いて説明します。
今回は説明を少し多めに、1 つサンプルプログラムを載せるだけなので、前のページよりは短くなると思います。
これまで説明していなかった(忘れてたとも言う)事柄の中でかなり大切なことの 1 つが、「座標」についてです。
前回までのプログラムで頂点の座標を指定した時、何気なく(0.0, 1.0), (-1.0, 0.0)といった数値を使っていましたが、なぜその数値を使うとああいった結果になるのかをこれから説明します。
OpenGL では、最初からウィンドウ上の座標を指定して立体や画像オブジェクトを配置するのではなく、オブジェクトごとに専用の空間と座標系を用意した後、いくつかの段階を経て、最終的に共通の座標系(ウィンドウ)へと投影する仕組みをとっています。
わざわざ個別の座標系を用意して、なんて煩雑なことをやっているのはもちろん理由があります。
特定の座標系を使ってオブジェクトを配置すると、物体を座標系内で移動させるたびに、形状を定義し直す必要が出るからです。。
「画像などのオブジェクト=コンピュータ上のデジタルデータ」だから、まとまったデータのコピー, 移動などといった作業はコンピュータの得意分野ですからね。
さて、下にオブジェクトの座標が与えられてからウィンドウ上に投影されるまでの流れ(「ビューイングパイプライン」)を書きます。
「モデリング」「射影変換」といった内容について、残念ながら“自分”の知識では詳しく書けないので、真面目に勉強したい方は CG についての参考書(CG-ARTS 協会から出されてる教科書とか?)を読むことをオススメします。
glVertex で与えているのは、オブジェクトの形状データなので、モデリング座標系上での座標です。
同じように glTexCoord も、テクスチャの形状データが定義されているテクスチャ座標系はモデリング座標系の仲間なので、モデリング座標系上の座標を指定していることになります。
ちなみに前々回, 前回のプログラムでは「視野変換」, 「射影変換」, 「ビューポート変換」の設定を全くしていません。
まあ、テクスチャ座標系については少し別物なので省くとして、それでは glVertex に与えた数値の -1.0~1.0 という数字はどこから来たのか?
これはビューボリュームの初期値が、x: -1.0~1.0, y: -1.0~1.0, z: -1.0~1.0、となっているからです。
上の画像はビューボリュームの面(2 次元)を見たものです。すでに作ってしまったので一応貼っておきます。
また、ビューポートも、初期設定では描画範囲がウィンドウ全体となっています。
glVertexでの(0.0, 0.0)の位置がウィンドウの真ん中になったり、(1.0, 1.0)がウィンドウの右上隅になったりしたのはそのためです。
当然、ビューボリュームやビューポートの設定を変えてやれば、座標値の有効範囲が変わるので、同じ(0, 0)という座標を glVertex で与えても、ウィンドウ上の位置は変わってしまいます。
後、ここに 射影・ビューポート変換などについて説明された pdf 資料が置いてあったので、こちらも見てみるといいかもです。
なお、ビューイングパイプラインについて書いてあるのは前半だけで、後半以降は3次元物体のモデリングに関する話になっていますが。
あともう 1 つ、座標関連で注意しなければいけないことがあります。
上の画像の例を見ればわかる通り、ファイルに格納されている時点での画像の座標とテクスチャ座標系とで、例えば(4, 4)のピクセルと(1.0, 1.0)のピクセルは色が異なっています。
そのまま「画像ファイル内の座標系の点A(x, y) = テクスチャ座標系の点A'(x/4, y/4)」という関係にはなっていませんよね?
「A(x, y) = A'(x/4, -y/4)」となっています。
画像ファイル内での座標とテクスチャ座標系での座標の対応関係を知っておかないと、「なぜかテクスチャ画像を貼ると上下が反転する」といった現象の原因が特定できません。
次のページの「文字の表示」で文字を表示する際、何も考えずにテクスチャを作成・貼付をすると、文字が上下反転した状態で表示されてしまうので注意が必要です。
確か、テクスチャ作成時の設定でも、左右・上下反転は出来た気はするが。
上の説明がかなり長くなってしまいました。こんなはずではなかったのに……。
ともかく。今度は、実際にサンプルプログラムを書いてみて、ビューボリュームやビューポート変換の設定を変えてみるとどうなるかを確かめてみましょう。
ついでに、アルファ値を用いた半透明色の表示などもやってみます。
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. |
|
実行結果はこちら。
だんだんとソースコードの分量が長くなって来ましたね。
ヘッダファイルとかに define とか include をまとめるなどして、少しでもソースコードを分割した方がいいのだろうか…。
それはともかく、太字で示した関数の解説を始めます。
定数 | 関連要素 | 算出される混合係数 |
---|---|---|
GL_ZERO | source, destination | (0, 0, 0, 0) |
GL_ONE | source, destination | (1, 1, 1, 1) |
GL_DST_COLOR | source | (Rd, Gd, Bd, Ad) |
GL_SRC_COLOR | destination | (Rs, Gs, Bs, As) |
GL_ONE_MINUS_DST_COLOR | src | (1, 1, 1, 1) - (Rd, Gd, Bd, Ad) |
GL_ONE_MINUS_SRC_COLOR | destination | (1, 1, 1, 1) - (Rs, Gs, Bs, As) |
GL_SRC_ALPHA | src, target | (As, As, As, As) |
GL_ONE_MINUS_SRC_ALPHA | src, destination | (1, 1, 1, 1) - (As, As, As, As) |
GL_DST_ALPHA | src, destination | (Ad, Ad, Ad, Ad) |
GL_ONE_MINUS_DST_ALPHA | src, destination | (1, 1, 1, 1) - (Ad, Ad, Ad, Ad) |
GL_SRC_ALPHA_SATURATE | src | (f, f, f, 1); f = min(As, 1 - Ad) |
このプログラムで行なっていることで重要なのは、glColor 関数によってテクスチャ画像の RGBA 成分の割合を調整できてしまう、ということだと思います。
glDrawPixels 関数の場合では、“自分”が試した限りでは同じことが出来なかったです。
まあ、元の画像が 24bit(RGB カラー)であっても、アルファブレンド処理が出来る、というわけです。
もしくは、公式通りに上手に調整すれば、輝度を調節する処理も可能なはず……。
最後に、このページで紹介した関数の一覧を。