I am trying to make a very simple MFC OpenGL tutorial.
There is a sphere. And the spere is the source of light(like sun). And there is two triangle. According to movement of the spere, I want to have the triangles lightend. But When I move the sphere, the surface of the triangle changed only for the first time. Next movement of the sphere don't change the surface the the triangle.How to keep trace of the light position?
This is the keyborad handler function.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);
}
And these are the functions which called by keyboard function.
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);
}
You should never place drawing calls in a input event handler. That's your main problem. The other problem is – so it seems – that you confuse OpenGL for a scene graph.
OpenGL is a drawing API with no recollection of a scene, whatsoever. In your input handler you set some variables, issue a redraw event and then in the drawing event handler render from those variables. OpenGL being a state machine drawing API also means, that there is no explicit initialization phase. A function like setGL
makes no sense whatsoever. What you do in setGL
actually belongs into the drawing function. This includes setting the viewport and the projection matrix!
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);
}
The calls to glLight…
happen in the context of the currently set state (most importantly for the lights is the modelview matrix). The light positions are multiplied by the modelview matrix. If using gluLookAt
, which you do, the calls to glLightfv(GL_LIGHT<n>, GL_POSITION, …)
must happen after gluLookAt
and before drawing the illuminated geometry.
void CView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
...
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
How isn't that an infinite recursive call? Doesn't your compiler warn you about this?
精彩评论