C++ 如何跟踪灯光位置的变化?

C++ 如何跟踪灯光位置的变化?,c++,opengl,light,C++,Opengl,Light,我正在尝试制作一个非常简单的MFC OpenGL教程。 有一个球体。而spere是光源(就像太阳一样)。有两个三角形。根据spere的移动,我希望三角形变亮。 但是,当我移动球体时,三角形的表面只是第一次发生变化。 球体的下一个移动不会改变三角形的表面 如何跟踪灯光位置? 这是keyborad处理程序函数 void CView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == VK_UP) {

我正在尝试制作一个非常简单的MFC OpenGL教程。
有一个球体。而spere是光源(就像太阳一样)。有两个三角形。根据spere的移动,我希望三角形变亮。
但是,当我移动球体时,三角形的表面只是第一次发生变化。
球体的下一个移动不会改变三角形的表面

如何跟踪灯光位置?
这是keyborad处理程序函数

void CView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    if (nChar == VK_UP)
    {
        m.x += 0.1f;
    }
    else if (nChar == VK_DOWN)
    {
        m.y -= 0.1f;
    }
    else if (nChar == VK_LEFT)
    {
        m.x -= 0.1f;
    }
    else if (nChar == VK_RIGHT)
    {
        m.x += 0.1f;
    }
    setGL();
    DrawGL();
    CView::OnKeyDown(nChar, nRepCnt, nFlags);
}  
void CView::setGL(GLvoid)           
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);       
    glClearDepth(1.0f); 
    glEnable(GL_DEPTH_TEST);    
    glDepthFunc(GL_LEQUAL);             
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    // light source configuration ##################
    glMatrixMode(GL_MODELVIEW);
    gluLookAt(0.f,0.f,1.f, 0.f,0.f,0.f, 0.f,1.f,0.f);

    GLfloat light0_diffuse[] = {0.5, 0.5, 1.0};
    GLfloat light0_specular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat light0_spot_direction[] = {1,1,1,0};

    GLfloat light1_diffuse[] = {1.0f, 0.3f, 0.3f};
    GLfloat light1_specular[] = {1.0f, 0.8f, 0.8f, 1.0f};
    GLfloat light1_shiniess[] = {50.0};
    GLfloat light1_pos[] = {m.x, m.y, m.z};

    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light0_spot_direction);

    glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
    glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
    glLightfv(GL_LIGHT1, GL_SHININESS, light1_shiniess);
    glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);
}

void CView::DrawGL(void)                
{
    // clear screen and depth buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glLoadIdentity();
    // camera view configuration 
    gluLookAt(0.0f,0.0f,1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);

    // draw 
    //glColor3f(1.f, 1.f, 1.f);
    glPushMatrix();
    glTranslatef(m.x, m.y, m.z);
    glutSolidSphere(0.25f, 120, 120);

    glPopMatrix();
    glBegin(GL_TRIANGLES);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(0.0f, 0.0f, -0.5f);
    glVertex3f(-1.0f, 0.0f, -0.5f);

    m.calculateNormal(-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -1.0f, 0.0f, -0.5f);
    glNormal3f(m.normalX, m.normalY, m.normalZ);

    glBegin(GL_TRIANGLES);
    glVertex3f(0.5f, 0.5f, -1.0f);
    glVertex3f(0.0f, 0.0f, -1.0f);
    glVertex3f(1.0f, 0.0f, -1.0f);

    m.calculateNormal(0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f);
    glNormal3f(m.normalX, m.normalY, m.normalZ);

    glEnd();

    // swap buffer
    SwapBuffers(m_hDC);
}
这些是键盘函数调用的函数

void CView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    if (nChar == VK_UP)
    {
        m.x += 0.1f;
    }
    else if (nChar == VK_DOWN)
    {
        m.y -= 0.1f;
    }
    else if (nChar == VK_LEFT)
    {
        m.x -= 0.1f;
    }
    else if (nChar == VK_RIGHT)
    {
        m.x += 0.1f;
    }
    setGL();
    DrawGL();
    CView::OnKeyDown(nChar, nRepCnt, nFlags);
}  
void CView::setGL(GLvoid)           
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);       
    glClearDepth(1.0f); 
    glEnable(GL_DEPTH_TEST);    
    glDepthFunc(GL_LEQUAL);             
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    // light source configuration ##################
    glMatrixMode(GL_MODELVIEW);
    gluLookAt(0.f,0.f,1.f, 0.f,0.f,0.f, 0.f,1.f,0.f);

    GLfloat light0_diffuse[] = {0.5, 0.5, 1.0};
    GLfloat light0_specular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat light0_spot_direction[] = {1,1,1,0};

    GLfloat light1_diffuse[] = {1.0f, 0.3f, 0.3f};
    GLfloat light1_specular[] = {1.0f, 0.8f, 0.8f, 1.0f};
    GLfloat light1_shiniess[] = {50.0};
    GLfloat light1_pos[] = {m.x, m.y, m.z};

    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light0_spot_direction);

    glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
    glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
    glLightfv(GL_LIGHT1, GL_SHININESS, light1_shiniess);
    glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);
}

void CView::DrawGL(void)                
{
    // clear screen and depth buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glLoadIdentity();
    // camera view configuration 
    gluLookAt(0.0f,0.0f,1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);

    // draw 
    //glColor3f(1.f, 1.f, 1.f);
    glPushMatrix();
    glTranslatef(m.x, m.y, m.z);
    glutSolidSphere(0.25f, 120, 120);

    glPopMatrix();
    glBegin(GL_TRIANGLES);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(0.0f, 0.0f, -0.5f);
    glVertex3f(-1.0f, 0.0f, -0.5f);

    m.calculateNormal(-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -1.0f, 0.0f, -0.5f);
    glNormal3f(m.normalX, m.normalY, m.normalZ);

    glBegin(GL_TRIANGLES);
    glVertex3f(0.5f, 0.5f, -1.0f);
    glVertex3f(0.0f, 0.0f, -1.0f);
    glVertex3f(1.0f, 0.0f, -1.0f);

    m.calculateNormal(0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f);
    glNormal3f(m.normalX, m.normalY, m.normalZ);

    glEnd();

    // swap buffer
    SwapBuffers(m_hDC);
}
这不是一个无限递归调用吗?你的编译器没有警告你这一点吗


这不是一个无限递归调用吗?编译器没有警告您这一点吗?

您不应该在输入事件处理程序中放置绘图调用。这是你的主要问题。另一个问题是——看起来是这样的——将OpenGL与场景图混淆了

OpenGL是一种绘图API,对场景没有任何记忆。在输入处理程序中设置一些变量,发出重画事件,然后在绘图事件处理程序中从这些变量渲染。OpenGL作为一个状态机绘图API也意味着,没有显式的初始化阶段。像
setGL
这样的函数毫无意义。在
setGL
中执行的操作实际上属于绘图功能。这包括设置视口和投影矩阵

void CView::drawGL(GLvoid)           
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);       
    glClearDepth(1.0f); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    glViewport(…);
    glMatrixMode(GL_PROJECTION);
        set_projection_matrix(…);    

    // light source configuration ##################
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity(); // gluLookAt expects to work from a identity matrix.
    gluLookAt(0.f,0.f,1.f, 0.f,0.f,0.f, 0.f,1.f,0.f);

    GLfloat light0_diffuse[] = {0.5, 0.5, 1.0};
    GLfloat light0_specular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat light0_spot_direction[] = {1,1,1,0};

    GLfloat light1_diffuse[] = {1.0f, 0.3f, 0.3f};
    GLfloat light1_specular[] = {1.0f, 0.8f, 0.8f, 1.0f};
    GLfloat light1_shiniess[] = {50.0};
    GLfloat light1_pos[] = {m.x, m.y, m.z};

    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light0_spot_direction);

    glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
    glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
    glLightfv(GL_LIGHT1, GL_SHININESS, light1_shiniess);
    glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    // draw 
    glColor3f(1.f, 1.f, 1.f);
    glPushMatrix();
    glTranslatef(m.x, m.y, m.z);
    glutSolidSphere(0.25f, 120, 120);
    glPopMatrix();

    glBegin(GL_TRIANGLES);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(0.0f, 0.0f, -0.5f);
    glVertex3f(-1.0f, 0.0f, -0.5f);

    m.calculateNormal(-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -1.0f, 0.0f, -0.5f);
    glNormal3f(m.normalX, m.normalY, m.normalZ);

    glBegin(GL_TRIANGLES);
    glVertex3f(0.5f, 0.5f, -1.0f);
    glVertex3f(0.0f, 0.0f, -1.0f);
    glVertex3f(1.0f, 0.0f, -1.0f);

    m.calculateNormal(0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f);
    glNormal3f(m.normalX, m.normalY, m.normalZ);
    glEnd();

    // swap buffer
    SwapBuffers(m_hDC);
}

glLight…
的调用发生在当前设置状态的上下文中(对于灯光最重要的是modelview矩阵)。灯光位置与modelview矩阵相乘。如果使用
gluLookAt
,则对
GllLightFv(GL\u LIGHT,GL\u POSITION,…)
的调用必须在
gluLookAt
之后和绘制照明几何体之前进行。

决不能在输入事件处理程序中进行绘制调用。这是你的主要问题。另一个问题是——看起来是这样的——将OpenGL与场景图混淆了

OpenGL是一种绘图API,对场景没有任何记忆。在输入处理程序中设置一些变量,发出重画事件,然后在绘图事件处理程序中从这些变量渲染。OpenGL作为一个状态机绘图API也意味着,没有显式的初始化阶段。像
setGL
这样的函数毫无意义。在
setGL
中执行的操作实际上属于绘图功能。这包括设置视口和投影矩阵

void CView::drawGL(GLvoid)           
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);       
    glClearDepth(1.0f); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    glViewport(…);
    glMatrixMode(GL_PROJECTION);
        set_projection_matrix(…);    

    // light source configuration ##################
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity(); // gluLookAt expects to work from a identity matrix.
    gluLookAt(0.f,0.f,1.f, 0.f,0.f,0.f, 0.f,1.f,0.f);

    GLfloat light0_diffuse[] = {0.5, 0.5, 1.0};
    GLfloat light0_specular[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat light0_spot_direction[] = {1,1,1,0};

    GLfloat light1_diffuse[] = {1.0f, 0.3f, 0.3f};
    GLfloat light1_specular[] = {1.0f, 0.8f, 0.8f, 1.0f};
    GLfloat light1_shiniess[] = {50.0};
    GLfloat light1_pos[] = {m.x, m.y, m.z};

    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light0_spot_direction);

    glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
    glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
    glLightfv(GL_LIGHT1, GL_SHININESS, light1_shiniess);
    glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    // draw 
    glColor3f(1.f, 1.f, 1.f);
    glPushMatrix();
    glTranslatef(m.x, m.y, m.z);
    glutSolidSphere(0.25f, 120, 120);
    glPopMatrix();

    glBegin(GL_TRIANGLES);
    glVertex3f(-0.5f, 0.5f, -0.5f);
    glVertex3f(0.0f, 0.0f, -0.5f);
    glVertex3f(-1.0f, 0.0f, -0.5f);

    m.calculateNormal(-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -0.5f, -1.0f, 0.0f, -0.5f);
    glNormal3f(m.normalX, m.normalY, m.normalZ);

    glBegin(GL_TRIANGLES);
    glVertex3f(0.5f, 0.5f, -1.0f);
    glVertex3f(0.0f, 0.0f, -1.0f);
    glVertex3f(1.0f, 0.0f, -1.0f);

    m.calculateNormal(0.5f, 0.5f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, -1.0f);
    glNormal3f(m.normalX, m.normalY, m.normalZ);
    glEnd();

    // swap buffer
    SwapBuffers(m_hDC);
}


glLight…
的调用发生在当前设置状态的上下文中(对于灯光最重要的是modelview矩阵)。灯光位置与modelview矩阵相乘。如果使用
gluLookAt
,则对
glLightfv(GL\u LIGHT,GL\u POSITION,…)
的调用必须在
gluLookAt
之后和绘制照明几何体之前进行。

+1:我认为您是对的。这就解释了为什么它只工作一次。正如@Heisenbug之前指出的,您不应该调用
glBegin
两次(或者您缺少
glEnd
)。第二个电话将被忽略,但这是一个等待出现的问题…@K-ballo No。编者没有对此抱怨。我不知道为什么CView::OnKeyDown(nChar、nRepCnt、nFlags);有。它是自动的made@manutd:如果这是你的真实代码,那么我不知道它是如何工作的。您意识到调用
OnKeyDown
会导致调用
OnKeyDown
,这反过来会调用
OnKeyDown
,这将。。。好吧,你明白了。@K-ballo,我解决了这个问题。我只调用
glbegin
一次。但是问题仍然存在。我想你是对的。这就解释了为什么它只工作一次。正如@Heisenbug之前指出的,您不应该调用
glBegin
两次(或者您缺少
glEnd
)。第二个电话将被忽略,但这是一个等待出现的问题…@K-ballo No。编者没有对此抱怨。我不知道为什么CView::OnKeyDown(nChar、nRepCnt、nFlags);有。它是自动的made@manutd:如果这是你的真实代码,那么我不知道它是如何工作的。您意识到调用
OnKeyDown
会导致调用
OnKeyDown
,这反过来会调用
OnKeyDown
,这将。。。好吧,你明白了。@K-ballo,我解决了这个问题。我只调用
glbegin
一次。但问题仍然存在。Quote
您不应该在输入事件处理程序中放置绘图调用。
但是如何将灯光位置的更改通知给DrawGL方法?@manutd:您将新的灯光位置存储在变量中,并在下一次绘图交互中应用它们。请记住:OpenGL不是场景图,也就是说,它不在内部构建某种场景。你发送它的几何图形,OpenGL绘制它,然后忘记它。灯光位置仅与绘图期间的某些状态相关。灯光不是OpenGL为您管理的一些场景数据。灯光与在绘图程序中选择线宽或画笔没有太大区别。谢谢回复。但我还有一个问题。引用“您不应该在输入事件处理程序中放置绘图调用”。那么我应该将绘图方法放置在哪里?再次感谢。在MFC程序中,您可以通过WM_PAINT处理程序(即CWnd::OnPaint)执行此操作。如果您的程序播放动画,您还应该从空闲处理程序CApp::OnIdle中进行绘制,调用OpenGL windows绘制函数;在绘图函数的开头也添加对wglMakeCurrent的调用。我使用点光源来解决这个问题。I plus
GLfloat light1\u pos[]
的第四个参数<代码>GLfloat light1_pos[]={m.x,m.y,m.z,1.0}像这样。一切似乎都很好。但是,我仍然将绘图调用放在输入事件hadler中。但效果很好。为什么建议
不要在输入事件处理程序中放置图形调用?任何