{
レッスン 9 へようこそ。ここまでで、OpenGL について十分に理解できたはずです。
「CKER: もしそうでないなら、それは私の翻訳者のせいでしょう...」。
(マイリングはこう付け加えた: 私の罪はさらに大きい、笑)
OpenGL ウィンドウのセットアップの詳細をすべて学習しました。
回転するオブジェクトに光と色の混合 (透明度) をマッピングして追加する方法を学びます。
このレッスンは中級チュートリアルとして考慮してください。
3D シーン上でビットマップを移動し、(カラー ブレンディングを使用して) ビットマップから黒いピクセルを削除する方法を学びます。
次に、白黒のテクスチャに色を付け、最後に豊かな色を作成する方法を学びます。
また、異なる色のテクスチャを互いに混ぜ合わせて、シンプルなアニメーション効果を得ることができます。
最初のレッスンのコードに基づいて修正を加えていきます。まず、プログラムのソース コードの先頭にいくつかの変数を追加します。
わかりやすくするためにコード全体を書き直しました。
}
ヴァール
h_RC: HGLRC; // レンダリング コンテキスト (シェーディング記述テーブル)。
h_DC: HDC; // デバイスコンテキスト (デバイス記述テーブル)
h_Wnd: HWND;
h_Instance: HINST; // プログラムインスタンス(インスタンス)。
key : Array[0..255] Of Boolean // キーボード ルーチンの配列;
{以下の行が新たに追加されました。
Twinkle と tp はブール変数です。つまり、TRUE または FALSE にのみ設定できます。
Twinkle は、フリッカー効果が有効かどうかを追跡するために使用されます。
tp は、「T」キーが押されたか放されたかを確認するために使用されます。
(押すと tp=TRUE、離すと tp=FALSE)。
Twinkle : ブール値 // きらきら星 (新規)
tp : ブール値; // 'T' が押されましたか?
{それでは構造体を作成しましょう。
構造という言葉は怖く聞こえますが、そうではありません。 (Delphiのレコードタイプです)
構造は、単純なタイプのデータ (および変数など) のセットを使用して、類似したデータのより大きな組み合わせを表現します。
私たちは星を追跡していることを知っています。
下に星が見えます。
各星には 3 つの整数の色の値があります。赤 (r)、緑 (g)、および青 (b) が 1 つずつあります。
さらに、各星は画面の中心からの距離が異なります。
そして画面の中心を原点として360度どの角度でも可能です。
距離を追跡するための dist の浮動小数点数。
角度の浮動小数点数は、星の角度値を追跡します。
そこで、一連のデータを使用して、画面上の星の色、距離、角度を記述しました。
残念ながら、私たちは複数の星を追跡しています。
ただし、50 個の赤の値、50 個の緑の値、50 個の青の値、50 個の距離の値を作成する必要はありません。
と 50 の角度値を指定して、星型配列を作成するだけです。 }
タイプ
stars = Record // スターという名前のスターの構造を作成します
r、g、b: 整数; // 星の色;
dist: GLfloat //中心からの星の距離
angle: GLfloat //星の現在の角度
終わり;
ヴァール
star : Array[0..49] Of Stars; // 'stars' 構造体を使用して、50 個の要素を含む 'star' 配列を生成します。
{次に、いくつかの追跡変数を設定します。
観測者からの星の距離変数(ズーム)、
星を見る角度(傾き)、
そして、きらめく星を Z 軸の周りに回転させる可変スピン。
ループ変数は 50 個の星を描画するために使用されます。
texture[1] は、白黒のテクスチャを保存するために使用されます。
さらにテクスチャが必要な場合は、
使用するテクスチャの数に応じて、テクスチャ配列のサイズを増やす必要があります。
}
zoom : GLfloat = -15.0; // 観測者からの星の距離
tilt : GLfloat = 90.0; // 星の傾き
stop : GLfloat; // きらめく星の回転
ループ : Gluint; // グローバル ループ変数
texture : Array[0..1] Of Gluint // テクスチャを保存します。
プロシージャ glGenTextures(n: GLsizei; 変数テクスチャ: stdcall);
opengl32;
プロシージャ glBindTexture(ターゲット: GLenum; テクスチャ: stdcall);
opengl32;
{
すぐ上のコードは、テクスチャをロードするために使用するコードです。
このコードについては詳しく説明しません。
これは、レッスン 6、7、および 8 で使用したコードとまったく同じです。
今回ロードされたビットマップはstar.bmpと呼ばれます。
ここでは glGenTextures(1, &texture[0]) を使用します。
テクスチャを生成します。テクスチャは線形フィルタリングを使用します。
}
Function LoadTexture: boolean //ビットマップをロードしてテクスチャに変換します。
ヴァール
Status : boolean // ステータスインジケーター
TextureImage : Array[0..1] Of PTAUX_RGBImageRec // テクスチャの保存領域を作成します。
始める
ステータス := false;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // ポインタを NULL に設定します。
TextureImage[0] := LoadBMP('Star.bmp');
TextureImage[0] <> Nil の場合
始める
ステータス := TRUE // ステータスを TRUE に設定します。
glGenTextures(1, texture[0]); // テクスチャを作成します
// 最近接フィルター マップを作成します
glBindTexture(GL_TEXTURE_2D, テクスチャ[0]);
// テクスチャを生成する
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY、0、GL_RGB、GL_UNSIGNED_BYTE、
テクスチャイメージ[0].data);
終わり;
If assign(TextureImage[0]) then // テクスチャが存在するかどうか
If assign(TextureImage[0].data) then // テクスチャ画像が存在するかどうか
TextureImage[0].data := Nil // テクスチャ画像が占有しているメモリを解放します。
TextureImage[0] := Nil // 画像構造を解放します。
result := ステータス // ステータスを返します。
終わり;
{glInit()でOpenGLレンダリングモードを設定します。ここでは深度テストは使用しません。
レッスン 1 のコードを使用する場合、
glDepthFunc(GL_LEQUAL)とglEnable(GL_DEPTH_TEST)が削除されているかどうかを確認してください。
そうしないと、表示される結果は混乱したものになります。
ここではテクスチャマッピングを使用します。
したがって、最初のレッスンに含まれていないコードが追加されていることを確認してください。
色を混合することでテクスチャ マッピングが有効になっていることがわかります。
}
プロシージャ glInit();
始める
If (Not LoadTexture) then // テクスチャ読み込みサブルーチンを呼び出す (新規)
exit; // ロードに失敗した場合は終了(新規)
glEnable(GL_TEXTURE_2D); // テクスチャマッピングを有効にする
glShadeModel(GL_SMOOTH); // 影のスムージングを有効にする
glClearColor(0.0, 0.0, 0.0, 0.5); // 黒の背景
glClearDepth(1.0); //深度バッファを設定します。
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 実に細かい遠近補正
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // 半透明効果を実現するカラー混合関数を設定します。
glEnable(GL_BLEND); // カラーブレンドを有効にする
{以下は新しいコードです。
各星の開始角度、距離、色を設定します。
構造のプロパティを変更するのがいかに簡単であるかがわかるでしょう。
50 個の星すべてが循環されます。
star[1] の角度を変更するには、star[1].angle=特定の値を指定するだけです。
それはとても簡単です! }
For ループ := 0 To 49 Do // すべての星を設定するループを作成します
始める
star[loop].angle := 0.0; // すべての星は角度 0 から始まります。
{ループ 番目の星の中心からの距離を、ループの値と星の総数で割って、5.0 を掛けます。
基本的に、これにより、後者の星が前の星よりも中心から少し離れた位置に配置されます。
このように、ループが 50 (最後の星) の場合、ループを num で割った値はちょうど 1.0 になります。
5.0 を掛ける必要がある理由は、1.0*5.0 が 5.0 であるためです。
『CKER: ナンセンス、ナンセンス!なんでこの外国人はコン・イジに似ているんだ! :)』
5.0 はすでに画面の端に近づいています。星が画面から飛び出すのが嫌なので、5.0 が最適です。
もちろん、画面の奥にシーンを設定すると、
5.0 より大きい値を使用することもできますが、星が小さく見えます (すべて遠近法のせいです)。
また、各星の色が 0 から 255 までの乱数であることもわかります。
ここでの色の値の範囲が、OpenGL の通常の範囲である 0.0 ~ 1.0 ではないのはなぜなのか疑問に思われるかもしれません。
ここで使用する色設定関数は、以前の glColor4f の代わりに glColor4ub です。
ub は、パラメータのタイプが符号なしバイトであることを意味します。
バイトの値の範囲は 0 ~ 255 です。
浮動小数点乱数を取得するよりも、バイト値を使用してランダムな整数を取得する方が簡単なようです。
}
star[loop].dist := (Trunc(loop) / 50) * 5.0; // 中心からの星の距離を計算します。
star[loop].r := random(256) // star[loop] にランダムな赤色コンポーネントを設定します。
star[loop].g := random(256) // star[loop] にランダムな赤色コンポーネントを設定します。
star[loop].b := random(256) // star[loop] にランダムな赤色コンポーネントを設定します。
終わり;
終わり;
{
次に、glDraw() 描画コードに移ります。
レッスン 1 のコードを使用している場合は、古い DrawGLScene コードを削除し、以下のコードをコピーするだけです。
実際、最初のレッスンのコードには 2 行しかないため、削除する部分はあまりありません。
}
プロシージャ glDraw();
始める
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 画面と深度バッファをクリアします。
glBindTexture(GL_TEXTURE_2D, texture[0]); //テクスチャを選択
For ループ := 0 To 49 Do // ループしてすべての星を設定します
始める
glLoadIdentity(); // 各星を描画する前に、モデル観測行列をリセットします。
glTranslatef(0.0, 0.0,zoom); // 画面の奥へ進みます ('zoom' の値を使用)
glRotatef(tilt, 1.0, 0.0, 0.0); // チルト表示角度 (「tilt」の値を使用)
{
では、星を移動してみましょう。
星は画面の中央から始まります。
最初に行う必要があるのは、Y 軸に沿ってシーンを回転することです。
90 度回転すると、X 軸は左から右ではなく、内側から外側へ画面の外に出ます。
わかりやすくするために、例を挙げてみましょう。あなたが家の真ん中に立っていると想像してください。
ここで、左側の壁には「-x」と表示され、正面の壁には「-z」と表示されていると想像してください。
右側の壁は +x、後ろの壁は +z です。
家全体が右に 90 度回転しても、あなたが動かなければ、正面の壁は -z ではなく -x になります。
他のすべての壁も同様に動きます。 -z は右側、+z は左側、+x は後ろに表示されます。
頭がおかしいのですか?シーンを回転すると、x 平面と z 平面の方向が変わります。
コードの 2 行目は、x 軸に沿って正の値を移動します。
通常、x 軸の正の値は、画面の右側 (つまり、通常の x 軸の正の方向) への移動を意味します。
ただし、ここでは y 軸を中心に座標系を回転させるため、x 軸の正の方向はどの方向でも構いません。
180度回転させると画面の左右が鏡面になります。
したがって、正の X 軸に沿って移動すると、左、右、前または後ろに移動する可能性があります。
}
glRotatef(star[loop].angle, 0.0, 1.0, 0.0); //現在描画されている星の角度に回転します。
glTranslatef(star[loop].dist, 0.0, 0.0); // X 軸に沿って前方に移動します。
{
次のコードにはちょっとしたトリックがあります。
星は実際には平らなテクスチャです。
ここで、画面の中央に平らな四角形を描画し、テクスチャを適用すると、見栄えが良くなります。
すべてはあなたの想像どおりです。しかし、y 軸に沿って 90 度回転すると、
画面上で自分に面したテクスチャの 2 つの面は、右側と左側だけです。 細い線のように見えるだけです。
これは私たちが望んでいることではありません。画面がどのように回転または傾いても、星が常に私たちを向いているようにしたいと考えています。
これは、星を描画する前に星に対して行われた回転をキャンセルすることで実現されます。
回転に対抗するために、回転を逆にすることができます。画面を傾けると、実際には星が現在の角度で回転します。
順序を逆にすることで、星を現在の角度で「逆回転」します。つまり、星は現在の角度の負の値だけ回転します。
つまり、
星を 10 度回転した場合は、星がその軸上で再び画面に向くように -10 度回転します。
以下の最初の行は、y 軸に沿った回転をキャンセルします。次に、X 軸に沿って画面の傾きをオフセットする必要もあります。
これを行うには、画面を再度回転する (tilt) だけで済みます。
x 軸と y 軸の回転をキャンセルすると、星は再び完全に私たちの方を向くようになります。
}
glRotatef(-star[loop].angle, 0.0, 1.0, 0.0); // 現在の星の角度をキャンセルします。
glRotatef(-tilt, 1.0, 0.0, 0.0); // 画面の傾きをキャンセル
{tinkle が TRUE の場合、まず回転していない星を画面上に描画します。
星の総数 (num) から現在の星の数 (loop) を引き、さらに 1 を引きます。
各星の異なる色を抽出します (ループ範囲が 0 から num-1 であるため、これが行われます)。
たとえば、結果が 10 の場合、星の 10 番の色を使用します。
このように、隣接する星の色は常に異なります。良いアイデアではありませんが、効果はあります。
最後の値はアルファ チャネル コンポーネントです。値が小さいほど、星は暗くなります。
Twinkle が有効になっているため、各星は 2 回描画されることになります。
マシンのパフォーマンスによっては、プログラムの実行が遅くなります。
しかし、2回のパスで描かれた星の色は互いに混ざり合い、素晴らしい効果を生み出します。
同時に、最初のパスでは星が回転しなかったため、きらめきを有効にした後の星はアニメーション効果のように見えます。
(ここで理解できない場合は、プログラムの実行結果を自分で確認してください。)
テクスチャの色付けが簡単であることは注目に値します。
テクスチャ自体は白黒ですが、テクスチャはペイントする前に選択した色に変わります。
さらに、ここで使用するカラー値はバイト型であることにも注意してください。
通常の浮動小数点数の代わりに。アルファチャンネルコンポーネントもこんな感じです。 }
If (きらめき) then // きらめきエフェクトを有効にする
始める
// バイト値を使用して色を指定します
glColor4ub(star[(50 - ループ) - 1].r, star[(50 - ループ) - 1].g,
star[(50 - ループ) - 1].b, 255);
glBegin(GL_QUADS); // テクスチャマップされたクワッドの描画を開始します。
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // 四角形描画の終了
終わり;
{
次に、星の 2 番目のパスを描画します。
前のコードとの唯一の違いは、今回は星が確実に描画され、星が Z 軸を中心に回転することです。
}
glRotatef(spin, 0.0, 0.0, 1.0); // Z 軸を中心に星を回転します。
// バイト値を使用して色を指定します
glColor4ub(スター[ループ].r, スター[ループ].g, スター[ループ].b, 255);
glBegin(GL_QUADS); // テクスチャマップされたクワッドの描画を開始します。
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // 四角形描画の終了
{以下のコードは星の動きを表しています。
スピン値を増やしてすべての星を回転させます (回転)。
次に、loop/num だけ各星の回転角度を増加させます。
これにより、中心から遠い星はより速く回転します。最後に、画面の中心から各星の距離を縮めます。
星が常に画面の中央に吸い込まれているように見えます。 }
スピン := スピン + 0.01; // 星の回転
star[loop].angle := star[loop].angle + Trunc(loop) // 星の回転角度を変更します。
star[loop].dist := star[loop].dist - 0.01; // 中心からの星の距離を変更します。
{次の数行では、星が画面の中心に触れたかどうかを確認します。
星が画面の中心に達したら、新しい色を与え、外側に 5 単位移動します。
スターはスクリーンの中心に戻る旅に乗り出します。 }
If (star[loop].dist < 0.0) then // 星は中心に到達しましたか?
始める
star[loop].dist := star[loop].dist + 5.0 // 5 単位外側に移動します。
star[loop].r :=random(256); // 新しい赤色コンポーネントを割り当てます。
star[loop].g := random(256) // 新しい緑色のコンポーネントを割り当てます。
star[loop].b :=random(256); // 新しい青色のコンポーネントを割り当てます。
終わり;
終わり;
終わり;
{
次に、キーボードを監視するコードを追加します。
WinMain() に移動します。 SwapBuffers(hDC) 行を見つけます。
この行の後にキーボード監視コードを追加します。
コードは、T キーが押されたかどうかをチェックします。
T キーを押して放すと、if ブロック内のコードが実行されます。
トゥインクルが FALSE の場合、TRUE になります。
逆に。 T キーを押している間、tp は TRUE になります。
これにより、T キーを押し続けた場合にブロック内のコードが繰り返し実行されるのを防ぎます。
}
If (keys[ord('T')] And Not tp) then // T キーが押されていて、tp 値が FALSE かどうか
始める
tp := TRUE // はいの場合、tp を TRUE に設定します。
Twinkle := トゥインクルではありません // トゥインクルの値を反転します。
終わり;
{
以下のコードは、T キーが離されたかどうかを確認します。
その場合は、tp=FALSE を設定します。
tp の値が FALSE でない限り、
そうしないと、T キーを押したままにしても何も起こりません。したがって、このコード行は重要です。
}
If (Not Keys[Ord('T')]) then // T キーは離されましたか?
始める
tp := FALSE // はいの場合、tp は FALSE です。
終わり;
{残りのコードは、上下の矢印キー、ページアップ キーまたはページダウン キーが押されたかどうかを確認します。 }
If (keys[VK_UP]) then // 上矢印キーが押されましたか?
tilt :=tilt - 0.5; // 画面を上に傾けます。
If (keys[VK_DOWN]) then // 下矢印キーが押されましたか?
tilt :=tilt + 0.5; // 画面を下に傾けます。
If (keys[VK_PRIOR]) then // ページアップキーが押されましたか?
ズーム := ズーム - 0.2;
If (keys[VK_NEXT]) then // ページダウンキーが押されましたか?
ズーム := ズーム + 0.2;
{
このレッスンでは、グレースケール ビットマップ テクスチャをロードする方法を説明するために最善を尽くします。
背景色を削除した後(混合色を使用)、再度色を付けて、最後に 3D シーン内で動かします。
美しい色とアニメーション効果を作成する方法を説明しました。
実装の原則は、ビットマップのコピーを元のビットマップに重ねることです。
これまで私が教えてきたことをしっかりと理解していれば、
独自の 3D デモを問題なく作成できるはずです。
基本はすべて網羅されています! }
//========マイリング:
//講義 1 ~ 9 を翻訳しました。NEHE さんのおっしゃるとおり、基本的な知識は説明されています。
//次のチュートリアルを見たところ、他の人が書いたもののようです。良い例があれば、選択して従うことにします。
//更新しました、とても疲れたので昼寝してください:)、また次回お会いしましょう