OpenGL:glNormalで法線を設定する必要があるのはなぜですか?


19

OpenGLのいくつかの基本を学んでいますが、なぜglNormal頂点の法線を設定する必要があるのか​​疑問に思っています。

このような単純な三角形を作成する場合:

glBegin(GL_TRIANGLES);
    glVertex3f(0,0,0);
    glVertex3f(1,0,0);
    glVertex3f(0,1,0);
glEnd();

法線は、幾何学的プリミティブのタイプによって暗黙的に定義されるべきではありませんか?法線を設定しない場合、OpenGLはそれを計算しますか?


7
このコードは非推奨の固定機能パイプラインを使用しており、最新のOpenGLでは法線と頂点の両方が単なる頂点属性であることに注意してください。
Bartek Banachewicz

4
即時モードを使用しないでください。非推奨です。Learn Modern 3D Graphics Programmingを強くお勧めします。
右折して

3
イミディエイトモードの使用に関するコメントは、ここではまったく無関係だと思います。はい、使用するべきではありませんが、イミディエイトモード、頂点配列、VBO、汎用属性、固定属性、またはトーストビットに関係なく、問題のポイントは変わりません。
マキシマスミニマス

1
自動的に決定されない理由は、照明が非常に多角形になるためです(より良い単語がないため)。これが意味することは、三角形上のすべての頂点が同じ正常値を持つことです。平らな表面の場合、これは予想されることですが、人の顔のモデルがある場合、顔の各三角形は同じ照明値を持ちます(ポリゴンを非常に見やすくします)。独自の法線値を指定することで、物事をより滑らかに見せることができます(通常、現在の頂点を含むすべての三角形の法線値を平均することで法線を見つけます)。
ベンジャミンデンジャージョンソン

回答:


30

glNormal間で複数回呼び出すglBegin/Endと、プリミティブごとではなく頂点ごとに法線を設定できます。

glBegin(GL_TRIANGLES);
    glNormal3f(0,0,1);
    glVertex3f(0,0,0);
    glNormal3f(0,0,1);
    glVertex3f(1,0,0);
    glNormal3f(0,0,1);
    glVertex3f(0,1,0);
glEnd();

複数の三角形で構成されるより複雑なメッシュの場合、1つの頂点の法線は、それが属する三角形の法線だけでなく、周囲のジオメトリの他の三角形に依存します。

以下は同じジオメトリの例です:

  • 頂点ごとの左側の法線 -面の各頂点には異なる法線があります(この球体の場合、すべての法線は中心から外側を指します)。
  • 右側の面ごとの法線 -各頂点は同じ法線値を取得します(一度だけ指定するか、デフォルトの法線値を使用するため(0,0,1))。

左側の頂点ごとの法線、右側の面ごとの法線

デフォルトのシェードモデル(GL_SMOOTH)により、顔の頂点の法線が顔全体に補間されます。頂点ごとの法線の場合、これは滑らかな影付きの球になりますが、面ごとの法線の場合、特徴的なファセットの外観になります。


4

いいえ、GLは標準を計算しません。法線がどうあるべきかを知ることはできません。プリミティブは、ラスター化(および他のいくつかの場所)以外のものを意味しません。GLは、どの面(三角形)が頂点を共有するかを知りません(実行時にこれを計算すると、異なるデータ構造を使用しないと非常にコストがかかります)。

メッシュの「三角形のスープ」を前処理して、共通の頂点を見つけ、法線を計算する必要があります。これは、ゲームを高速化する前に実行する必要があります。

また、ハードエッジのように、幾何学的にはコーナーに共有頂点が存在する場合もありますが、正常に点灯するように個別の法線が必要です。GL / D3Dレンダリングモデルでは、このために2つの別々の頂点が(同じ位置に)必要であり、それぞれに個別の法線があります。

これらはすべて、UVとテクスチャマッピングにも必要です。


3

短い答えは、あなたが実際にしていないということである持っているすべての法線を設定します。法線ベクトルは、OpenGLライティング(またはおそらくそれらに依存する他の計算)を実行している場合にのみ使用されますが、それが当てはまらない場合(またはライトマップなどのその他の方法を使用している場合) )その後、すべてのglNormal呼び出しを非常に喜んで省略できます。

したがって、glNormalを指定することが理にかなっている何かをしていると仮定して、もう少し見てみましょう。

glNormalは、プリミティブごとまたは頂点ごとに指定できます。プリミティブごとの法線とは、プリミティブの各頂点のすべての法線が同じ方向を向いているということです。時々これはあなたが望むものですが、時にはそうではありません-頂点ごとの法線が役立つのは、各頂点がそれ自身の向きを持っていることです。

球体の古典的な例を見てみましょう。球体の各三角形の法線が同じ場合、最終結果はかなりファセットになります。それはおそらくあなたが望むものではなく、代わりに滑らかなシェーディングが必要です。そのため、共通の頂点を共有する各三角形の法線を平均し、滑らかなシェーディング結果を得ます。


2

glNormal拡散ライトニングの動作方法の詳細を示す最小限の例

display関数のコメントは、各三角形の意味を説明しています。

ここに画像の説明を入力してください

#include <stdlib.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

/* Triangle on the x-y plane. */
static void draw_triangle() {
    glBegin(GL_TRIANGLES);
    glVertex3f( 0.0f,  1.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, 0.0f);
    glVertex3f( 1.0f, -1.0f, 0.0f);
    glEnd();
}

/* A triangle tilted 45 degrees manually. */
static void draw_triangle_45() {
    glBegin(GL_TRIANGLES);
    glVertex3f( 0.0f,  1.0f, -1.0f);
    glVertex3f(-1.0f, -1.0f,  0.0f);
    glVertex3f( 1.0f, -1.0f,  0.0f);
    glEnd();
}

static void display(void) {
    glColor3f(1.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glPushMatrix();

    /*
    Triangle perpendicular to the light.
    0,0,1 also happens to be the default normal if we hadn't specified one.
    */
    glNormal3f(0.0f, 0.0f, 1.0f);
    draw_triangle();

    /*
    This triangle is as bright as the previous one.
    This is not photorealistic, where it should be less bright.
    */
    glTranslatef(2.0f, 0.0f, 0.0f);
    draw_triangle_45();

    /*
    Same as previous triangle, but with the normal set
    to the photorealistic value of 45, making it less bright.

    Note that the norm of this normal vector is not 1,
    but we are fine since we are using `glEnable(GL_NORMALIZE)`.
    */
    glTranslatef(2.0f, 0.0f, 0.0f);
    glNormal3f(0.0f, 1.0f, 1.0f);
    draw_triangle_45();

    /*
    This triangle is rotated 45 degrees with a glRotate.
    It should be as bright as the previous one,
    even though we set the normal to 0,0,1.
    So glRotate also affects the normal!
    */
    glTranslatef(2.0f, 0.0f, 0.0f);
    glNormal3f(0.0, 0.0, 1.0);
    glRotatef(45.0, -1.0, 0.0, 0.0);
    draw_triangle();

    glPopMatrix();
    glFlush();
}

static void init(void) {
    GLfloat light0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
    /* Plane wave coming from +z infinity. */
    GLfloat light0_position[] = {0.0, 0.0, 1.0, 0.0};
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);
    glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glColorMaterial(GL_FRONT, GL_DIFFUSE);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_NORMALIZE);
}

static void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 7.0, -1.0, 1.0, -1.5, 1.5);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(800, 200);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return EXIT_SUCCESS;
}

理論

OpenGLでは、各頂点には独自の法線ベクトルが関連付けられています。

法線ベクトルは、頂点の明るさを決定し、三角形の明るさを決定するために使用されます。

表面が光に垂直な場合、平行な表面よりも明るくなります。

glNormal 後続のすべての頂点に使用される現在の法線ベクトルを設定します。

すべての前の法線の初期値glNormal0,0,1です。

法線ベクトルをしなければならない規範1、または他の色の変更を持っています!glScale法線の長さも変更します!glEnable(GL_NORMALIZE);OpenGLに標準を自動的に1に設定させます。このGIFはそれを美しく示しています。

書誌:


いい答えですが、なぜ古い質問と古い技術に焦点を合わせたのですか?
ベイランクール

@AlexanderVaillancourtありがとう!古い質問:なぜそうではない:-)古い技術:今日のより良い方法は何ですか?
Ciro Santilli新疆改造中心法轮功六四事件

現代のOpenGLはglNormalを指定する代わりにバッファオブジェクトを使用すると思います。
ベイランクール

1
確かに、glNormalやglVertexなどは現代のOpenGLではなくなっており、それ以前に廃止されました...この質問が最初に尋ねられたときでさえ、実際は廃止されました。

0

コーダーに依存するいくつかの機能を実装するにはglNormalが必要です。たとえば、ハードエッジを保持するように法線を作成したい場合があります。


4
おそらく、あなたの答えを少し改善したいと思うでしょう。
Bartek Banachewicz

1
私の答えを改善したい場合は、弱点を指摘する必要があります。でも詳しく説明できます。以前はxblaxが考えていたように、通常の各「同じ」方法で計算されるべきです。各ピクセルと各顔の補間法線の違いにもかかわらずです。トピックをもう少し詳しく見てみましょう。
AB。

1
ハードエッジを維持し、より際立たせたい場合があります。以下にサンプル画像を示します。titan.cs.ukzn.ac.za / opengl / opengl-d5 / trant.sgi.com / opengl / PS。二重投稿でごめんなさい。私はSEのインターフェイスに新しいです
AB。

「編集」ボタンがあります。
Bartek Banachewicz

1
5分後には編集できません
AB。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.