OpenGL学习笔记

你好,窗口

  1. 创建一个窗口对象

    • 先初始化窗口,再创建窗口对象。glfwCreateWindow(宽, 高, 窗口名称, monitor, share)

      void framebuffer_size_callback(GLFWwindow* window, int width, int height);
      void processInput(GLFWwindow* window);
      
      glfwInit(); // 初始化GLFW
          //  配置GLFW
      glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);  
      glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
      glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
      glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
      
      //  glfwCreateWindow(宽,高,窗口名称, monitor,share),monitor用于全屏模式的监视器,share用于上下文共享资源的窗口
      GLFWwindow* windows = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Botao", NULL, NULL);
      
  2. glfwCreateWindow只能创建一个固定大小的窗口,若想要改变窗口大小的时候,就需要对窗口注册一个回调函数,在窗口被调整的时候调用

    int main
    {
        ...
        glfwSetFramebufferSizeCallback(windows, framebuffer_size_callback);
        ...
    }
    void framebuffer_size_callback(GLFWwindow* window, int width, int height)
    {
        glViewport(0, 0, width, height);
    }
    
  3. 添加渲染循环,让GLFW退出前一直保持运行

    • glfwWindowShouldClose函数在我们每次循环的开始前检查一次GLFW是否被要求退出,如果是的话该函数返回true然后渲染循环便结束了,之后为我们就可以关闭应用程序了。
    • glfwPollEvents函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置)。
    • glfwSwapBuffers函数会交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
    while(!glfwWindowShouldClose(window))
    {
        glfwSwapBuffers(window);
        glfwPollEvents();    
    }
    
  4. 添加输入控制,glfwGetKey会返回该按键是否被按下,可用于控制窗口的关闭

    void processInput(GLFWwindow *window)
    {
        if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, true);
    }
    while (!glfwWindowShouldClose(window))
    {
        ...
        processInput(window);
    
        glfwSwapBuffers(window);
        glfwPollEvents();
        ...
    }
    
    
  5. 渲染,所有的渲染操作都需要放到渲染循环中,这样每次渲染循环迭代才都能被执行

你好,三角形

  1. 在3D空间中工作,渲染一个2D三角形,则需要把顶点的z坐标设置为0

  2. 顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER,glBindBuffer函数把新创建的缓冲绑定在GL_ARRARY_BUFFER上,glBufferData函数把定义的顶点数据复制到缓冲内存。glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数

    unsigned int VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);  
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
  3. 顶点缓冲数据解析:

    • 位置数据被储存为32位(4字节)浮点值。

    • 每个位置包含3个这样的值。

    • 在这3个值之间没有空隙(或其他值)。这几个值在数组中紧密排列(Tightly Packed)。

    • 数据中第一个值在缓冲开始的位置。
      在这里插入图片描述

  4. 顶点数组对象,可以像顶点缓冲对象那样绑定,任何随后的顶点属性调用都会储存在VAO中。好处就是,当配置顶点属性指针时,只需要调用执行一次,之后再绘制物体时只需绑定相应的VAO就行。顶点数组对象存储的内容如下:

    • glEnableVertexAttribArray和glDisableVertexAttribArray的调用。
    • 通过glVertexAttribPointer设置的顶点属性配置。
    • 通过glVertexAttribPointer调用与顶点属性关联的顶点缓冲对象。
      在这里插入图片描述
  5. 索引缓冲对象,工作方式与顶点缓冲对象一样,专门存储索引,OpenGL调用顶点的索引来决定该绘制哪个顶点

着色器

  1. 着色器是使用GLSL的类C语言写成。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。着色器的开头总是要声明版本,接着是输入和输出变量、uniform和main函数。
  2. 数据类型,GLSL有数据类型可以来指定变量的种类,其中包含了两种容器类型,分别是向量(Vector)和矩阵(Matrix)
  3. 着色器是各自独立的小程序,GLSL定义了in和out关键字专门来实现其输入和输出
  4. uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。uniform是全局的,意味着该变量对象是独一无二的,且被着色器程序的任意着色器在任意阶段访问

纹理

  1. 纹理是一个2D图片(也有1D和3D纹理),它可以用来添加物品的细节,除了图像以外,纹理也可以被用来储存大量的数据。

  2. 纹理环绕方式,纹理坐标的范围通常是从(0,0)到(1,1)

    环绕方式描述
    GL_REPEAT对纹理的默认行为。重复纹理图像。
    GL_MIRRORED_REPEAT和GL_REPEAT一样,但每次重复图片是镜像放置的。
    GL_CLAMP_TO_EDGE纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。
    GL_CLAMP_TO_BORDER超出的坐标为用户指定的边缘颜色。
  3. 纹理过滤,较为重要的两种分别为:GL_NEAREST和GL_LINEAR

    1. GL_NEAREST,也叫邻近过滤,是OpenGL默认的纹理过滤方式
    2. GL_LINEAR,也叫线性过滤,基于纹理坐标附近的纹理像素,计算出一个差值,近似出这些纹理像素之间的颜色
  4. 多级渐远纹理,简而言之,就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。其理念就是距观察者的距离超过一定的阙值,OpenGL就会使用不同的多级渐远纹理,即最适合物体的距离的那个

    过滤方式描述
    GL_NEAREST_MIPMAP_NEAREST使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样
    GL_LINEAR_MIPMAP_NEAREST使用最邻近的多级渐远纹理级别,并使用线性插值进行采样
    GL_NEAREST_MIPMAP_LINEAR在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样
    GL_LINEAR_MIPMAP_LINEAR在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样
  5. 新增纹理后,顶点属性的存储格式为
    在这里插入图片描述

  6. 纹理单元,一个纹理的位置值通常称为一个纹理单元,一个纹理的默认纹理单位是0,它是默认的激活纹理单位。其目的是让我们在着色器中可以使用多于一个的纹理

变换

  1. OpenGL有个量身定做的数学库GLM,GLM默认会将矩阵类型初始化为一个零矩阵,而不是单位矩阵
  2. GLSL中有mat2和mat3类型从而允许了像向量一样的混合计算

坐标系统

  1. 为了将坐标从一个坐标系变换到另一个坐标系,需要用到几个变换矩阵,其中最重要的包括模型(Model)、观察(View)、投影(Projection)三个矩阵。顶点坐标始于局部坐标,然后变为世界坐标,观察坐标,裁剪坐标并最后以屏幕坐标的形式结束。该为整个流程以及各个变换过程

    1. 局部坐标是对象相对于局部原点的坐标,也是物体起始的坐标。
    2. 下一步是将局部坐标变换为世界空间坐标,世界空间坐标是处于一个更大的空间范围的。这些坐标相对于世界的全局原点,它们会和其它物体一起相对于世界的原点进行摆放。
    3. 接下来我们将世界坐标变换为观察空间坐标,使得每个坐标都是从摄像机或者说观察者的角度进行观察的。
    4. 坐标到达观察空间之后,我们需要将其投影到裁剪坐标。裁剪坐标会被处理至-1.0到1.0的范围内,并判断哪些顶点将会出现在屏幕上。
    5. 最后,我们将裁剪坐标变换为屏幕坐标,我们将使用一个叫做视口变换(Viewport Transform)的过程。视口变换将位于-1.0到1.0范围的坐标变换到由glViewport函数所定义的坐标范围内。最后变换出来的坐标将会送到光栅器,将其转化为片段。
      在这里插入图片描述
  2. 局部空间,指物体所在的空间坐标,即对象最开始所在的地方

  3. 世界坐标,顶点相对于(游戏)世界的坐标

  4. 观察空间,将世界空间坐标转化为用户视野前方的坐标而产生的结果

  5. 裁剪空间,OpenGL期望所有的坐标都能落在一个特定的范围内,且任何在这个范围之外的点都应该被裁剪掉。被裁后,剩下的坐标就变为屏幕上所见的片段。

  6. 正射投影,正射投影矩阵定义了一个类似立方体的平截头箱,定义了一个裁剪空间,在这个空间之外的顶点都会被裁剪掉

  7. 透视投影,类似于近大远小的视觉效果。由于透视,会导致两条平行的线在很远的地方会看起来相交

  8. Z缓冲,OpenGL存储它的所有深度信息于一个Z缓冲(Z-buff)中,被称为深度缓冲。GLFW会自动为你生成一个这样的缓冲。深度值存储在每个片段里面,当片段想要输出它的颜色时,OpenGL会将它的深度值和z缓冲进行比较,如果当前的片段在其他片段之后,它将会被丢弃,否则将会覆盖。这个过程称之为深度测试

摄像机

  1. OpenGL本没有摄像机,是通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生一种我们在移动的感觉,而不是场景在移动。
  2. 摄像机的视角作为场景原点时场景中所有的顶点坐标;观察矩阵把所有的世界坐标变换为相对于摄像机位置和方向的观察坐标。
  3. 右轴,定义一个右向量,代表着摄像机空间的x轴的正方向。为方便获取右向量,先定义一个上向量,与右向量进行叉乘,可得到指向x轴的正方向
  4. 上轴,通过x轴和z轴向量,获取一个指向摄像机的正y轴向量
  5. LookAt矩阵,可通过三个相互垂直的轴和一个定义摄像机空间的位置坐标来创建。LookAt矩阵作为观察矩阵可以很高效地把所有世界坐标变换抽到刚刚定义的观察空间
  6. 对右向量进行了标准化后。如果没对其他向量进行标准化,最后的叉乘结果会根据cameraFront变量返回大小不同的像狼。如果不对向量进行标准化,我们就得根据摄像机的朝向不同加速或减速移动,但如果进行了标准化移动的就是匀速的
  7. 欧拉角,可以表示3D空间中任何旋转的3个值,可用于视角的移动。3种欧拉角分别是:俯仰角(Pitch)、偏航角(Yaw)和滚转角(Roll)
    1. 俯仰角,描述我们如何往上看或往下看的角
    2. 偏航角,表示我们往左和往右看的程度
    3. 滚转角,代表我们如何翻滚摄像机。通常使用在太空飞船的摄像机
  8. 缩放,视野或fov定义了我们可以看到场景中多大的范围。当视野变小时,场景投影出来的空间就会减少,缠上了放大的感觉。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值