
OpenGL笔记
文章平均质量分 76
OpenGL学习笔记
ycr的帐号
这个作者很懒,什么都没留下…
展开
-
【OpenGL】笔记二十九、抗锯齿(MSAA)
经过之前的教程,我们目前渲染出来的画面已经有了足够的表现力,但是还是有一些缺陷,比如当我们的渲染画面分辨率跟不上屏幕分辨率时,在我们渲染的图形边缘一些比较严重的锯齿效果就会显现:自然,这种效果就是因为画面采样像素太少,从而在一条直线上出现了明显的“断带”: 那么,理所当然的,解铃还须系铃人,我们可以增大采样数量,而目前应用比较广泛的抗锯齿方法也是多重采样MSAA,这种方法的原理很简单,就是将每个采样的像素分为四个像素进行采样计算,最后将结果进行平均计算: 在【OpenGL】笔记二十三、帧缓冲中,我原创 2022-07-03 00:19:05 · 3723 阅读 · 1 评论 -
【OpenGL】笔记三十、高级光照(镜面高光)
传统的冯氏光照模型中,镜面光照的算法能够取得比较好的效果:但是该光照模型也有限制,可以看到,在下图镜面高光区域的边缘出现了一道很明显的断层。出现这个问题的原因是观察向量和反射向量间的夹角不能大于90度。如果点积的结果为负数,镜面光分量会变为0.0。在进行漫反射光照计算时,光照方向与法向量夹角超过90°就代表着光照来自背面,这时不显示光照是正确的,但是镜面光的计算可不是这样,因为光照入射角和视角夹角大于90°可不是什么违背常理的事,要解决这部分光照的缺陷,我们就要想另一种方式来进行近似:那就是如原创 2022-06-29 21:48:45 · 825 阅读 · 0 评论 -
【OpenGL】杂谈一、通过鼠标拖拽实现相机绕空间中的某点进行球面旋转查看
这是我最近遇到的一个问题,如题所示,我需要通过鼠标拖拽实现相机绕点的球面旋转,原本的想法很简单,类似笔记八、摄像机中提到的那样,从聚焦中心点的视角出发,将鼠标移动的距离xoffset和yoffset转换为yaw和pitch角,然后计算出该视角的向量,与球面求交从而得到相机的当前位置,但是实际过程中出现了一个比较严重的问题,就是欧拉角的致命缺陷——万向锁,如果pitch角超过±90°,我们就会遇到各种问题,在设计第一视角时我们可以控制pitch角在90°到-90°之间,这不影响我们的体验,但是如果我们要控制相原创 2022-06-28 00:28:00 · 1733 阅读 · 1 评论 -
【OpenGL】笔记二十八、实例化
假设你有一个绘制了很多模型的场景,而大部分的模型包含的是同一组顶点数据,只不过进行的是不同的世界空间变换。想象一个充满草的场景:每根草都是一个包含几个三角形的小模型。你可能会需要绘制很多根草,最终在每帧中你可能会需要渲染上千或者上万根草。因为每一根草仅仅是由几个三角形构成,渲染几乎是瞬间完成的,但上千个渲染函数调用却会极大地影响性能。如果我们能够将数据一次性发送给GPU,然后使用一个绘制函数让OpenGL利用这些数据绘制多个物体,就会更方便了。这就是实例化(Instancing)。如果想使用实例化渲染,我们原创 2022-06-06 08:16:51 · 460 阅读 · 0 评论 -
【OpenGL】笔记二十七、几何着色器
在顶点和片段着色器之间有一个可选的几何着色器(Geometry Shader),几何着色器的输入是一个图元(如点或三角形)的一组顶点。几何着色器可以在顶点发送到下一着色器阶段之前对它们随意变换。然而,几何着色器最有趣的地方在于,它能够将(这一组)顶点变换为完全不同的图元,并且还能生成比原来更多的顶点。在几何着色器的顶部,我们需要声明从顶点着色器输入的图元类型。这需要在in关键字前声明一个布局修饰符(Layout Qualifier)。这个输入布局修饰符可以从顶点着色器接收下列任何一个图元值:接下来,我们还原创 2022-06-05 21:10:30 · 851 阅读 · 0 评论 -
【OpenGL】笔记二十六、高级GLSL
之前我们对于GLSL只是进行了比较简单的应用,接下来就来介绍一下更有趣的应用我们已经学会使用顶点属性、uniform和采样器来往着色器传入数据了,然而,除此之外,GLSL还定义了另外几个以gl_为前缀的变量,它们能提供给我们更多的方式来读取/写入数据。(我们已经在前面教程中接触过其中的两个了:顶点着色器的输出向量gl_Position,和片段着色器的gl_FragCoord)我们能够选用的其中一个图元是GL_POINTS,如果使用它的话,每一个顶点都是一个图元,都会被渲染为一个点。我们可以通过OpenGL的原创 2022-06-05 09:30:50 · 1890 阅读 · 0 评论 -
【OpenGL】笔记二十五、高级数据
除了用缓冲来储存数据,我们还可以有更多的玩法首先,用glBufferData往VBO里填充数据的时候,我们可以把data参数设置为NULL,让它被分配为空的内存,然后我们可以利用glBufferSubData在自己想要的位置插入数据:如上,我们在分配的内存里从第24位开始填充数据除此之外,我们还可以请求缓冲内存的指针,直接将数据复制到缓冲当中如上,通过调用glMapBuffer函数,OpenGL会返回当前绑定缓冲的内存指针,供我们操作当我们使用glUnmapBuffer函数,告诉OpenGL我们已经完成原创 2022-06-05 00:39:29 · 182 阅读 · 0 评论 -
【OpenGL】笔记二十四、立方体贴图
之前我们使用了不少2D形式的贴图,那么现在有没有其他类型的贴图呢?当然有,比如立方体贴图,它就是由6个2D贴图组合而成的:那么为什么要把6张纹理合并到一张纹理中,而不是直接使用6个单独的纹理呢?立方体贴图有一个非常有用的特性,它可以通过一个方向向量来进行索引/采样。假设我们有一个1x1x1的单位立方体,要求某个点的纹理颜色是什么该怎么办呢?现在从这个立方体的中心出发,与立方体上要求的点之间能够形成一个方向向量,那么通过这个向量,我们就可以通过立方体贴图很方便的查到纹理颜色(因为也是可以从立方体贴图原点出原创 2022-06-04 21:29:46 · 1087 阅读 · 0 评论 -
【OpenGL】笔记二十三、帧缓冲
达成了各种渲染效果以后,现在我们想要更进一步,对屏幕的每一个像素进行精准着色,或者对渲染后的图像再进行全局效果处理(比如镜子、模糊等效果),这些做法在之前是没有办法实现的,我们该怎么办?其实OpenGL给出了一种数据缓冲——帧缓冲(Framebuffer),我们之前用的颜色缓冲、深度缓冲和模板缓冲就是包含在帧缓冲之中的,我们之前所做的渲染也都是在默认的帧缓冲中做的,完成一切渲染后,OpenGL就会从帧缓冲中读取数据,然后渲染到屏幕上的每一个像素当然,想要做出自己的效果,我们肯定需要定义一个自己的帧缓冲,一个原创 2022-06-03 20:57:14 · 1249 阅读 · 2 评论 -
【OpenGL】笔记二十二、面剔除
渲染一个立方体的时候,我们会对它的六个面的点先进行一遍深度测试,如果没有通过的话就是被遮挡了,就不着色,但是仔细想,一个立方体至少会有三个面被遮挡,我们明明知道这一点,却还是要对被遮挡的每个面上的点进行深度测试,这是不是有点浪费时间呢?所以我们可以想一种方法,每次渲染一个物体的时候,判断每个面是不是正面朝向相机,如果不是就跳过这个面,这样是不是就可以节省至少50%以上的精力?当我们定义一组三角形顶点时,我们会以特定的环绕顺序来定义它们,可能是顺时针(Clockwise)的,也可能是逆时针(Counter-c原创 2022-06-01 01:48:23 · 400 阅读 · 0 评论 -
【OpenGL】笔记二十一、Alpha测试、混合测试
1. 流程原创 2022-06-01 00:59:10 · 1836 阅读 · 0 评论 -
【OpenGL】笔记二十、模板测试
1. 流程当片段着色器处理完一个片段之后,模板测试(Stencil Test)会开始执行,和深度测试一样,它也可能会丢弃片段。接下来,被保留的片段会进入深度测试,它可能会丢弃更多的片段。一个模板缓冲中,(通常)每个模板值(Stencil Value)是8位的。所以每个像素/片段一共能有256种不同的模板值。我们可以将这些模板值设置为我们想要的值,然后当某一个片段有某一个模板值的时候,我们就可以选择丢弃或是保留这个片段了。利用模板测试,我们可以限制渲染区域、渲染阴影,渲染物体粗轮廓等,下面是一个限制区域原创 2022-05-31 05:17:55 · 395 阅读 · 0 评论 -
【OpenGL】笔记十九、深度测试
1. 流程在前面的教程中,我们有简略介绍过深度测试,它的存在帮助我们最终渲染的画面不会存在那些本应被遮挡住了的图像,其实若深究其中的原理的话,倒也没多复杂,就是每次渲染一个图形时测测当前这个要渲染的像素是否是目前离屏幕最近的,若是,就说明没有被其他物体遮挡,就可以把它的颜色映射到屏幕上,而这个距离就是由depth_buffer所存储,每次渲染一个新图形的时候我们就去比较和更新这个buffer。1.1 深度测试一般情况下,深度测试默认是禁用的,所以如果要启用深度测试的话,我们需要用GL_DEPTH_T原创 2022-05-30 23:24:32 · 1271 阅读 · 2 评论 -
【OpenGL】笔记十八、利用Assimp加载自定义模型(Model类)
1.流程1.1 头文件经过上节网格类的设置以后,我们现在开始正式接触assimp(上图为其简化结构),加载自己的模型,首先我们要使用assimp,就需要它的头文件:#include <assimp/Importer.hpp>#include <assimp/scene.h>#include <assimp/postprocess.h>1.2 Model类其次我们要定义一个Model类,包含一个构造函数用于读取数据,一个Draw函数用于渲染,一个上节定义的原创 2022-05-30 20:37:39 · 2735 阅读 · 0 评论 -
【OpenGL】笔记十七、网格类(复杂模型的存储与渲染)
1. 流程完成了assimp的配置,接下来就进入到模型环节了,首先是网格(Mesh),它代表的是单个的可绘制实体,我们现在先来定义一个我们自己的网格类。一个网格应该至少需要一系列的顶点,每个顶点包含一个位置向量、一个法向量和一个纹理坐标向量。一个网格还应该包含用于索引绘制的索引以及纹理形式的材质数据(漫反射/镜面光贴图)。既然我们有了一个网格类的最低需求,我们可以在OpenGL中定义一个顶点了,我们将所有需要的向量储存到一个叫做Vertex的结构体中,我们可以用它来索引每个顶点属性。:struct原创 2022-05-29 22:34:47 · 497 阅读 · 0 评论 -
【OpenGL】笔记九、相机类
1.流程在上节完成了相机的各种操作之后,我们的主程序代码中充斥了各种全局变量和不明的函数调用,为了能够使代码更加简洁易读,我们对相机也自定义一个类1.1 Camera类首先给出Camera类的粗略定义,先是它的各项坐标向量:class Camera{public: // camera Attributes glm::vec3 Position; glm::vec3 Front; glm::vec3 Up; glm::vec3 Right; glm:原创 2022-05-29 22:33:05 · 546 阅读 · 0 评论 -
【OpenGL】笔记十六、Assimp v5.2.4 编译配置(Win10 / x64 / VS2019 )
目录1. 编译库1.1 下载源码1.2 CMake编译1.2.1 Could not locate DirectX 错误1.2.2 Error Code:s10231.3 生成解决方案1.3.1 无法打开包括文件: “gtest/gtest.h”/“gtest.lib”?2. 在VS中配置库文件2.1 config.h2.2 头文件2.3 .lib 文件2.4 .dll 文件3. 尝试1. 编译库学过了不同光照的渲染,接下来就轮到更多模型的拓展了,现实生活中我们不可能所有物体都是简单的立方体,还会有更复原创 2022-05-23 11:39:51 · 4525 阅读 · 6 评论 -
【OpenGL】笔记十五、多光源
1. 流程介绍完了几种光源,现在我们要综合一下,我们将模拟一个类似太阳的定向光(Directional Light)光源,四个分散在场景中的点光源(Point Light),以及一个手电筒(Flashlight)。但是三种光源都写一遍有些杂乱,分开写着色器的话又有些浪费,怎么办呢?GLSL里面也有函数封装,我们把三种光源的属性分别定义结构体,然后传入函数计算,最后相加就行:#version 330 corestruct Material { sampler2D diffuse; sa原创 2022-05-22 20:57:55 · 331 阅读 · 0 评论 -
【OpenGL】笔记十四、投光物
1. 流程之前一致都是默认基于点光源的讨论,本节将讨论更多的光源1.1 平行光当一个光源处于很远的地方时,来自光源的每条光线就会近似于互相平行。不论物体和/或者观察者的位置,看起来好像所有的光都来自于同一个方向。这种情况比较简单,我们可以对之前在片段着色器里设置的光源结构体里将光源位置直接定义为光源方向struct Light { //vec3 position; vec3 direction; vec3 ambient; vec3 diffuse; ve原创 2022-05-22 11:42:14 · 468 阅读 · 0 评论 -
【OpenGL】笔记十三、光照贴图
1. 流程简单的光照材质无法满足要求,接下来我们要对不同材质的物体在各个片段的反射做出精准控制1.1 漫反射贴图之前,我们对物体的漫反射做了简单的单色定义,现在我们加入纹理贴图,让纹理的颜色作为漫反射的颜色:...原创 2022-05-22 02:42:22 · 655 阅读 · 0 评论 -
【OpenGL】笔记十二、材质
1. 流程接上节布林冯模型,现实生活中物体还会有不同的反光效果当描述一个表面时,我们可以分别为三个光照分量定义一个材质颜色(Material Color):环境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和镜面光照(Specular Lighting)。通过为每个分量指定一个颜色,我们就能够对表面的颜色输出有细粒度的控制了。现在,我们再添加一个反光度(Shininess)分量,结合上述的三个颜色,我们就有了全部所需的材质属性了#version 330 cor原创 2022-05-21 21:15:04 · 784 阅读 · 1 评论 -
【OpenGL】笔记十一、基础光照(布林冯)
1. 流程解释了颜色的一部分原理,接下来介绍一种应用普遍的基础光照模型:布林-冯 Blinn-Phong布林冯光照模型分为三个分量,环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。:环境光照(Ambient Lighting):即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色。漫反射光照(Diffuse Lighting):模拟光源对物体的方向性影响(原创 2022-05-21 03:57:44 · 1631 阅读 · 0 评论 -
【OpenGL】笔记十、颜色
1. 流程光打在一个物体上,它反射出来的光是什么颜色的?比如白色的太阳光,打在红色的物体上,我们看到的就是红色,而又因为白色光是所有可见颜色的集合,我们可不可以这样想:白光打在物体上面,物体选择性接收rgb通道的光,反射出来的就是没有吸收的,比如下面这个例子,物体的颜色可以看作RGB反射率,白光与物体颜色相乘,结果就是反射出来的光glm::vec3 lightColor(1.0f, 1.0f, 1.0f);glm::vec3 toyColor(1.0f, 0.5f, 0.31f);glm::ve原创 2022-05-20 21:42:00 · 284 阅读 · 0 评论 -
【OpenGL】笔记八、摄像机(View矩阵)
流程上回说到了MVP矩阵的使用,但是在view矩阵的设置时比较粗略,view矩阵变换本质是转换到相机坐标系,是根据相机的位置变换的,上次我们只是将相机往z轴正方向移了三个单位而已,但是现实的情况是相机可能会以各种方式移动,现在就来正式讨论相机坐标系的变换首先要知道,相机坐标系需要三个属性来定义,分别是位置坐标(原点),看向的方向(-z轴)和向上向量(y轴),这是默认的,知道了这些,就能根据叉乘等算出整个坐标系的轴的向量,然后就能根据这些求出世界坐标系到相机坐标系的变换了(知道了相机位置,求平移到原点的矩原创 2022-05-20 17:47:36 · 1527 阅读 · 0 评论 -
【OpenGL】笔记七、MVP矩阵的使用
首先创建一个模型矩阵,将其绕着x轴旋转,使它看起来像放在地上一样(将该顶点坐标变换到世界坐标):glm::mat4 model = glm::mat4(1.0f);model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));接下来我们需要创建一个观察矩阵,我们想要在场景里面稍微往后移动,以使得物体变成可见的:glm::mat4 view = glm::mat4(1.0f);// 注意,我们将矩阵向我们原创 2022-05-19 11:35:08 · 1738 阅读 · 2 评论 -
【OpenGL】笔记六、GLM配置
1. 流程GLM是OpenGL Mathematics的缩写,它是一个只有头文件的库,有了它,我们完成各种矩阵和向量操作就变得方便了许多,下载完 文件 后将它加入include目录即可现在看看怎么来使用这个库:首先是添加头文件:#include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>#include <glm/gtc/type_ptr.hpp>然后我们创建一个(1,0,0)的初始坐标ve原创 2022-05-19 01:07:54 · 4598 阅读 · 0 评论 -
【OpenGL】笔记五、纹理
1. 流程1.1 单个纹理纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来添加物体的细节,为了能够使用纹理图片,我们需要一个叫做stb_image.h的头文件库来加载不同格式的图片作为纹理,下载在文末给出,得到该头文件后,加入项目,并且新建一个叫做stb_image_wrap.cpp的文件,写入:#define STB_IMAGE_IMPLEMENTATION#include "stb_image.h"然后在主程序里加入头文件:#include "stb_image.h"这样就可原创 2022-05-18 05:48:12 · 1025 阅读 · 0 评论 -
【OpenGL】笔记四、自己的着色器类
流程因为每次新建项目时,我们都要再定义一次着色器,显得很麻烦,更方便的方法就是自己定义一个着色器类,每次建立新着色器对象时就自动完成从硬盘读取源码、编译,链接等过程。shader_s.h这里给出了着色器类的头文件,头两行的预处理指令会告知你的编译器只在它没被包含过的情况下才包含和编译这个头文件,即使多个文件都包含了这个着色器头文件。它是用来防止链接冲突的。接下来运用c++的ifstream来读取硬盘里的着色器源代码,着色器构造函数的结果就是直接保存最后生成的着色器程序ID,调用USE方法就可以使用了原创 2022-05-17 16:35:13 · 431 阅读 · 0 评论 -
【OpenGL】笔记三、着色器
1. 流程1.1 图形颜色随时间变化接上回生成矩形,本次我们要对矩形颜色做一定改变,让它在渲染过程中随时间而变化,但是目前来说我们好像无法在着色器源码中获取时间,那么剩下的方法应该就是在程序中对片段着色器的颜色进行修改了首先,为了在程序中修改着色器的输出,我们需要在片段着色器内定义一个全局变量(可被程序访问),在GLSL中被称为uniform类,将这个变量的值赋给片段着色器的输出变量,如下:#include <glad/glad.h>#include <GLFW/glfw3.h&原创 2022-05-17 05:48:00 · 543 阅读 · 0 评论 -
【OpenGL】笔记二、你好三角形
1. 流程对比于生成窗口,本次生成三角形所需的知识点多了顶点着色器和片段着色器,着色器程序与VAO、VBO、EBO,在此之前,先要了解一下OpenGL的图形渲染管线1.1 OpenGL图形渲染管线图形渲染管线的第一个部分是顶点着色器(Vertex Shader),它把一个单独的顶点作为输入。顶点着色器主要的目的是把3D坐标转为另一种3D坐标,同时顶点着色器允许我们对顶点属性进行一些基本处理。图元装配(Primitive Assembly)阶段将顶点着色器输出的所有顶点作为输入(如果是GL_POIN原创 2022-05-16 22:12:47 · 486 阅读 · 0 评论 -
【OpenGL】笔记一、你好窗口
#include <glad/glad.h>#include <GLFW/glfw3.h>#include <iostream>void framebuffer_size_callback(GLFWwindow* window, int width, int height);void processInput(GLFWwindow* window);// settingsconst unsigned int SCR_WIDTH = 800;const原创 2022-05-16 19:01:13 · 415 阅读 · 0 评论 -
【OpenGL】VS2019三步完成库配置
一、下载配置文件OpenGL配置文件二、项目配置打开VS2019,创建C++控制台项目解压附件至项目文件夹打开项目配置,附加包含目录里选为刚刚添加的include文件夹的路径常规的附加库目录选为刚刚添加的lib-vc2019文件夹的路径输入的附加依赖项直接填入glfw3.lib最后项目内右键添加源文件glad.c三、运行尝试粘贴以下代码运行:#include <glad/glad.h>#include <GLFW/glfw3.h>#includ原创 2022-05-14 15:30:10 · 1266 阅读 · 0 评论