什么是OpenGL中的法线?

什么是OpenGL中的法线?,opengl,colors,light,normals,Opengl,Colors,Light,Normals,我听说我应该使用法线而不是颜色,因为颜色是不推荐使用的。(这是真的吗?)法线与光的反射有关,但我找不到清晰直观的解释。什么是法线?现在很多东西都不推荐使用,包括法线和颜色。这只意味着你必须自己实现它们。使用法线可以对对象进行着色。这取决于您进行计算,但有很多关于Gouraud/Phong着色的教程 编辑:有两种类型的法线:面法线和顶点法线。面法线指向远离三角形的方向,顶点法线指向远离顶点的方向。使用顶点法线可以获得更好的质量,但面法线也有许多用途,例如,它们可以用于碰撞检测和阴影体积。A通常是一

我听说我应该使用法线而不是颜色,因为颜色是不推荐使用的。(这是真的吗?)法线与光的反射有关,但我找不到清晰直观的解释。什么是法线?

现在很多东西都不推荐使用,包括法线和颜色。这只意味着你必须自己实现它们。使用法线可以对对象进行着色。这取决于您进行计算,但有很多关于Gouraud/Phong着色的教程


编辑:有两种类型的法线:面法线和顶点法线。面法线指向远离三角形的方向,顶点法线指向远离顶点的方向。使用顶点法线可以获得更好的质量,但面法线也有许多用途,例如,它们可以用于碰撞检测和阴影体积。

A通常是一个单位向量,其方向垂直于特定点处的曲面。因此,它会告诉您曲面朝向哪个方向。法线的主要使用情形是照明计算,在这种情况下,您必须确定给定曲面点处法线与朝向光源或相机的方向之间的角度(或通常是余弦)。

glNormal
最小示例

glNormal
是一种不推荐使用的OpenGL2方法,但它很容易理解,所以让我们来研究一下。下面将讨论现代着色器替代方案

此示例演示了如何使用漫反射闪电的一些详细信息

display
函数的注释解释了每个三角形的含义

#包括
#包括
#包括
#包括
/*x-y平面上的三角形*/
静态空心绘制_三角形(){
glBegin(GL_三角形);
glVertex3f(0.0f,1.0f,0.0f);
glVertex3f(-1.0f,-1.0f,0.0f);
glVertex3f(1.0f,-1.0f,0.0f);
格伦德();
}
/*手动倾斜45度的三角形*/
静态空心画_三角形_45(){
glBegin(GL_三角形);
glVertex3f(0.0f,1.0f,-1.0f);
glVertex3f(-1.0f,-1.0f,0.0f);
glVertex3f(1.0f,-1.0f,0.0f);
格伦德();
}
静态无效显示(无效){
GL3F(1.0f,0.0f,0.0f);
glClear(GLU颜色缓冲位);
glPushMatrix();
/*
垂直于光线的三角形。
如果我们没有指定0,0,1,那么0,0,1也恰好是默认的法线。
*/
glNormal3f(0.0f、0.0f、1.0f);
画一个三角形();
/*
这个三角形和前一个一样明亮。
这不是照片级真实感,它应该不那么明亮。
*/
glTranslatef(2.0f,0.0f,0.0f);
画一个三角形;
/*
与上一个三角形相同,但使用法线集
将照片级真实感值设置为45,使其亮度降低。
注意,该法向量的范数不是1,
但我们很好,因为我们使用了“glEnable(GL_NORMALIZE)”。
*/
glTranslatef(2.0f,0.0f,0.0f);
glNormal3f(0.0f、1.0f、1.0f);
画一个三角形;
/*
此三角形使用glRotate旋转45度。
它应该和前一个一样明亮,
即使我们将法线设置为0,0,1。
所以glRotate也会影响正常!
*/
glTranslatef(2.0f,0.0f,0.0f);
glNormal3f(0.0,0.0,1.0);
glRotatef(45.0,-1.0,0.0,0.0);
画一个三角形();
glPopMatrix();
glFlush();
}
静态void init(void){
GLfloat light0_diffuse[]={1.0,1.0,1.0,1.0};
/*来自+z无穷远的平面波*/
GLfloat light0_位置[]={0.0,0.0,1.0,0.0};
glClearColor(0.0,0.0,0.0,0.0);
glShadeModel(GL_平滑);
glLightfv(GLU LIGHT0、GLU位置、LIGHT0位置);
glLightfv(GL_LIGHT0、GL_漫反射、LIGHT0_漫反射);
glEnable(德国劳埃德大学照明);
glEnable(GL_LIGHT0);
glColorMaterial(GL_前部、GL_漫反射);
glEnable(GL_颜色_材料);
glEnable(GL_正常化);
}
静态空洞重塑(int w,int h){
glViewport(0,0,w,h);
glMatrixMode(GL_投影);
glLoadIdentity();
格洛托(-1.0,7.0,-1.0,1.0,-1.5,1.5);
glMatrixMode(GLU模型视图);
glLoadIdentity();
}
int main(int argc,字符**argv){
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(800200);
位置(100100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(显示器);
GLUTREFORUNC(重塑);
glutMainLoop();
返回退出成功;
}
理论

在OpenGL 2中,每个顶点都有自己的关联法向量

法线向量确定顶点的亮度,然后用于确定三角形的亮度

OpenGL 2使用了,其中灯光被分为三个组件:环境光、漫反射光和镜面反射光。其中,漫反射和镜面反射组件受法线的影响:

  • 如果漫反射光与曲面垂直,则无论观察者在何处,漫反射光都会使曲面变得更亮
  • 如果镜面反射光击中曲面,并反弹到观察者的眼睛中,则该点成为brigher
glNormal
设置当前法向量,该法向量用于以下所有顶点

在我们都
glNormal
之前,normal的初始值是
0,0,1

法向量必须有范数1,否则颜色会改变<代码>glScale还可以更改法线的长度<代码>glEnable(GL_标准化)使OpenGL自动为我们将其标准设置为1。这很好地说明了这一点

为什么每个顶点的法线比每个面的法线有用

下面的两个球体具有相同数量的多边形。顶点上有法线的那个看起来更平滑

OpenGL 4片段着色器

在较新的OpenGL API中,将法线方向数据作为任意数据块传递给GPU:GPU不知道它代表法线

然后你写一个手写的框架
#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;
}