公式の翻訳(少し磨き上げたもの)はこちらから入手できます。
リアルタイムグラフィックスをプログラミングする初心者向けの別の入門記事
私はかつて(迅速に)分子を視覚化する仕事がありました。 たとえば、分子は、次のような一連の球体として簡単に表すことができます。
具体的には、このウイルスは約300万個の原子で構成されています。 彼のモデルは素晴らしいサイト
rcsb.orgからダウンロードできます。
これは、シェーダーのトレーニングに最適なトピックです。
まず、OpenGLがどのように呼び出され、シェーダーコードがどのようにリンクするかを示します。
OpenGL helloworld
いつものように、コンパニオンコードの
リポジトリを作成しました。 OpenGL自体には、レンダリング用のコンテキストを作成する通常のクロスプラットフォームの方法がないため、ここではGLUTライブラリを使用してウィンドウを作成しますが、実際にはユーザーとのやり取りは行いません。
このチュートリアルのGLUTに加えて、GLUおよびGLEWライブラリが必要です。これが
やかんを描く最も簡単なプログラムです:
非表示のテキスト#include <GL/glu.h> #include <GL/glut.h> #include <vector> #include <cmath> const int SCREEN_WIDTH = 1024; const int SCREEN_HEIGHT = 1024; const float camera[] = {.6,0,1}; const float light0_position[4] = {1,1,1,0}; void render_scene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); gluLookAt(camera[0], camera[1], camera[2], 0, 0, 0, 0, 1, 0); glColor3f(.8, 0., 0.); glutSolidTeapot(.7); glutSwapBuffers(); } void process_keys(unsigned char key, int x, int y) { if (27==key) { exit(0); } } void change_size(int w, int h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glViewport(0, 0, w, h); glOrtho(-1,1,-1,1,-1,8); glMatrixMode(GL_MODELVIEW); } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowPosition(100,100); glutInitWindowSize(SCREEN_WIDTH, SCREEN_HEIGHT); glutCreateWindow("GLSL tutorial"); glClearColor(0.0,0.0,1.0,1.0); glutDisplayFunc(render_scene); glutReshapeFunc(change_size); glutKeyboardFunc(process_keys); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glutMainLoop(); return 0; }
理解しましょう。すぐにmain()から始めます。
- 最初の行は単にライブラリを初期化し、2番目の行はダブルフレームバッファ、カラー、およびzバッファを使用することを示しています。
- 次に、ウィンドウのサイズ、場所、タイトル、および背景色(この場合は青)を指定します。
- 次に、興味深いことが始まります。glutDisplayFunc、glutReshapeFunc、glutKeyboardFuncは、コードのコールバックを設定します。コールバックは、画面の再描画、ウィンドウのジオメトリの変更、キーボードの処理のイベントで呼び出されます。
- 次に、「はい、1つの光源があります」、「はい、zバッファを使用する必要がある」などと単純に言う特定のチェックボックスのセットを含めます。
- さて、最後のコードは、メインウィンドウの処理サイクルを呼び出すことです。glutMainLoopが動作している間、オペレーティングシステムはウィンドウを表示します。
キーボード処理は最も簡単です。ESCキーを押すと、プログラムを(やや残酷に)終了します。 ウィンドウのジオメトリを変更するとき、OpenGLに投影がまだ直交しており、ウィンドウのフルサイズで座標[-1,1] x [-1,1]の正方形を表示することを伝えます。
render_scene()関数で最も興味深いこと。
- まず、画面と対応するzバッファーを消去します
- 次に、ModelViewマトリックスをゼロにし、カメラの現在の位置をロードします(この場合は変更されないため、main()で定義できます)
- 赤い色を設定する
- やかんを描く
- 画面バッファーの切り替え
その結果、次の図を取得する必要があります。
GLSL helloworld
ここでは、シェーダーを最も簡単に使用するためのソースを見つけることができます。 Githubには非常に便利なバージョン比較ツールがあります。
変更点を確認してください。
画像は次のようになります。
コードに正確に何が追加されましたか? 開始するために、2つの新しいファイルが追加されました:frag_shader.glslおよびvert_shader.glsl。C++ではなく
GLSLで記述されています。 これは、グラフィックスカードに直接供給されるシェーダーコードです。 また、main.cppには、これらのシェーダーを使用する必要があることをOpenGLに伝えるバインディングが追加されました。
つまり、prog_hdlrハンドラーが作成され、以前にテキストファイルから読み取られ、コンパイルされた頂点シェーダーとフラグメントシェーダーがそれにリンクされます。
標準のOpenGLを使用して「分子」を描画します
そこで、OpenGLコンテキストを呼び出してシェーダーをリンクする方法を学びました。 それらを脇に置き、何万ものランダムな球体を描画しましょう。 .pdb形式は非常にテキスト形式で非常にシンプルですが、コードをできるだけシンプルに保ちたいので、実際の分子をロードしません。 タスクは次のとおりです。ランダムな色のランダムな球を多数描画してみましょう。
シェーダーを使用せず、glutSolidSphere()を呼び出して1万個の球体を描画するコミットです。
変更
を見ることを忘れないでください 。 7つの要素の配列を含むatom配列を追加しました。最初の3つは現在の原子の中心の座標、次に半径、さらに3つの色です。
これは次のような写真です。
個人的には、この写真を見ると痛いです。2つの球の交点は円の弧で、ここにはすべてがありますが、円はありません。 これは、各球体を16個の緯線と16個の子午線、つまり各球体について約500個の三角形で描いたという事実の結果です。 そして、写真の質の低さに加えて、効率に関する直接的な疑問が残っています.1000万個の原子を描画したい場合、50億個の三角形を送信する必要があり、バスの帯域幅に大きな打撃を与え始めます。
シェーダーは役立ちますか?
彼らはできる! シェーダーは照明の変更だけではありませんが、本来はそれを行うことを目的としていました。 CPUとGPU間のデータ転送を最小限に抑えたいため、描画する必要がある各球体に1つの頂点のみを送信します。
古いGLSL#120でコードを書いています。 非常に古いマシンで実行する必要があります。新しいGLSLの構文は少し異なりますが、一般的な考え方はまったく同じです。同じ領域を描画
するコードですが、シェーダーを使用しています。
それでは、アイデアは何ですか?
まず、CPU側で、描画する必要がある各球体に1つの頂点を送信します。
シェーダーを作成しない場合、次の図が表示されます。
さらに頂点シェーダーでは、gl_PointSizeを変更できます。これにより、結果として正方形のセットが得られます。
フラグメントシェーダーは、正方形の各ピクセルに対して実行されることに注意してください!
つまり、すべてが非常に単純になったので、正方形の指定されたピクセルが中心からどれだけ離れているかを検討します。
球体の半径を超えている場合、discardを呼び出します。
各球体の中心を通る平らな紙吹雪のセットを手に入れました。
興味深いことに、各フラグメントの深さを変更する権利があります。
照明を計算するためだけに残っており、そのような写真は最終的に判明します:
それを三角形の球体を描いた絵と比較してください。 画像ははるかに正確で、より高速に描画されます。
ここで、.pdbファイルの読み取り値、画面空間アンビエントオクルージョンを追加する必要があり、この記事のタイトルイメージを取得できます。
シェーダーを使用して球体を描画する方法を理解したいが、glOrthoではなく遠近法を使用したい人には、素晴らしい
記事があります。