web-dev-qa-db-ja.com

OpenGLでライティングを有効にすると、色が消えるのはなぜですか?

OpenGL APIとGLUTを使用してC++でグラフィックアプリケーションを開発しています。

照明を追加するために、モデルビューマトリックスに次の変更を加えました。

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);

// Create light components.
GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
GLfloat diffuseLight[] = { 0.8f, 0.8f, 0.8, 1.0f };
GLfloat specularLight[] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat position[] = { 0.0f, 0.0f, 0.0f, 1.0f };

// Assign created components to GL_LIGHT0.
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
glLightfv(GL_LIGHT0, GL_POSITION, position);

照明は大部分は機能すると私は信じていますが、私のオブジェクトの色はすべて消えます。私が見るのは、全体像の黒と白のシルエットだけです。

なんでこれなんだろう?

26

ライティングが有効になっている場合、頂点の色はglColorまたはglColorPointerによって設定された色からではなく、ライティング計算を使用してライトの色と組み合わせて現在設定されているマテリアルの色によって決まります。

したがって、オブジェクトの色を変更するには、レンダリングの前に glMaterial 関数を使用して、マテリアル設定(デフォルトでは拡散灰色のマテリアル)を変更する必要があります。基本的に、異なるライトカラー(_GL_DIFFUSE_、...)のそれぞれに対応するマテリアルカラーがあり、発光マテリアル(_GL_EMISSION_)を概算してマテリアルの粗さを制御するためのいくつかの追加プロパティがあります(_GL_SHININESS_)。 OpenGLの照明機能の紹介資料を読んで、その機能を理解してください。

コードをプレーンカラーからライティングにすばやく適合させる(または頂点ごとのマテリアルプロパティを有効にする)ためにできることは、カラーマテリアルを使用することです。 glEnable(GL_COLOR_MATERIAL)を呼び出し、 glColorMaterial で適切なマッピングを設定することにより、現在の頂点カラーを変更するたびに、特定のマテリアルカラーを変更するようにOpenGLを構成できます(glColorまたはglColorPointer)。

30
Christian Rau

glEnable(GL_COLOR_MATERIAL)を試してください。

一般的なOpenGLの落とし穴#14を参照してください

  1. 慎重に使用できるカラー素材

OpenGLのカラーマテリアル機能は、マテリアルパラメータを変更するためのより安価な方法を提供します。カラーマテリアルを有効にすると、マテリアルカラーは現在のカラーを追跡します。つまり、比較的高価なglMaterialfvルーチンを使用する代わりに、glColor3fルーチンを使用できます。

以下は、カラーマテリアル機能を使用して、三角形の各頂点の拡散色を変更する例です。

glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glBegin(GL_TRIANGLES);
    glColor3f(0.2, 0.5, 0.8);
    glVertex3f(1.0, 0.0, 0.0);
    glColor3f(0.3, 0.5, 0.6);
    glVertex3f(0.0, 0.0, 0.0);
    glColor3f(0.4, 0.2, 0.2);
    glVertex3f(1.0, 1.0, 0.0);
glEnd();

glMaterialfvが明示的に使用されている場合に必要な、より高価なコードシーケンスを検討してください。

GLfloat d1[] = { 0.2, 0.5, 0.8, 1.0 };
GLfloat d2[] = { 0.3, 0.5, 0.6, 1.0 };
GLfloat d3[] = { 0.4, 0.2, 0.2, 1.0 };

glBegin(GL_TRIANGLES);
    glMaterialfv(GL_FRONT,GL_DIFFUSE,d1);
    glVertex3f(1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT,GL_DIFFUSE,d2);
    glVertex3f(0.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT,GL_DIFFUSE,d3);
    glVertex3f(1.0, 1.0, 0.0);
glEnd();

単純なマテリアルの変更を頻繁に必要とするオブジェクトをレンダリングする場合は、カラーマテリアルモードを使用してみてください。ただし、カラーマテリアルモードを有効にすると、よくある落とし穴があります。カラーマテリアルが有効になっている場合、OpenGLはカラーマテリアルの状態によって制御されるマテリアルカラーを即座に変更します。新しく作成したOpenGLレンダリングコンテキストを初期化するには、次のコードを検討してください。

GLfloat a[] = { 0.1, 0.1, 0.1, 1.0 };
glColor4f(1.0, 1.0, 1.0, 1.0);

glMaterialfv(GL_FRONT, GL_AMBIENT, a);
glEnable(GL_COLOR_MATERIAL); /* WARNING: Ambient and diffuse material latch immediately to the current color. */
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glColor3f(0.3, 0.5, 0.6);

上記のコードフラグメントを実行した後、フロントアンビエントと拡散マテリアルのカラーはどのような状態になりますか?プログラマーは、周囲のマテリアルの状態を(0.1, 0.1, 0.1, 1.0)に、拡散のマテリアルの状態を(0.3, 0.5, 0.6, 1.0)にすることを意図していた可能性がありますが、これは実際には起こりません。

結果の拡散マテリアル状態は、プログラマーが意図したものですが、結果の周囲のマテリアル状態は、予想外に(1.0, 1.0, 1.0, 1.0)です。どうしてこうなりました?ええと、色材モードが有効になるとすぐに現在の色の追跡を開始することを覚えておいてください。カラーマテリアル設定の初期値はGL_FRONT_AND_BACKGL_AMBIENT_AND_DIFFUSEです(おそらく期待どおりではありません)。

カラーマテリアルモードを有効にするとすぐに現在のカラーの追跡が開始されるため、アンビエントとディフューズの両方のマテリアルの状態が(1.0, 1.0, 1.0, 1.0)に更新されます。最初のglMaterialfvの効果は失われることに注意してください。次に、カラーマテリアルの状態が更新され、前面の拡散マテリアルのみが変更されます。最後に、glColor3fの呼び出しにより、拡散マテリアルが(0.3, 0.5, 0.6, 1.0)に変更されます。アンビエントマテリアルの状態は(1.0, 1.0, 1.0, 1.0)になります。

上記のコードの問題は、glColorMaterialを呼び出す前にカラーマテリアルモードが有効になっていることです。カラーマテリアルモードは、効率的な単純なマテリアル変更に非常に効果的ですが、上記の落とし穴を回避するために、GL_COLOR_MATERIALを有効にする前に、常にglColorMaterialを設定するように注意してください。

20
genpfault