C++ 为什么在 OpenGL 中启用照明时颜色会消失?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8494942/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 18:40:19  来源:igfitidea点击:

Why does my color go away when I enable lighting in OpenGL?

c++openglglut

提问by dangerChihuahua007

I am developing a graphics application in C++ with the OpenGL API and GLUT.

我正在使用 OpenGL API 和 GLUT 用 C++ 开发图形应用程序。

To add lighting, I made the following changes in my modelview matrix:

为了添加照明,我在模型视图矩阵中进行了以下更改:

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);

The lighting largely works I believe, but the colors of my objects all go away. All I see is a black/white silhouette of my overall figure.

我相信照明在很大程度上有效,但我的物体的颜色都消失了。我所看到的只是我整体身材的黑白轮廓。

I was wondering why this is?

我想知道这是为什么?

回答by Christian Rau

When lighting is enabled, a vertex' color is not determined from the color set by glColoror glColorPointer, but by the currently set material colors combined with the lights' colors using the lighting computations.

启用照明后,顶点的颜色不是由glColor或设置的颜色决定的glColorPointer,而是由当前设置的材质颜色与使用照明计算的灯光颜色组合而成。

So in order to change an object's color, you need to change the material setting (which by default is a diffuse grey material) before rendering, using the glMaterialfunctions. There is essentially a corresponding material color for each of the different light colors (GL_DIFFUSE, ...) along with some additional properties to approximate light emitting materials (GL_EMISSION) and controlling the material's roughness (GL_SHININESS). Read some introductory material on OpenGL's lighting features to understand their workings.

因此,为了更改对象的颜色,您需要在渲染之前使用glMaterial函数更改材质设置(默认情况下为漫反射灰色材质)。对于每种不同的光色 ( GL_DIFFUSE, ...) ,本质上都有相应的材料颜色以及一些附加属性来近似发光材料 ( GL_EMISSION) 和控制材料的粗糙度 ( GL_SHININESS)。阅读一些关于 OpenGL 光照特性的介绍材料,以了解它们的工作原理。

What you can do to quickly adapt your code from plain coloring to lighting (or to enable per-vertex material properties) is to use color material. By calling glEnable(GL_COLOR_MATERIAL)and setting an appropriate mapping with glColorMaterialyou can configure OpenGL to change a specific material color, whenever you change the current vertex color (using either glColoror glColorPointer).

您可以通过使用颜色材料来快速调整您的代码从纯色到照明(或启用每个顶点的材质属性)。通过调用glEnable(GL_COLOR_MATERIAL)和设置适当的映射,glColorMaterial您可以配置 OpenGL 以更改特定材质颜色,无论何时更改当前顶点颜色(使用glColorglColorPointer)。

回答by genpfault

Try glEnable(GL_COLOR_MATERIAL).

试试glEnable(GL_COLOR_MATERIAL)

See Common OpenGL Pitfall #14:

请参阅常见的 OpenGL 陷阱 #14

  1. Careful Enabling Color Material

OpenGL's color material feature provides a less expensive way to change material parameters. With color material enabled, material colors track the current color. This means that instead of using the relatively expensive glMaterialfvroutine, you can use the glColor3froutine.

Here is an example using the color material feature to change the diffuse color for each vertex of a triangle:

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();

Consider the more expensive code sequence needed if glMaterialfvis used explicitly:

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();

If you are rendering objects that require frequent simple material changes, try to use the color material mode. However, there is a common pitfall encountered when enabling the color material mode. When color material is enabled, OpenGL immediately changes the material colors controlled by the color material state. Consider the following piece of code to initialize a newly create OpenGL rendering context:

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);

What state will the front ambient and diffuse material colors be after executing the above code fragment? While the programmer may have intended the ambient material state to be (0.1, 0.1, 0.1, 1.0)and the diffuse material state to be (0.3, 0.5, 0.6, 1.0), that is not quite what happens.

The resulting diffuse material state is what the programmer intended, but the resulting ambient material state is rather unexpectedly (1.0, 1.0, 1.0, 1.0). How did that happen? Well, remember that the color material mode immediately begins tracking the current color when enabled. The initial value for the color material settings is GL_FRONT_AND_BACKand GL_AMBIENT_AND_DIFFUSE(probably not what you expected!).

Since enabling the color material mode immediately begins tracking the current color, both the ambient and diffuse material states are updated to be (1.0, 1.0, 1.0, 1.0). Note that the effect of the initial glMaterialfvis lost. Next, the color material state is updated to just change the front diffuse material. Lastly, the glColor3finvocation changes the diffuse material to (0.3, 0.5, 0.6, 1.0). The ambient material state ends up being (1.0, 1.0, 1.0, 1.0).

The problem in the code fragment above is that the color material mode is enabled before calling glColorMaterial. The color material mode is very effective for efficient simple material changes, but to avoid the above pitfall, always be careful to set glColorMaterialbefore you enable GL_COLOR_MATERIAL.

  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。颜色材质模式对于高效简单的材质更改非常有效,但为了避免上述陷阱,glColorMaterial在启用之前请务必小心设置GL_COLOR_MATERIAL