
OpenGL
文章平均质量分 52
OpenGL
ZEKEGU1997
温故而知新,多看多写
展开
-
常见渲染管线整理
最常见的渲染,所谓的前向渲染,就是将物件串成一个队列,一个接一个的进行渲染。可以以光源为主循环也可以物体为主循环。缺点是当物体或光源较多时效率低下,且会有比较多的重复计算。将渲染分为两个阶段,第一阶段处理光照计算需要的数据,并将他们储存到GBuffer中,这些数据包括片元位置、漫反射贴图,法线贴图,镜面反射强度图等。其优点是物体和光源较多时效率高,缺点是需要的带宽较大,不适用MSAA,难以处理透明混合。由于带宽限制,移动端很难实现常规的延迟渲染,一种解决办法是将屏幕划分为多个区域,分别进行渲染。将屏幕空间划原创 2022-06-08 16:25:26 · 441 阅读 · 0 评论 -
管线中的坐标变换
1原创 2022-06-07 21:40:47 · 228 阅读 · 0 评论 -
反走样/抗锯齿技术
走样的根本原因,是用离散的像素点无法正确表达连续的几何体,导致边缘的像素不平滑。不过当像素越多分辨率越高时,走样现象就越不明显。所以反走样的第一种办法就是在渲染计算时使用更高的分辨率,这种方法被称为超采样抗锯齿(Super Sample Anti-aliasing, SSAA),但是这种方法显然性能开销很大。如左图所示,通常判断一个点是否属于某个三角面片,是根据像素中心点是否被遮盖,这个中心点也被称为采样点。增加采样点的个数,并根据被覆盖的采样点个数对颜色进行平均,如右图所示,这就是MSAA方法。MSAA要原创 2022-06-07 20:51:28 · 656 阅读 · 0 评论 -
四元数简介
图形学中的旋转主要分两种:欧拉旋转和轴角式旋转。欧拉曾经证明过,任何旋转都可以表示为物体绕自身三轴的旋转。所以欧拉旋转就是物体以特定的顺序,依次绕自身的三轴进行的旋转。但是这种旋转在绕第二个轴旋转90°时会失去一个自由度,导致万向节锁的现象。轴角式,顾名思义是绕某个特定轴旋转某个角度,通过四元数和Rodriguez公式都可以表示这一旋转过程。复数可以表示为a+bi,其中i²=-1,而复数的相乘与矩阵相乘可以看做是等价的。四元数与复数相似但不是复数。四元数的定义a+bi+cj+dk,其中i²=j²=k²=ij原创 2022-06-07 19:49:15 · 554 阅读 · 0 评论 -
learnOpenGL 笔记 1.1
1.早期的OpenGL使用立即渲染模式(Immediate mode,也就是固定渲染管线),这个模式下绘制图形很方便。OpenGL的大多数功能都被库隐藏起来,立即渲染模式确实容易使用和理解,但是效率太低。当使用OpenGL的核心模式时,OpenGL迫使我们使用现代的函数。当我们试图使用一个已废弃的函数时,OpenGL会抛出一个错误并终止绘图。现代函数有一些难度,然而提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程。...转载 2020-07-04 18:06:43 · 162 阅读 · 0 评论 -
learn opengl 笔记 1.2
1、GLFWGLFW是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口。它允许用户创建OpenGL上下文,定义窗口参数以及处理用户输入。2、GLAD由于OpenGL驱动版本众多,它大多数函数的位置都无法在编译时确定下来,需要在运行时查询。所以任务就落在了开发者身上,开发者需要在运行时获取函数地址并将其保存在一个函数指针中供以后使用。取得地址的方法因平台而异,代码非常复杂,而且很繁琐,我们需要对每个可能使用的函数都要重复这个过程。幸运的是,有些库能简化此过程,其中GLAD是目转载 2020-08-01 16:55:09 · 113 阅读 · 0 评论 -
learnOpenGL 笔记1.3 创建窗口
1、以下几个函数是初始化并配置GLFW,我们将主版本号(Major)和次版本号(Minor)都设为3。我们同样明确告诉GLFW我们使用的是核心模式(Core-profile)。 glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFI转载 2020-08-02 15:50:58 · 199 阅读 · 0 评论 -
learnOpenGL 笔记 1.4.1三角形
简单的图形渲染管线图形渲染管线接受一组3D坐标,然后把它们转变为你屏幕上的有色2D像素输出。图形渲染管线可以被划分为几个阶段,每个阶段将会把前一个阶段的输出作为输入。所有这些阶段都是高度专门化的(它们都有一个特定的函数),并且很容易并行执行。正是由于它们具有并行执行的特性,当今大多数显卡都有成千上万的小处理核心,它们在GPU上为每一个(渲染管线)阶段运行各自的小程序,从而在图形渲染管线中快速处理你的数据。这些小程序叫做着色器(Shader)。图形渲染管线的第一个部分是顶点着色器(Vertex Sh.转载 2020-08-03 14:47:31 · 135 阅读 · 0 评论 -
learnOpenGL 笔记 1.4.2 三角形
编写shader源码每个着色器都起始于一个版本声明,同时明确表示我们使用核心模式。以下是顶点着色器的源码。第二行创建一个三维向量变量,通过layout (location = 0)设定了输入变量的位置值,in 是说明这个变量是输入的,没有实际作用。我们把位置数据赋值给预定义的gl_Position变量,它在幕后是vec4类型的。在main函数的最后,我们将gl_Position设置的值会成为该顶点着色器的输出。由于我们的输入是一个3分量的向量,我们必须把它转换为4分量的。我们可以把vec3的数据.转载 2020-08-03 17:09:54 · 172 阅读 · 0 评论 -
learnOpenGL 笔记1.4.3EBO
假如我们要绘制两个共边的三角形,实际上涉及的顶点是4个,然而如果我们用VBO和VAO来绘制,就必须输入6组数据,因为不允许重复使用。这样就造成了浪费。为了解决这个问题,我们引入EBO索引缓冲对象(Element Buffer Object)。我们要输入顶点数据和索引float vertices[] = { 0.5f, 0.5f, 0.0f, // 右上角 0.5f, -0.5f, 0.0f, // 右下角 -0.5f, -0.5f, 0.0f, // 左下角原创 2020-08-04 17:04:53 · 183 阅读 · 0 评论 -
learOpenGL 1.5.1 着色器
shader 的典型结构#version version_numberin type in_variable_name;in type in_variable_name;out type out_variable_name;uniform type uniform_name;int main(){ // 处理输入并进行一些图形操作 ... // 输出处理过的结果到输出变量 out_variable_name = weird_stuff_we_processed;}.转载 2020-08-07 17:08:30 · 159 阅读 · 0 评论 -
learnOpenGL 1.5.2 渐变三角形
在顶点数据中,不仅可以添加顶点坐标,还可以添加颜色float vertices[] = { // 位置 // 颜色 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下 -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部};由于数据的改变,对应的VAO也就要发生变化。/转载 2020-08-12 15:52:37 · 469 阅读 · 0 评论 -
learnOpenGL 1.5.3 文件读取
我们会把着色器类全部放在在头文件里,主要是为了学习用途,当然也方便移植。#ifndef SHADER_H#define SHADER_H#include <glad/glad.h>; // 包含glad来获取所有的必须OpenGL头文件#include <string>#include <fstream>#include <sstream>#include <iostream>class Shader{public:转载 2020-08-21 17:25:04 · 273 阅读 · 0 评论 -
learnOpenGL 1.6.1 纹理
纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来添加物体的细节。因为我们可以在一张图片上插入非常多的细节,这样就可以让物体非常精细而不用指定额外的顶点。为了能够把纹理映射(Map)到三角形上,我们需要指定三角形的每个顶点各自对应纹理的哪个部分。这样每个顶点就会关联着一个纹理坐标(Texture Coordinate),用来标明该从纹理图像的哪个部分采样(译注:采集片段颜色)。之后在图形的其它片段上进行片段插值(Fragment Interpolation)。纹理坐标在x和y轴上,范围为0到1之转载 2020-08-22 23:22:25 · 293 阅读 · 0 评论 -
learnOpenGL 1.6.2
加载贴图我们可以用stb_image.h来加载我们需要的图片,在下载好源文件后,我们将它假如工程中,输入以下#define STB_IMAGE_IMPLEMENTATION#include "stb_image.h"要使用stb_image.h加载图片,我们需要使用它的stbi_load函数:int width, height, nrChannels;unsigned char *data = stbi_load("container.jpg", &width, &height,转载 2020-08-23 23:33:01 · 129 阅读 · 0 评论 -
learnOpenGL 1.7变换
“数学”基础向量与标量运算OpenGL中向量可以和标量相加减,方法是在向量的所有分量上加减标量。而乘除操作与数学上相同。向量与向量加减向量取模向量点乘、叉乘矩阵与标量运算OpenGL中矩阵可以和标量相加减,方法同上。矩阵之间运算矩阵与向量相乘单位矩阵...转载 2020-08-24 21:48:46 · 213 阅读 · 0 评论 -
learnOpenGL 1.8 坐标系统
一个物体从被我们创建到在屏幕上显示出来,需要经过多个坐标空间。我们的顶点坐标起始于局部空间(Local Space),在这里它称为局部坐标(Local Coordinate),它在之后会变为世界坐标(World Coordinate),观察坐标(View Coordinate),裁剪坐标(Clip Coordinate),并最后以屏幕坐标(Screen Coordinate)的形式结束。为了将坐标从一个坐标系变换到另一个坐标系,我们需要用到几个变换矩阵,最重要的几个分别是**模型(Model)、观察(V转载 2020-08-25 21:46:16 · 258 阅读 · 0 评论 -
learnOpenGL 1.9 摄像机
要定义一个摄像机,我们需要它在世界空间中的位置、观察的方向、一个指向它右测的向量以及一个指向它上方的向量。细心的读者可能已经注意到我们实际上创建了一个三个单位轴相互垂直的、以摄像机的位置为原点的坐标系。摄像机位置我们把摄像机位置设置为上一节中的那个相同的位置:glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);摄像机方向这里指的是摄像机指向哪个方向。现在我们让摄像机指向场景原点:(0, 0, 0)。用场景原点向量减去摄像机位置向量的结果就是转载 2020-08-27 21:06:30 · 256 阅读 · 0 评论 -
learnOpenGL 2.1基础光照
Phong Lighting Model冯氏光照模型的主要结构由3个分量组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。环境光把环境光照添加到场景里非常简单。我们用光的颜色乘以一个很小的常量环境因子,再乘以物体的颜色,然后将最终结果作为片段的颜色:float ambientStrength = 0.1;vec3 ambient = ambientStrength * lightColor;漫反射光图左上方有一个光源,它所发出的光线落在物体的一个片段上。原创 2020-09-07 21:42:43 · 240 阅读 · 0 评论 -
learnOpenGL 2.2 材质
设置材质在着色器中建立结构体如下#version 330 corestruct Material { vec3 ambient; vec3 diffuse; vec3 specular; float shininess;}; uniform Material material;在渲染中设置材质的实际值,环境光反射和漫反射都和物体本身颜色有关,因此设置成物体的颜色。镜面反射只与光源颜色有关,所以设置成单位向量,再乘以镜面反射强度0.5lightingshader原创 2020-09-08 19:54:04 · 132 阅读 · 0 评论 -
learnOpenGL 2.3 光照贴图
漫反射贴图将材质结构体中的漫反射设置成贴图struct Material { sampler2D diffuse; vec3 specular; float shininess;}; ...in vec2 TexCoords;同时修改漫反射光照的公式,注意这里diffuse是一个vec3,而texture输出的是vec4,所以要在后面加上.rgb。vec3 diffuse = light.diffuse * diff * texture(materia原创 2020-09-09 21:51:55 · 204 阅读 · 0 评论 -
learnOpenGL 2.4 投光物
多个箱子创建多个箱子的过程与第一章中类似,下面是主程序中的代码 glm::vec3 cubePositions[] = { ...}; glBindVertexArray(cubeVAO); for (int i = 0; i < 10; i++) { glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, cubePositions[i]原创 2020-09-10 21:42:22 · 143 阅读 · 0 评论 -
learnOpenGL 2.5 多光源
之前我们学习了多种光源,也介绍了他们的计算方法。当画面中有多个光源时,为了方面管理和计算光照,我们将它们分别建立结构体和计算函数。struct dirLight{ vec3 direction; vec3 ambient; vec3 diffuse; vec3 specular; float constant; float linear; float quadratic;};struct pointLight{ vec3 position; vec3 ambient; ve原创 2020-09-15 21:17:07 · 118 阅读 · 0 评论 -
learnOpenGL 3.1 模型
这一节我们要读入外部的3D模型,为此我们要用到Assimp库,还需要创建一个mesh类和model类。Assimp首先我们要了解Assimp的数据结构assimp将一个模型加载到一个scene对象中,这个对象下存有根节点,mesh数组,material数组。场景的Root node(根节点)可能包含子节点,它会有一系列指向场景对象中mMeshes数组中储存的网格数据的索引。Scene下的mMeshes数组储存了真正的Mesh对象,节点中的mMeshes数组保存的只是场景中网格数组的索引。一个M原创 2020-09-22 18:48:11 · 239 阅读 · 0 评论 -
learnOpenGL 4.1 深度测试
深度测试函数OpenGL允许我们修改深度测试中使用的比较运算符。我们可以调用glDepthFunc函数来设置比较运算符。默认情况下,我们使用LESS。glDepthFunc(GL_LESS);GL_ALWAYS 永远通过深度测试GL_NEVER 永远不通过深度测试GL_LESS 在片段深度值小于缓冲的深度值时通过测试GL_EQUAL 在片段深度值等于缓冲区的深度值时通过测试GL_LEQUAL 在片段深度值小于等于缓冲区的深度值时通过测试GL_GREATER 在片段深度值大于缓冲原创 2020-09-22 20:25:44 · 323 阅读 · 0 评论 -
learnOpenGL 学习拾遗纠错
fragment (片段/片元)的具体含义OpenGL中的一个片段是OpenGL渲染一个像素所需的所有数据。非学无以致疑,非问无以广识原创 2020-09-23 21:03:25 · 118 阅读 · 0 评论 -
learnOpenGL 4.2 模板测试
除了深度测试,OpenGL还有一种较为自由的测试,称为模板测试stencil。模板函数首先,和深度测试一样,我们要先启用它,同时需要在渲染循环中清除它的缓存glEnable(GL_STENCIL_TEST);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);除此以外,我们还可以使用以下函数开启和禁用模板值的写入glStencilMask(0xFF); // 每一位写入模板缓冲时都保持原样gl原创 2020-09-24 19:22:46 · 195 阅读 · 0 评论 -
learnOpenGL 4.3 透明混合
在实际场景中,我们会遇到一些透明的物体,如何显示透明物体是一个问题。RGBA值中A即为透明度,当A非常小,接近或等于零时,我们可以直接在fragment shader中将这些部分舍弃。void main(){ vec4 texColor = texture(texture1, TexCoords); if(texColor.a < 0.1) discard; FragColor = texColor;}注意,当采样纹理的边原创 2020-09-25 16:34:12 · 386 阅读 · 0 评论 -
learnOpenGL 4.4 面剔除
在实际显示中,我们一般只能看到一个物体少于等于50%的部分,比如一个立方体,我们最多看到三个面。如此一来,我们只绘制面向我们的面就可以大大提升渲染效率。这就是所谓的面剔除。glEnable(GL_CULL_FACE);原理面剔除的原理主要是,通过构成三角形的顶点的顺序判断正反。如果在正面三个点为逆时针顺序,则在反面看它们成顺时针。通过下面这个函数我们可以设定朝哪个方向为正,CCW为逆时针,CW为顺时针。默认为逆时针。glFrontFace(GL_CCW);这样设置以后,从相机角度看为顺原创 2020-09-25 19:22:33 · 183 阅读 · 0 评论 -
learnOpenGL 4.5 帧缓冲
到目前为止,我们已经使用了很多屏幕缓冲了:用于写入颜色值的颜色缓冲、用于写入深度信息的深度缓冲和允许我们根据一些条件丢弃特定片段的模板缓冲。这些缓冲结合起来叫做帧缓冲(Framebuffer)。实际上我们平时做的一些操作都是在默认帧缓冲中的渲染缓冲(Renderbuffer)中进行的,这里默认的帧缓冲是在创建窗口的时候GLFW生成和配置的。创建帧缓冲第一步创建和绑定与其他缓冲类似。 unsigned int framebuffer; glGenFramebuffers(1, &原创 2020-09-26 21:29:08 · 237 阅读 · 0 评论 -
learnOpenGL 4.6 立方纹理
立方纹理是一种特殊纹理,它利用从立方体中心出发的方向向量进行纹理的采样,如下图:方向向量的大小并不重要,只要提供了方向,OpenGL就会获取方向向量(最终)所击中的纹素,并返回对应的采样纹理值。这样子,只要立方体的中心位于原点,我们就能使用立方体的实际位置向量来对立方体贴图进行采样了。于是乎,我们要做的就是要使面与相应的贴图对应。因为立方体贴图包含有6个纹理,每个面一个,我们需要调用glTexImage2D函数6次,参数和之前教程中很类似。但这一次我们将纹理目标(target)参数设置为立方体原创 2020-09-27 20:32:01 · 285 阅读 · 0 评论 -
learnOpenGL 4.7 高级数据
分批顶点通常我们使用交错布局处理顶点数据,与交错布局123123123123不同,我们也可以采用分批(Batched)的方式111122223333。我们可以先用glBufferData函数预留一块内存,如果我们将它的data参数设置为NULL,那么这个函数将只会分配内存,但不进行填充。然后使用glBufferSubData函数填充缓存。一个缓冲目标、一个偏移量、数据的大小和数据本身作为它的参数。要注意的是,缓冲需要有足够的已分配内存,所以对一个缓冲调用glBufferSubData之前必须要先调用原创 2020-10-09 19:59:11 · 236 阅读 · 0 评论 -
learnOpenGL 4.8 高级GLSL
内建变量1、顶点着色器变量gl_Position它是顶点着色器的裁剪空间输出位置向量gl_PointSize我们能够选用的其中一个图元是GL_POINTS,如果使用它的话,每一个顶点都是一个图元,都会被渲染为一个点。我们可以通过OpenGL的glPointSize函数来设置渲染出来的点的大小glEnable(GL_PROGRAM_POINT_SIZE);gl_VertexID整型变量gl_VertexID储存了正在绘制顶点的当前ID。当(使用glDrawElements)进行索引渲染的时候转载 2020-10-09 21:26:41 · 195 阅读 · 0 评论 -
learnOpenGL 4.8.2 uniform缓冲
在多个shader中可能使用相同的uniform变量,比如projection和view矩阵,此时多次填入数据较为麻烦。利用uniform缓冲就可实现多个shader共用uniform数据。首先在shader程序中写好uniform接口块注意接口块最后是有分号的#version 330 corelayout (location = 0) in vec3 aPos;layout (std140) uniform Matrices{ mat4 projection; mat4 vi原创 2020-10-10 20:40:00 · 276 阅读 · 0 评论 -
learnOpenGL 4.9 几何着色器
在顶点着色器和片元着色器之间还有一个可选的几何着色器。几何着色器的一大特点,是它可以输入和输出图元(点,线,三角形)。以下是具体可以输入的类型points:绘制GL_POINTS图元时(1)。lines:绘制GL_LINES或GL_LINE_STRIP时(2)lines_adjacency:GL_LINES_ADJACENCY或GL_LINE_STRIP_ADJACENCY(4)triangles:GL_TRIANGLES、GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN(3)原创 2020-10-13 20:52:42 · 144 阅读 · 0 评论 -
learnOpenGL 4.10 实例化
如果画面中有大量的重复模型,使用glDrawArrays或glDrawElements函数效率是比较低的,这种时候就要用到实例化。比如我们绘制在画面中重复绘制一个彩色矩形。在重复次数少于一百次时,我们只需要在顶点着色器中传入一个uniform形式的偏移量数组,数组下标为内建变量gl_InstanceID。gl_InstanceID会从0开始,在每个实例被渲染时递增1,对应每个渲染的实例。然后在gl_Position上每次加入对应的偏移就可以了。//顶点着色器代码#version 330 core原创 2020-10-14 17:03:26 · 200 阅读 · 0 评论 -
learnOpenGL 5.1 Blinn-Phong着色模型
在phong模型中,高光区域有明显的断层,这是因为镜面反射中,视线方向与反射方向角度大于90度,镜面光为0,实际上在较为粗糙的表面,镜面光仍有影响。在此我们引入一种改进模型:Blinn-Phong着色模型它唯一的变化是在计算镜面反射时加入了一个半程向量,如图,即光线与视线夹角一半方向上的一个单位向量。当半程向量与法线向量越接近时,镜面光分量就越大。因此计算过程也变成了这样:vec3 halfwayDir = normalize(lightDir + viewDir);float spec =原创 2020-10-15 15:56:52 · 270 阅读 · 0 评论 -
learnOpenGL 5.2 阴影贴图
阴影贴图的原理较为简单,就是以光的方向为视角生成一副深度贴图,这幅图中能看到的部分就是光能照到的部分,所以在计算阴影时只要将片段深度与这幅深度贴图进行对比,深度比它大的片段即在阴影中。实际实现的步骤如下:创建画面元素(箱子,地板等)的VBO,VAO,光照矩阵,传入深度贴图shader注意,因为本节考虑定向光,不存在透视,所以使用正交投影矩阵GLfloat near_plane = 1.0f, far_plane = 7.5f;glm::mat4 lightProjection = glm::o原创 2020-10-22 17:18:10 · 275 阅读 · 0 评论 -
learnOpenGL 5.3 法线贴图
要理解和应用法线贴图,首先须明白切线空间,这里贴一个知乎的文章,里面对切线空间的讲解非常细致切线空间(Tangent Space)完全解析简单来说,切线空间就是把某个三角面片放到正对屏幕的位置,也就是其法线与屏幕空间z轴平行。其中最重要的一个公式该公式描述的数学意义是,表示一个点在uv空间与三维空间的映射关系,其中TB作为基矢,以uv空间中的u和v的增长作为控制参数。假设三角形中存在一点P,则向量AP=u(p)*T+v(p)*B,只要知道P点的uv坐标值,即可得到P点的三维坐标值,反之亦然。通过这个原创 2020-11-08 15:59:49 · 260 阅读 · 0 评论 -
learnOpenGL 5.4 视差贴图
高度贴图视差贴图要用到一副利用R通道储存片元高度的高度贴图,模拟在看到凹凸面的视差。如图所示,如果这是一个3D的模型,我们沿黄线方向看到的应当是B点,如果是平面则会看到A点。按着这个逻辑,我们只要在贴图的A点显示B的内容,就可以假乱真,用平面贴图达到3D的效果。所以,我们要做的工作,就是计算出B点,用它替换A点。顺便一提,视差贴图一般与法线贴图一同使用,相辅相成。视差计算深度比高度更容易模拟,所以我们通常使用深度贴图取反来代替高度图。寻找B点的过程如图所示,从T0点出发,将深度分成N份逐原创 2020-11-08 21:36:33 · 244 阅读 · 0 评论