(相信有了前两节课的基础这是不难做到的)
#include < GL / glut.h >
void myDisplay( void )
{
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LINE_STIPPLE); // 启动虚线模式(使用glDisable(GL_LINE_STIPPLE)可以关闭之)
glLineStipple( 2 , 0x0F0F );
glLineWidth( 10.0f );
glBegin(GL_LINES);
glVertex2f( 0.0f , 0.0f );
glVertex2f( 0.5f , 0.5f );
glEnd();
glFlush();
}
int main( int argc, char * argv[])
{
glutInit( & argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition( 100 , 100 );
glutInitWindowSize( 400 , 400 );
glutCreateWindow( " 画虚线 " );
glutDisplayFunc( & myDisplay);
glutMainLoop();
return 0 ;
}
效果图如下:
比如,将程序中glLineStipple(2, 0x0F0F);换成glLineStipple(2, 0xAAAA);将虚线宽度glLineWidth(10.0f);换成glLineWidth(2.0f);则效果图如下:
使用glLineStipple来设置虚线的样式。
void glLineStipple(GLint factor, GLushort pattern);
pattern是由1和0组成的长度为16的序列,从最低位开始看,如果为1,则直线上接下来应该画的factor个点将被画为实的;如果为0,则直线上接下来应该画的factor个点将被画为虚的。
以下是一些例子(来自网上) :
一些必要的说明:
1、void glEnable(GL_LINE_STIPPLE); 是启动虚线模式,使用glDisable(GL_LINE_STIPPLE) 该模式,在以后它的应用是经常性的,至于可以用哪些模式,通过http://www.google.cn可以搜索到很多的。
2、void glLineStipple(GLint factor, GLushort pattern);该函数设置当前点的划线方式。factor表示连续画线的次数,范围为1~255,pattern是由0和1组成的16进制数,当位值为1时绘制直线,为0时不绘制直线,例如:0000111100001111的16进制为0x0F0F,表示绘制的是一条短线段,即我们说的破折线。
3、void glLineWidth(GLfloat width);表示划线宽度的函数。
关于虚线的模式,通过一个直观的程序给出:
#include < GL / glut.h >
#include < stdlib.h >
void drawALine(GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)
{
glBegin(GL_LINES);
glVertex2f((x1),(y1));
glVertex2f((x2),(y2));
glEnd();
}
void init( void )
{
glClearColor( 0.0 , 0.0 , 0.0 , 0.0 ); // 清除屏幕颜色为白色
glShadeModel(GL_FLAT);
}
void display( void )
{
int i;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f( 1.0 , 1.0 , 1.0 );
// 画第一行
glEnable(GL_LINE_STIPPLE);
glLineWidth( 3.0 );
glLineStipple( 1 , 0x0101 );
drawALine( 50.0 , 125.0 , 150.0 , 125.0 ); // 调用drawALine()函数
glLineStipple( 1 , 0x00FF );
drawALine( 150.0 , 125.0 , 250.0 , 125.0 );
glLineStipple( 1 , 0x1C47 );
drawALine( 250.0 , 125.0 , 350.0 , 125.0 );
// 画第二行
glLineWidth( 6.0 );
glLineStipple( 1 , 0x0101 );
drawALine( 50.0 , 100.0 , 150.0 , 100.0 );
glLineStipple( 1 , 0x00FF );
drawALine( 150.0 , 100.0 , 250.0 , 100.0 );
glLineStipple( 1 , 0x1C47 );
drawALine( 250.0 , 100.0 , 350.0 , 100.0 );
// 画第三行
glLineWidth( 3.0 );
glLineStipple( 1 , 0x1C47 );
glBegin(GL_LINE_STRIP);
for (i = 0 ;i < 7 ;i ++ )
glVertex2f( 50.0 + ((GLfloat)i * 50.0 ), 75.0 );
glEnd();
// 画第四行
for (i = 0 ;i < 6 ;i ++ )
{
drawALine( 50.0 + ((GLfloat)i * 50.0 ), 50.0 , 50.0 + ((GLfloat)(i + 1 ) * 50.0 ), 50.0 );
}
// 画第五行
glLineStipple( 5 , 0x1C47 );
drawALine( 50.0 , 25.0 , 350.0 , 25.0 );
glFlush();
}
void reshape( int w, int h)
{
glViewport( 0 , 0 ,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D( 0.0 ,(GLdouble)w, 0.0 ,(GLdouble)h);
}
int main( int argc, char * argv[])
{
glutInit( & argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition( 100 , 100 );
glutInitWindowSize( 400 , 400 );
glutCreateWindow( " OpenGL Stipple " );
init();
glutReshapeFunc( & reshape);
glutDisplayFunc( & display);
glutMainLoop();
return 0 ;
}
运行效果如图所示:
对如上程序作如下说明:
1、void drawALine(GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2)是用户自己编写的函数,实现画线功能:画出以(x1,y1)和(x2,y2)为端点的线段。因为后面的void display(void)函数要反复调用该函数。
2、对于函数:
void reshape(int w,int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h);
}
作如下解释:
(1)函数原型为void reshape(GLsizei w,GLsizei h),其中w表示视口(视口:是在屏幕上所绘制的一个矩形区域)宽度,h表示视口高度,通过协调w,h来实现改变视口的大小,当然也可以使视口保持不变的。尤其是在被调用时能够恢复视口大小。
(2)主函数main()中的glutReshapeFunc(&reshape);对void reshape(int w,int h)进行调用,使得无论何时改变窗口的大小,都能够使正方形看起来仍然是正方形,当减小窗口时,正方形也将变小。
(3)glViewport(0,0,(GLsizei)w,(GLsizei)h);的函数原型为:
void glViewport(GLint x,GLint y,GLsizei width,GLsizei height);
其中(x,y)定义了视口左下角的坐标,width和height定义了视口的宽度和高度,默认情况下视口区域初始值为(0,0,winWidth,winHeight),这里winWidth,winHeight分别为窗口的宽度和高度。
(4)glMatrixMode(GL_PROJECTION);的函数原型为:
void glMatrixMode(GLenum mode);
通过该函数可以实现用户所希望的矩阵模式,moded可以取值为GL_MODEVIEW、GL_PROJECTION、GL_TEXTURE,分别指定当前操纵的矩阵式模型视景矩阵、投影矩阵、纹理矩阵,随后的转换命令只影响指定的矩阵。
(5)glLoadIdentity();表示清除当前矩阵为单位矩阵。若不进行矩阵转换,当前矩阵就是单位矩阵。之所以在每步矩阵转换之后调用glLoadIdentity();是因为,下次进行矩阵转换的话就要乘以当前矩阵,如果没有调用glLoadIdentity();则直接乘以上次转换的矩阵(不是单位矩阵)就与用户的意愿偏离了,达不到预期效果。
(6)gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h);的函数原型为:
void gluOrtho2D(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top,GLdouble near,GLdouble far);
该函数创建了一个平行的视景体。(left,bottom,near)和(right,top,near)定义了近切面左下角和右上角的坐标,(left,bottom,far)和(right,top,far)定义了远切面的左下角和右上角的坐标。例如:gluOrtho2D()定义的正视投影,直观地如下图(来自网络)所示: