我试图使用评估器在C语言中用OpenGL制作一个小型波形发生器.
但是,由于我的评估员只是部分点亮,所以运气不好.
为什么会这样?
下面我为了完整性而包含完整的源代码,你可能只需要查看init(),display()和文件顶部的常量.
#include <gl/glui.h> #include <math.h> const int DIMX = 500; const int DIMY = 500; const int INITIALPOS_X = 200; const int INITIALPOS_Y = 200; // Aspect ratio (calculated on the fly) float xy_aspect; // UI aux. matrices float view_rotate[16] = { 1,1,1 }; float obj_pos[] = { 0.0,0.0,0.0 }; float obj_pan[] = { 0.0,0.0 }; // Referential axis double axis_radius_begin = 0.2; double axis_radius_end = 0.0; double axis_lenght = 16.0; int axis_nslices = 8; int axis_nstacks = 1; // Light 0 properties float light0_position[] = {5.0,5.0,0.0}; float light0_ambient[] = {0.0,1.0}; float light0_diffuse[] = {0.6,0.6,1.0}; float light0_specular[] = {1.0,1.0,1.0}; float light0_kc = 0.0; float light0_kl = 1.0; float light0_kq = 0.0; double light0x = 5.0; double light0y = 5.0; double light0z = 5.0; double symb_light0_radius = 0.2; int symb_light0_slices = 8; int symb_light0_stacks =8; // Ambient light source properties float light_ambient[] = {0.5,0.5,1.0}; /* Set the background ambient lighting. */ // Windowing related variables int main_window; GLUquadric* glQ; GLUI *glui; const unsigned int gridSize = 40; float grid[gridSize][gridSize][3]; const int uSize = gridSize; const int vSize = gridSize; GLfloat ambient[] = {0.2,0.2,1.0}; GLfloat position[] = {0.0,2.0,1.0}; GLfloat mat_diffuse[] = {0.6,1.0}; GLfloat mat_specular[] = {1.0,1.0}; float mat_shininess[] = {50.0}; void display(void) { static float value = 0; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glFrustum( -xy_aspect*.04,xy_aspect*.04,-.04,.04,.1,50.0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( obj_pos[0],obj_pos[1],-obj_pos[2]-25 ); glTranslatef( obj_pan[0],obj_pan[1],obj_pan[2] ); glRotated( 20.0,0.0 ); glRotated(-45.0,0.0 ); glMultMatrixf( view_rotate ); glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glColor3f(1.0,0.0); glPushMatrix(); glRotated(90.0,0.0 ); gluCylinder(glQ,axis_radius_begin,axis_radius_end,axis_lenght,axis_nslices,axis_nstacks); glPopMatrix(); glColor3f(0.0,0.0); glPushMatrix(); glRotated(-90.0,1.0); glPushMatrix(); gluCylinder(glQ,axis_nstacks); glPopMatrix(); light0_position[0] = light0x; light0_position[1] = light0y; light0_position[2] = light0z; glLightfv(GL_LIGHT0,GL_POSITION,light0_position); glColor3f(1.0,0.0); gluQuadricOrientation( glQ,GLU_INSIDE); glPushMatrix(); glTranslated(light0x,light0y,light0z); gluSphere(glQ,symb_light0_radius,symb_light0_slices,symb_light0_stacks); glPopMatrix(); gluQuadricOrientation( glQ,GLU_OUTSIDE); gluQuadricDrawStyle(glQ,GLU_FILL); gluQuadricNormals(glQ,GLU_SMOOTH); gluQuadricOrientation(glQ,GLU_OUTSIDE); gluQuadricTexture(glQ,GL_FALSE); for (unsigned int y = 0; y < vSize; ++y) { for (unsigned int x = 0; x < uSize; ++x) { float xVal = 5*3.14/gridSize*x; float yVal = 5*3.14/gridSize*y; grid[y][x][0] = (float) x/gridSize*10.0; grid[y][x][1] = sin(xVal + value) + sin(yVal + value); grid[y][x][2] = (float) y/gridSize*10.0; } } glMap2f(GL_MAP2_VERTEX_3,3,uSize,uSize * 3,vSize,&grid[0][0][0]); glEvalMesh2(GL_FILL,gridSize,gridSize); value += 3.14/25; if (value > 3.14*2) value = 0; // swapping the buffers causes the rendering above to be shown glutSwapBuffers(); glFlush(); } /* Mouse handling */ void processMouse(int button,int state,int x,int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { } if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { } glutPostRedisplay(); } void processMouseMoved(int x,int y) { // pedido de refrescamento da janela glutPostRedisplay(); } void processPassiveMouseMoved(int x,int y) { // pedido de refrescamento da janela glutPostRedisplay(); } void reshape(int w,int h) { int tx,ty,tw,th; GLUI_Master.get_viewport_area( &tx,&ty,&tw,&th ); glViewport( tx,th ); xy_aspect = (float)tw / (float)th; glutPostRedisplay(); } void keyboard(unsigned char key,int y) { switch (key) { case 27: // tecla de escape termina o programa exit(0); break; } } void glut_idle( void ) { if ( glutGetWindow() != main_window ) glutSetWindow(main_window); glutPostRedisplay(); } void init() { glQ = gluNewQuadric(); glFrontFace(GL_CCW); // Front faces defined using a counterclockwise rotation glDepthFunc(GL_LEQUAL); // Por defeito e GL_LESS glEnable(GL_DEPTH_TEST); // Use a depth (z) buffer to draw only visible objects glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse); glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); // Face Culling para aumentar a velocidade glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // GL_FRONT,GL_BACK,GL_FRONT_AND_BACK // Define que modelo de iluminacao utilizar; consultar o manual de referencia glLightModelfv(GL_LIGHT_MODEL_AMBIENT,light_ambient); // define luz ambiente glLightModelf (GL_LIGHT_MODEL_TWO_SIDE,GL_FALSE); glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER,1); // por defeito a cor de fundo e o preto // glClearColor(1.0,1.0); // cor de fundo a branco // declaracoes para a fonte luz GL_LIGHT0 glLightfv(GL_LIGHT0,GL_AMBIENT,light0_ambient); glLightfv(GL_LIGHT0,light0_diffuse); glLightfv(GL_LIGHT0,light0_specular); glLightf(GL_LIGHT0,GL_CONSTANT_ATTENUATION,light0_kc); glLightf(GL_LIGHT0,GL_LINEAR_ATTENUATION,light0_kl); glLightf(GL_LIGHT0,GL_QUADRATIC_ATTENUATION,light0_kq); // NOTA: a direccao e a posicao de GL_LIGHT0 estao na rotina display(),pelo // que as isntrucoes seguntes nao sao necessarias //glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,90.0); //glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,spot_direction); //glLightfv(GL_LIGHT0,light0_position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); glEnable(GL_MAP2_VERTEX_3); glMapGrid2f(gridSize,1.0); glShadeModel(GL_SMOOTH); glPolygonMode(GL_FRONT,GL_FILL); //glPolygonMode(GL_FRONT,GL_LINE); } void do_nothing(int key,int y) {} int main(int argc,char* argv[]) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize (DIMX,DIMY); glutInitWindowPosition (INITIALPOS_X,INITIALPOS_Y); main_window = glutCreateWindow (argv[0]); glutDisplayFunc(display); GLUI_Master.set_glutReshapeFunc(reshape); GLUI_Master.set_glutKeyboardFunc (keyboard); GLUI_Master.set_glutMouseFunc(processMouse); glutMotionFunc(processMouseMoved); glutPassiveMotionFunc(processPassiveMouseMoved); GLUI_Master.set_glutSpecialFunc( do_nothing ); /*** Create the bottom subwindow ***/ glui = GLUI_Master.create_glui_subwindow( main_window,GLUI_SUBWINDOW_BOTTOM ); glui->set_main_gfx_window( main_window ); GLUI_Rotation *view_rot = glui->add_rotation( "Rotation",view_rotate ); view_rot->set_spin( 1.0 ); glui->add_column( false ); GLUI_Translation *trans_z = glui->add_translation( "Zoom",GLUI_TRANSLATION_Z,&obj_pos[2] ); trans_z->set_speed( .1 ); glui->add_column(false); GLUI_Translation *trans_pan = glui->add_translation("Pan",GLUI_TRANSLATION_XY,&obj_pan[0]); trans_pan->set_speed(.1); GLUI_Master.set_glutIdleFunc( glut_idle ); init(); glutMainLoop(); return 0; }
解决方法
你说OpenGL评估者不需要设置法线.这只是部分正确.如果通过调用以下方式为评估者启用自动生成的法线,则只需设置法线:
glEnable(GL_AUTO_NORMAL);
只是启用GL_NORMALIZE将不会这样做.
但是,您当然也可以通过为GL_MAP2_NORMAL提供控制点来指定自己的法线,方法与GL_MAP2_VERTEX_3相同.
如果没有提到OpenGL评估员被高度弃用并且最有可能被驱动程序软件实现,答案就不会完整.因此,只需滚动自己的Bezier评估代码(这不是很难)并生成一个绘制为GL_TRIANGLES的简单网格网格肯定会是一个更好的主意.