在几何学中有点,线,边,图形的概念,这些概念在计算机中也存在,但是可能会有所不同,比如数学中的直线是表示两端无限延伸的一条线,并且在数学中直线是没有宽度的,但是计算机中无法做到无限延伸,可以说计算机中的直线概念更像是数学中的线段概念,两个点的相连。同样点也是一样,数学中的点是表示一个坐标,并没有大小。计算机中无论图形设备多么精密也做不到显示一个无穷小的点,一般不设置点的大小的画,计算机会把点显示为1像素大小。在OpenGL中规定,一个多边形必须是一个“凸多边形”(多边形内任意两点所确定的线段都在多边形内,由此也可以推导出,凸多边形不能是空心的)。多边形可以由其边的顶点来确定。
好了,通过了解这些概念,我们可以利用点,线,多边形通过一些数学运算构成各种几何图形。
在上高中的时候,数学老师在讲几何基础的时候说过,点连成线,线移动成面。可以说点是所有几何图形的基础。在OpenGL中为我们提供了一系列函数来指定点,他们都是以glVertex开头,后面的数字表示参数,f,d等表示数据类型(有编程的应该都会清楚)。v结尾的函数参数是指针。OpenGL和C/C++不同的是,OpenGL中是没有定义sting和char类型(或者说是没有必要用)的,因为这些类型在图形中是没有意义的。还有int型在OpenGL中将这个类型定义为GLint和GLsizei;float型在OpenGL中将这个类型定义为GLfloat和GLclampf;double型在OpenGL中将这个类型定义为GLdouble和GLclampd。这些函数虽然参数类型和个数不同,但是却可以表示相同的功能,如下面几行代码的功能是一样的:
glVertex2i(1, 3);
glVertex2f(1.0f, 3.0f);
glVertex3f(1.0f, 3.0f, 0.0f);
glVertex4f(1.0f, 3.0f, 0.0f, 1.0f);
GLfloat VertexArr3[] = {1.0f, 3.0f, 0.0f};
glVertex3fv(VertexArr3);
我们知道如何确定顶点了,但是我们该如何约束这些点的行为呢?我们是要连成一条线,或者绘制一个多边形?OpenGL为我们提供了glBengin方法。OpenGL规定:指定顶点的命令必须包含在glBegin函数之后,glEnd函数之前(否则指定的顶点将被忽略)。并由glBegin来指明如何使用这些点。例如:
glBegin(GL_POINTS);//指定这些顶点的行为为GL_POINTS
glVertex2f(0.0f, 0.0f);
glVertex2f(0.5f, 0.0f);
glEnd();
这样会把这两个顶点显示出来,可以同过glPointSize方法来指定点的大小,如果将GL_POINTS替换成GL_LINES,则两个点将被认为是直线的两个端点,OpenGL将会画出一条直线。另外OpenGL还为我们提供了其他的参数来画出其他的集合图形,这里不作介绍。
在上中学的时候,我们大多的集合图形都是画在坐标系中,这里我们先显示一个坐标系,原点为屏幕中点。代码如下:
int const WINWEIGHT=400;
int const WINHEIGHT=400;
void drawSomething(){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//画线
glLineWidth(1.0f);//设置线的宽度
glBegin(GL_LINES);
glVertex2f(0.0f,-1.0f);
glVertex2f(0.0f,1.0f);//这两个点确定Y轴
glVertex2f(1.0f,0.0f);
glVertex2f(-1.0f,0.0f);//这两个点确定X轴
glEnd();
glFlush();
}
void InitializeCallback(){
glutDisplayFunc(drawSomething);
glutIdleFunc(drawSomething);
}
int _tmain(int argc, char* argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);//设置单缓冲
glutInitWindowSize(WINWEIGHT,WINHEIGHT);//设置窗体大小
glutInitWindowPosition(10,10);//设置窗体位置
glutCreateWindow("DrawSomething");
GLenum res=glewInit();
if(res!=GLEW_OK){
fprintf(stderr,"Error:%s",glewGetErrorString(res));
return 1;
}
InitializeCallback();
glClearColor(1.0f,0.0f,0.0f,0.0f);//窗体填充颜色为红色
glutMainLoop();
return 0;
}
我们会得到如下的显示:
我们来看drawSomething函数(下面的绘图只需改变这个函数),我们在这个函数中进行绘制操作。OpenGL把glVertex*函数的参数限制在[-1,1](可以做修改,不做解释)。我们确定了4个点,在glBegin中传入GL_LINES表示把点两两相连。这样就画出了坐标系。
画圆的方法应很多,这里就用最容易理解的一种方式。圆是什么?圆形就是有无穷多个边的多边形。边数越多,这个多边形就越接近圆。
#include
void drawSomething(){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//画圆
//圆上的各个点的坐标可以表示为(R*cos(x),R*sin(x));
//所以可以用多边形表示圆,当边数足够多,那么就越接近圆
const GLint n=100;//点数
const GLfloat R=0.5f;//半径
const GLfloat PI=3.1415926f;
glPointSize(3.0f);
//表示画出图形的模式.
//GL_LINES会把点1和点2,点3和点4依次类推连接起来,要指定glLineWidt,点数足够多的情况下会画出一个虚边圆或者实边圆
//GL_LINE_LOOP会画出一个未被填充的图形,只有边缘,要指定glLineWidt;
//GL_POLYGON会画出一个填充的多边形
//GL_POINTS只显示点
glBegin(GL_LINE_LOOP);
glColor3f(0.0f,0.0f,0.0f);//指定线条为黑色
for(int i=0;icos(2*PI/n*i),R*sin(2*PI/n*i));
}
glEnd();
glFlush();
上面声明的变量n是指点数,事实上我们可以通过改变n的值来画出不同的多边形,如:n=3的时候会画出一个正三角形。为4的时候是正方形。还有一点要特别注意,由于glVertex*函数参数被限制在[-1.0,1.0]之间,所以可以理解为这里的参数是表示占的窗口的比例。如同我们上面画的坐标系,OpenGL把窗口分成了四个象限。这就造成了一个问题,我们这里把窗口设置为长宽比例为1:1,如果不是这个值的画,那么画出来的就会是一个椭圆,至于怎么解决还需要更深的学习。总之上面代码的运行结果入下:
其实画五角星一般都会确认五个点,然后连接起来。关于如何确定点,不同人有不同的方法。这里我是假设五角星对应的正五边形的边长为R,然后通过三角函数来确定点的,这里不做详解,相信有初中数学基础的应该都会推算出来。
#include
void drawSomething(){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//画五角星
const GLfloat R=0.5f;
const int n=5;
const GLfloat PI=3.1415926f;
GLfloat Point[][5]={
{R*cos(2*PI/n*0),R*sin(2*PI/n*0)},
{R*cos(2*PI/n*1),R*sin(2*PI/n*1)},
{R*cos(2*PI/n*2),R*sin(2*PI/n*2)},
{R*cos(2*PI/n*3),R*sin(2*PI/n*3)},
{R*cos(2*PI/n*4),R*sin(2*PI/n*4)}
};
//glPointSize(2.0f);
glBegin(GL_LINE_LOOP);
glVertex2fv(Point[0]);
glVertex2fv(Point[2]);
glVertex2fv(Point[4]);
glVertex2fv(Point[1]);
glVertex2fv(Point[3]);
glEnd();
glFlush();
}
这个就简单了,不过就是注意一下,把坐标的比例缩小一下就行了
#include
void DrawSomething(GLvoid){
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLineWidth(1.0f);
glBegin(GL_LINES);
glVertex2f(-1.0f,0.0f);
glVertex2f(1.0f,0.0f);
glVertex2f(0.0f,1.0f);
glVertex2f(0.0f,-1.0f);
glEnd();
const GLfloat R=100.0f;
glBegin(GL_LINE_STRIP);
for (GLfloat i=-R;isin(i/5));
}
glEnd();
glFlush();
}