opengl学习笔记

时间:2023-03-09 04:40:09
opengl学习笔记

准备:

1、准备资源:
GLEW1.13.0下载GLEW,并且解压出glew-1.13.0目录。
从FreeGLUT官网下载3.0.0版本。直接从这里下的编译后的FreeGLUT,选for MSVC,下载后解压。

2、将所有的x64(64位)版本的.h和.lib拷贝到vs2015安装目录下的vc文件夹里的include和lib里

将所有.dll文件拷贝到C:\Windows\SysWOW64这个目录下

如果是32位系统就不一样了

3、打开ivs2015,创建新的控制台应用程序

#include <glut.h>
#include <glew.h>

包括上边的两个头文件

 void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0f, 1.0f, 0.0f);
glRectf(-0.5f, -0.5f, 0.5f, 0.5f);
glFlush();
} int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(, );
glutInitWindowSize(, );
glutCreateWindow("First_GL!");
glutDisplayFunc(myDisplay);
glutMainLoop();
}

写下如上代码,如果运行成功,并且里边有一个正方形,即代表配置成功

学习:

1、glutInit,对GLUT进行初始化,这个函数必须在其它的GLUT使用之前调用一次。其格式比较死板,一般照抄这句glutInit(&argc, argv)就可以了。

2、glutInitDisplayMode,设置显示方式,其中GLUT_RGB表示使用RGB颜色,与之对应的还有GLUT_INDEX(表示使用索引颜色)。GLUT_SINGLE表示使用单缓冲,与之对应的还有GLUT_DOUBLE(使用双缓冲)。更多信息,请自己Google。当然以后的教程也会有一些讲解。

3、glutInitWindowPosition,这个简单,设置窗口在屏幕中的位置。

4、glutInitWindowSize,这个也简单,设置窗口的大小。

5、glutCreateWindow,根据前面设置的信息创建窗口。参数将被作为窗口的标题。注意:窗口被创建后,并不立即显示到屏幕上。需要调用glutMainLoop才能看到窗口。

6、glutDisplayFunc,设置一个函数,当需要进行画图时,这个函数就会被调用。(这个说法不够准确,但准确的说法可能初学者不太好理解,暂时这样说吧)。

7、glutMainLoop,进行一个消息循环。(这个可能初学者也不太明白,现在只需要知道这个函数可以显示窗口,并且等待窗口关闭后才会返回,这就足够了。)

在glutDisplayFunc函数中,我们设置了“当需要画图时,请调用myDisplay函数”。于是myDisplay函数就用来画图。观察myDisplay中的三个函数调用,发现它们都以gl开头。

1、glClear,清除。GL_COLOR_BUFFER_BIT表示清除颜色,glClear函数还可以清除其它的东西,但这里不作介绍。

2、glColor3f,设置颜色。即用浮点数设置RGB三原色,后边的画图都用此时设置的颜色,直到再次调用该函数,1.0f==255,0.0f==0

3、glRectf,画一个矩形。四个参数分别表示了位于对角线上的两个点的横、纵坐标。

4、glFlush,保证前面的OpenGL命令立即执行(而不是让它们在缓冲区中等待)。其作用跟fflush(stdout)类似。

开始绘制:

 glBegin(GL_POINTS);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.5f, 0.0f);
glEnd();

在绘图函数中写下如上代码,即可在屏幕中绘制出两个点,glVertex2f代表设置点的位置信息

如果将GL_POINTS替换成GL_LINES,则两个点将被认为是直线的两个端点,OpenGL将会画出一条直线。

即glBegin,glEnd中间夹的代码就是要绘制的点,glBegin的参数即是将下边设置的点按照参数设置的方式绘制出来

glBegin支持的方式除了GL_POINTS和GL_LINES,还有GL_LINE_STRIP,GL_LINE_LOOP,GL_TRIANGLES,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN等

矩阵与变换

1、 模型变换和视图变换

从“相对移动”的观点来看,改变观察点的位置与方向和改变物体本身的位置与方向具有等效性。在OpenGL中,实现这两种功能甚至使用的是同样的函数。 由于模型和视图的变换都通过矩阵运算来实现,在进行变换前,应先设置当前操作的矩阵为“模型视图矩阵”。设置的方法是以GL_MODELVIEW为参数调用glMatrixMode函数,像这样: glMatrixMode(GL_MODELVIEW);

通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。这也只需要一行代码:glLoadIdentity();

然后,就可以进行模型变换和视图变换了。进行模型和视图变换,主要涉及到三个函数:

glTranslate*,把当前矩阵和一个表示移动物体的矩阵相乘。三个参数分别表示了在三个坐标上的位移值。

glRotate*,把当前矩阵和一个表示旋转物体的矩阵相乘。物体将绕着(0,0,0)到(x,y,z)的直线以逆时针旋转,参数angle表示旋转的角度。

glScale*,把当前矩阵和一个表示缩放物体的矩阵相乘。x,y,z分别表示在该方向上的缩放比例。

2、投影变换

投影变换就是定义一个可视空间,可视空间以外的物体不会被绘制到屏幕上。(注意,从现在起,坐标可以不再是-1.0到1.0了!) OpenGL支持两种类型的投影变换,即透视投影和正投影。投影也是使用矩阵来实现的。如果需要操作投影矩阵,需要以GL_PROJECTION为参数调用glMatrixMode函数。 glMatrixMode(GL_PROJECTION);

通常,我们需要在进行变换前把当前矩阵设置为单位矩阵。 glLoadIdentity();

使用glFrustum函数可以将当前的可视空间设置为透视投影空间。

使用glOrtho函数可以将当前的可视空间设置为正投影空间。

3、视口变换 当一切工作已经就绪,只需要把像素绘制到屏幕上了。这时候还剩最后一个问题:应该把像素绘制到窗口的哪个区域呢?通常情况下,默认是完整的填充整个窗口,但我们完全可以只填充一半。

使用glViewport来定义视口。其中前两个参数定义了视口的左下脚(0,0表示最左下方),后两个参数分别是宽度和高度。

纹理:

1、启用纹理和载入纹理 就像我们曾经学习过的OpenGL光照、混合等功能一样。在使用纹理前,必须启用它。OpenGL支持一维纹理、二维纹理和三维纹理,这里我们仅介绍二维纹理。可以使用以下语句来启用和禁用二维纹理:
glEnable(GL_TEXTURE_2D); // 启用二维纹理

glDisable(GL_TEXTURE_2D); // 禁用二维纹理

使用纹理前,还必须载入纹理。利用glTexImage2D函数可以载入一个二维的纹理,该函数有多达九个参数(虽然某些参数我们可以暂时不去了解),现在分别说明如下:

第一个参数为指定的目标,在我们的入门教材中,这个参数将始终使用GL_TEXTURE_2D。

第二个参数为“多重细节层次”,现在我们并不考虑多重纹理细节,因此这个参数设置为零。

第三个参数有两种用法。在OpenGL 1.0,即最初的版本中,使用整数来表示颜色分量数目,例如:像素数据用RGB颜色表示,总共有红、绿、蓝三个值,因此参数设置为3,而如果像素数据是用RGBA颜色表示,总共有红、绿、蓝、alpha四个值,因此参数设置为4。而在后来的版本中,可以直接使用GL_RGB或GL_RGBA来表示以上情况,显得更直观(并带来其它一些好处,这里暂时不提)。注意:虽然我们使用Windows的BMP文件作为纹理时,一般是蓝色的像素在最前,其真实的格式为GL_BGR而不是GL_RGB,在数据的顺序上有所不同,但因为同样是红、绿、蓝三种颜色,因此这里仍然使用GL_RGB。(如果使用GL_BGR,OpenGL将无法识别这个参数,造成错误)

第四、五个参数是二维纹理像素的宽度和高度。这里有一个很需要注意的地方:OpenGL在以前的很多版本中,限制纹理的大小必须是2的整数次方,即纹理的宽度和高度只能是16, 32, 64, 128, 256等值,直到最近的新版本才取消了这个限制。

2、纹理坐标

只要指定每一个顶点在纹理图象中所对应的像素位置,OpenGL就会自动计算顶点以外的其它点在纹理图象中所对应的像素位置。

通常,每个顶点使用不同的纹理,于是下面这样形式的代码是比较常见的。
glBegin( /* ... */ );

  glTexCoord2f( /* ... */ );

  glVertex3f( /* ... */ );

  glTexCoord2f( /* ... */ );

  glVertex3f( /* ... */ ); /* ... */

glEnd();

3、纹理参数

使用glTexParameter*系列函数来设置纹理参数。通常需要设置下面四个参数:GL_TEXTURE_MAG_FILTER:指当纹理图象被使用到一个大于它的形状上时(即:有可能纹理图象中的一个像素会被应用到实际绘制时的多个像素。例如将一幅256*256的纹理图象应用到一个512*512的正方形),应该如何处理。可选择的设置有GL_NEAREST和GL_LINEAR,前者表示“使用纹理中坐标最接近的一个像素的颜色作为需要绘制的像素颜色”,后者表示“使用纹理中坐标最接近的若干个颜色,通过加权平均算法得到需要绘制的像素颜色”。前者只经过简单比较,需要运算较少,可能速度较快,后者需要经过加权平均计算,其中涉及除法运算,可能速度较慢(但如果有专门的处理硬件,也可能两者速度相同)。从视觉效果上看,前者效果较差,在一些情况下锯齿现象明显,后者效果会较好(但如果纹理图象本身比较大,则两者在视觉效果上就会比较接近)。

  GL_TEXTURE_MIN_FILTER:指当纹理图象被使用到一个小于(或等于)它的形状上时(即有可能纹理图象中的多个像素被应用到实际绘制时的一个像素。例如将一幅256*256的纹理图象应用到一个128*128的正方形),应该如何处理。可选择的设置有    

  GL_NEAREST,GL_LINEAR,GL_NEAREST_MIPMAP_NEAREST,GL_NEAREST_MIPMAP_LINEAR,GL_LINEAR_MIPMAP_NEAREST和GL_LINEAR_MIPMAP_LINEAR。其中后四个涉及到mipmap,现在暂时不需要了解。前两个选项则和GL_TEXTURE_MAG_FILTER中的类似。此参数似乎是必须设置的(在我的计算机上,不设置此参数将得到错误的显示结果,但我目前并没有找到根据)。

  GL_TEXTURE_WRAP_S:指当纹理坐标的第一维坐标值大于1.0或小于0.0时,应该如何处理。基本的选项有GL_CLAMP和GL_REPEAT,前者表示“截断”,即超过1.0的按1.0处理,不足0.0的按0.0处理。后者表示“重复”,即对坐标值加上一个合适的整数(可以是正数或负数),得到一个在[0.0, 1.0]范围内的值,然后用这个值作为新的纹理坐标。例如:某二维纹理,在绘制某形状时,一像素需要得到纹理中坐标为(3.5, 0.5)的像素的颜色,其中第一维的坐标值3.5超过了1.0,则在GL_CLAMP方式中将被转化为(1.0, 0.5),在GL_REPEAT方式中将被转化为(0.5, 0.5)。在后来的OpenGL版本中,又增加了新的处理方式,这里不做介绍。如果不指定这个参数,则默认为GL_REPEAT。

  GL_TEXTURE_WRAP_T:指当纹理坐标的第二维坐标值大于1.0或小于0.0时,应该如何处理。选项与GL_TEXTURE_WRAP_S类似,不再重复。如果不指定这个参数,则默认为GL_REPEAT。

设置参数的代码如下所示:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

4、纹理对象

glGenTextures来分配纹理对象。该函数有两种比较常见的用法:
GLuint texture_ID; glGenTextures(1, &texture_ID); // 分配一个纹理对象的编号

glBindTexture(GL_TEXTURE_2D, texture_ID_1); // 载入第一幅纹理

glBindTexture(GL_TEXTURE_2D, texture_ID_2); // 载入第二幅纹理