[读书笔记] OpenGL学习笔记-十-深度测试
深度测试
深度测试用于解决像素的遮挡问题,即:哪个像素应该被显示在屏vanishing.cc20040422
幕上.
深度测试原理如下:
用一张纹理来存储信息
将每个片段与深度缓冲中的值信息进行深度测试,如果测试通过,则更新深度缓冲中的值信息,否则丢弃该片段.
启用深度测试
在OpenGL中,使用以下代码来启用深度测试:
glEnable(GL_DEPTH_TEST);
为了防止渲染帧使用上一帧的深度缓冲,你应该在每个渲染迭代之前清除深度缓冲:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
禁用写入深度缓冲
有时你可能需要禁止写入深度缓冲,例如,当你只需要渲染一个透明物体时,你可能不希望它影响深度测试.
在OpenGL中,使用以下代码来禁止写入深度缓冲:
glDepthMask(GL_FALSE);
深度测试函数
深度测试函数用于控制OpenGL如何判断是否通过深度测试.
有以下几种深度测试函数:
GL_ALWAYS: 总是通过测试
GL_NEVER: 总是丢弃片段
GL_LESS: 如果片段的深度值小于深度缓冲中 ...
[读书笔记] OpenGL学习笔记(八)-光照
光照
在上一节我们实现了材质.
材质用于表征一个表面的各种属性.
但是相同的材质在不同光照的情况下显现出的结果不同.例如:一件白衣服在不同灯光下显现的颜色不同.
所以最终像素点上的颜色应该由光照和材质共同决定.
光照模型有很多种,常见的有Phong光照模型,Blinn-Phong光照模型.
我们在这一节实现一个Blinn-Phong光照模型.
Light类
首先我们定义一个Light类,用于描述光源.
class Light{public: glm::vec3 position; glm::vec3 color; float radiant;public: Light(){ position = glm::vec3(0.0f, 0.0f, 0.0f); color = glm::vec3(1.0f, 1.0f, 1.0f); radiant = 10.0f; } Light(glm::vec3 pos, glm::vec3 col, float rad) { ...
[读书笔记] OpenGL学习笔记(七)-3d模型
Assimp库
3d资产的格式种类非常之多,文件的细节与标准也千差万别,我们需要一个专门的库来为我们处理这些资产文件.Assimp库就是这样一个库,它可以读取各种3d资产文件,以便我们加载3d模型.
你可以点击这里访问Assimp库的GitHub页面,下载最新版本的Assimp库.
由于Assimp库实际上较为庞大,考虑到编译Assimp库需要的时间较长,我们选用Assimp库的预编译版本.你可以点击这里下载
我们将库安装在我们的3rd目录下.然后更改我们的CMakeLists.txt文件,添加以下内容:
include_directories(${CMAKE_SOURCE_DIR}/3rd/assimp/include)link_libraries(${CMAKE_SOURCE_DIR}/3rd/assimp/lib/x64)
别忘了在Source中的CMakeLists.txt中链接Assimp库:
target_link_libraries(BickRenderer ${CMAKE_SOURCE_DIR}/3rd/as ...
[读书笔记] OpenGL学习笔记(六)-坐标系统
概述
本节核心就是一张图:
局部空间(Local Space)
局部空间是物体所在的空间,比如在DCC软件中创建的模型所在的空间.
世界空间(World Space)
世界空间是全局坐标系,为世界中的所有物体提供一个坐标系.
观察空间(View Space)
观察空间是摄像机所在的空间,它是相机的视角,是摄像机看到的世界的局部空间.
裁剪空间(Clip Space)
在我们的着色器中,我们希望坐标都能落在一个特定的范围,否则在着色器运算中会增加很多复杂的步骤,因此需要对观察空间进行裁剪变换到NDC空间.
应用
glm库已经为我们实现好了计算这些变换矩阵的方法:
glm::mat4 model = glm::mat4(1.0f); // 模型矩阵glm::mat4 view = glm::mat4(1.0f); // 观察矩阵glm::mat4 projection = glm::mat4(1.0f); // 投影矩阵model = glm::translate(model, glm::vec3(0.0f, 0.0f, -3.0f)); // 平移view = glm:: ...
[读书笔记] OpenGL学习笔记(五)--3D数学
向量
向量相乘
点乘:
叉乘:
注意,叉乘的方向取决于坐标系是左手系还是右手系.
常见软件使用坐标系如下:
OpenGL : 右手系
DirectX: 左手系
Unreal : 左手系
Unity : 左手系
glm : 右手系
矩阵
矩阵乘法
值得注意的是,在矩阵乘法中,乘法交换律是不满足的.
又由于各种平台对一维向量的表示不同(行向量还是列向量),所以在矩阵乘法中顺序尤为重要.
比如MVP矩阵,在OpenGL中使用的是列向量,所以MVP矩阵的乘法顺序是P * V * M * v.
而在DirectX中使用的是行向量,所以MVP矩阵的乘法顺序是v * M * v * P .
以下是常见软件向量表示方法:
OpenGL : 列向量
Unity : 列向量
DirectX: 行向量
glm : 列向量
矩阵与向量相乘
我们的模型顶点一般是一个三维向量,我们可以利用举证对这个向量进行变换,比如平移,旋转,缩放等操作.
缩放矩阵
注意,第四个缩放向量仍然是1,因为在3D空间中缩放w分量是无意义的.w分量另有其他用途,在后 ...
[读书笔记] OpenGL学习笔记(四)--纹理
本节目录
纹理基础
纹理技术
应用纹理
纹理类
纹理基础
图片实际上就是一张纹理,为了表现丰富的计算机世界,纹理是必不可少的.
首先需要解决的是如何将一张图片映射到我们的计算机世界中.我们使用x和y轴的两个0-1的数来表示纹理的坐标,即uv坐标
对于我们的三角形,我们可以为每个顶点指定uv坐标,这样就可以和纹理对应起来了.
纹理技术
Wrapping
当纹理z轴坐标超过1时,我们需要对纹理坐标进行wrap,也就是如何处理uv大于1的情况.
OpenGL提供了四种选择:
GL_REPEAT: 重复纹理
GL_MIRRORED_REPEAT: 镜像重复纹理
GL_CLAMP_TO_EDGE: 贴边纹理
GL_CLAMP_TO_BORDER: 边缘纹理
效果如下:
MipMap
想象一下,当镜头拉远,一个很远的物体只占屏幕的4个像素时,如果还让其在一张512x512的纹理上采样,想想都不太高效.
所以可以生成各种分辨率的纹理,然后根据距离摄像机的远近选择合适的纹理.
这种方法带来的开销也非常小.
纹理过滤
纹理是有分辨率的,但uv坐标"没有".这就 ...
[读书笔记] OpenGL学习笔记(三)--Shader
本节内容
Shader基础
Shader类
什么是Shader
Shader是运行在GPU上的程序.编写Shader程序使用的是Shading Language.主流的Shading Language有GLSL,HLSL,CG等.其中OpenGL使用的是GLSL.
Shader基本结构
一个典型的shader有以下结构
#version version_numberin type in_variable_name;in type in_variable_name;out type out_variable_name;uniform type uniform_name;void main(){ // 处理输入并进行一些图形操作 ... // 输出处理过的结果到输出变量 out_variable_name = weird_stuff_we_processed;}
Shader类
对于创建和使用一个shader程序,我们有以下几个固定的步骤.
unsigned int vertexShader, fragmentShader;const char *v ...
[读书笔记] OpenGl学习笔记(二)--Triangle
本节内容
第一个三角形
Hello Triangle
在本章之前首先需要明确以下几个名词
VAO(Vertex Array Object): 顶点数组对象,用于存储顶点数据
VBO(Vertex Buffer Object): 顶点缓冲对象,用于存储顶点数据
EBO(Element Buffer Object): 元素缓冲对象,用于存储索引数据
IBO(Index Buffer Object): 索引缓冲对象,用于存储索引数据
OpenGL 渲染管线
顶点着色器: 将顶点转换到NDC(Normalized Device Coordinates)
几何着色器: 处理顶点的几何变换
图元装配: 将顶点组成图元
光栅化: 将图元转换为像素
片段着色器: 计算每个像素的颜色
测试混合: 融合颜色
输入顶点数据
由于我们想要渲染一个三角形,所以首先需要指定三个顶点.
float vertices[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f};
这里将 ...
[读书笔记] OpenGl学习笔记(一)--环境搭建
本节内容
OpenGl简要介绍
创建第一个窗口
OpenGl简要介绍
什么是OpenGl
OpenGl是一个规范,虽然一般被认为是一个API,但其本身并不负责实现.
OpenGl严格规定每个函数如何执行以及输出值,内部具体实现则由OpenGl库开发者完成.而其开发者一般为显卡厂商.
核心模式 && 立即渲染模式
立即渲染模式被时代抛弃
核心模式更自由,是主流
扩展(Extension)
为了开发者不必等待新的规范发布,通过检查显卡是否支持某些功能,来实现更好的优化和别的特性
状态机
OpenGL本身是一个大状态机,根据自身的状态来执行操作
对象
对象是一个结构体
Hello World,创建第一个窗口
首先需要:
创建OpenGl上下文
创建窗口
由于这两个步骤在不同平台上都不一样,并且OpenGL有意将其抽象出去,所以需要我们自己进行处理.当然,这一步已经有许多成熟的开源库为我们处理好了.
GLFW
GLFW是一个c语言库,它可以创建OpenGL上下文,定义窗口,处理输入
GLAD
由于OpenGL只是一个规范,具体实现需要驱动开发者根据显 ...
