zoukankan      html  css  js  c++  java
  • 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:WindowsSysWOW64这个目录下

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

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

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

    包括上边的两个头文件

     1 void myDisplay(void)
     2 {
     3     glClear(GL_COLOR_BUFFER_BIT);
     4     glColor3f(0.0f, 1.0f, 0.0f);
     5     glRectf(-0.5f, -0.5f, 0.5f, 0.5f);
     6     glFlush();
     7 }
     8 
     9 int main(int argc, char *argv[])
    10 {
    11     glutInit(&argc, argv);
    12     glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    13     glutInitWindowPosition(100, 100);
    14     glutInitWindowSize(640, 480);
    15     glutCreateWindow("First_GL!");
    16     glutDisplayFunc(myDisplay);
    17     glutMainLoop();
    18 }

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

    学习:

    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)类似。

    开始绘制:

    1 glBegin(GL_POINTS); 
    2     glVertex2f(0.0f, 0.0f); 
    3     glVertex2f(0.5f, 0.0f); 
    4 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); // 载入第二幅纹理

  • 相关阅读:
    解决DataGridView中回车换行的问题
    几条经典的SQL语句
    SQL中把一个表中的数据导出到一个新表中
    [转载]TCP的网络编程中一些典型的问题,以及一些分析和解决方案
    Delphi调用C#web服务参数无法接收的问题
    IIS服务器不支持中文文件名的解决方法
    SQL SERVER2005导入导出工具
    为远程IP服务器取个本地认识的主机名
    Win Form中如何把ENter回车键转换成Tab键
    CheckedListBox 用法
  • 原文地址:https://www.cnblogs.com/chengyu404/p/5450454.html
Copyright © 2011-2022 走看看