如何记录光线位置的变化?

时间:2011-09-18 07:31:49

标签: c++ opengl light

我正在尝试制作一个非常简单的MFC OpenGL教程 有一个球体。而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);
}

2 个答案:

答案 0 :(得分:3)

您永远不应该在输入事件处理程序中放置绘图调用。那是你的主要问题。另一个问题是 - 似乎 - 你把OpenGL混淆为一个场景图。

OpenGL是一个绘图API,无论如何都不会回忆起场景。在输入处理程序中,您可以设置一些变量,发出重绘事件,然后在绘图事件处理程序中根据这些变量进行渲染。作为状态机绘图API的OpenGL也意味着没有明确的初始化阶段。像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…的调用发生在当前设置状态的上下文中(最重要的是灯光是模型视图矩阵)。光位置乘以模型视图矩阵。如果您使用gluLookAt,则glLightfv(GL_LIGHT<n>, GL_POSITION, …)的调用必须在gluLookAt之后和绘制照明几何体之前进行。

答案 1 :(得分:2)

void CView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    ...
    CView::OnKeyDown(nChar, nRepCnt, nFlags);
}  

这不是一个无限的递归调用?你的编译器不是在警告你吗?