模型加载
使用 Assimp 导入模型。
Model.hpp
1 | /* |
Model.cpp
1 |
|
使用 Assimp 导入模型。
1 | /* |
1 | #pragma mark - Public |
网格(Mesh):代表的是单个的可绘制实体。
网格(Mesh)最少需要的数据有:
1 | #include <glad/glad.h> |
1 | #pragma mark - Public |
3D 模型
通常是在 Blender、3DS Max 或者 Maya 3D建模工具(3D Modeling Tool)中制作完成;并使用 UV映射(uv-mapping) 的手段来应用贴图。这些工具将会在导出到模型文件的时候自动生成所有的 顶点坐标
、顶点法线
以及 纹理坐标
。
模型的文件格式有很多种,每一种都会以它们自己的方式来导出模型数据。例如:
模型颜色
和 漫反射/镜面光贴图
。Assimp(Open Asset Import Library):能够导入很多种不同的模型文件格式(并也能够导出部分的格式),并将所有的模型数据加载至 Assimp
的通用数据结构中。一个简化的 Assimp
数据结构模型如图:
Scene
对象中。Scene
对象也包含了场景根节点的引用。Root node
(根节点)可能包含子节点(和其它的节点一样),包含了一系列指向场景对象中mMeshes
数组中储存的网格(组合模型的每个单独的形状)数据的索引。Scene
下的mMeshes
数组储存了真正的Mesh对象,节点中的mMeshes
数组保存的只是场景中网格数组的索引。Mesh
对象本身包含了渲染所需要的所有相关数据,像是顶点位置、法向量、纹理坐标、面(Face)**和物体的材质**。一个网格是在OpenGL中绘制物体所需的最小单位(顶点数据、索引和材质属性);一个模型(通常)会包括多个网格。
GLSL
中的函数和C
函数很相似,它有一个函数名、一个返回值类型,如果函数不是在main
函数之前声明的,则必须在代码文件顶部声明一个原型。
当在场景中使用多个光源时,由于每一个光源都会对片段产生一定的影响,所以需要一个单独的颜色向量,将每个光源对片段的影响累加,以得出最终的片段颜色。大体的结构如下:
1 | out vec4 FragColor; /* 片段颜色 */ |
红绿蓝(RGB)
分量的组合描绘大部分真实颜色的向量。(一个物体的颜色实际上是该物体所不能吸收的反射颜色分量。)环境光
,漫反射
和 镜面光
分量的值来估计真实光照的模型。3x3
矩阵,或者说是没有平移的模型(或者模型-观察)矩阵。它也被以某种方式修改(逆转置),从而在应用非统一缩放时,保持法向量朝向正确的方向;否则法向量会在使用非统一缩放时被扭曲。观察者的方向
,光源的方向
和设定高光分散量的 反光度
值三个量共同决定的。片段着色器
。顶点着色器
上。在使用很少数量的顶点时会产生明显的瑕疵。会得到效率提升但是损失了视觉质量。C
的结构体,用作着色器变量的容器。大部分时间用来管理输入/输出/uniform。环境光
、漫反射
、镜面光
颜色。这些东西设定了物体所拥有的颜色。环境光
、漫反射
、镜面光
的 强度。可以使用任何颜色值,对每一个冯氏分量(Phong Component)定义光源发出的颜色/强度。漫反射颜色
的纹理图片。镜面光强度/颜色
的纹理贴图。(仅在物体的特定区域显示镜面高光。)点光源
和 聚光
。锥形的光源
。聚光
。教程来源:https://learnopengl.com/。
投光物(Light Caster):将光 投射(Cast)
到物体的光源。
定向光(Directional Light):一个处于无限远的光源(也叫做平行光),看似所有光线都朝着某一方向传播。
当一个光源处于很远的地方时,来自光源的每条光线就会近似于互相平行;不论物体和/或者观察者的位置,看起来好像所有的光都来自于同一个方向。(例如:太阳。)
通过定义一个光线 方向向量
而不是位置向量来模拟一个定向光。
vec4
时,必需将 w 分量设置为 1.0
,这样 变换 和 投影 才能正确应用。vec4
时,必需将 w 分量设置为 0.0
,这样 位移 时就不会有任何的效果(因为它仅仅代表的是方向)。这样就可以通过检测 w分量 是否等于 1.0
来判断是光的 位置向量 还是光的 方向向量 了:(这正是旧 OpenGL(固定函数式)决定光源是定向光还是位置光源(Positional Light Source)的方法,并根据它来调整光照。)
1 | if(0.0 == lightVector.w) // 注意浮点数据类型的误差 |
漫反射贴图(Diffuse Map):在光照场景中,使用一张覆盖物体的图像,使其能够逐片段索引其独立的颜色值来代表一个物体的漫反射颜色的纹理图。
镜面光贴图(Specular Map):镜面高光的强度可以通过图像每个像素的亮度来获取,让物体的某些部分以不同的强度显示镜面高光。
使用 Photoshop
或 Gimp
之类的工具,将 漫反射纹理 转换为 镜面光纹理 还是比较容易的,只需要剪切掉一些部分,将图像转换为黑白的,并增加亮度/对比度就好了。
发光值(Emission Value)
的贴图。发光(Emit)
时可能显现的颜色,这样物体就能够忽略光照条件进行 发光(Glow)
。例如,游戏中某个物体在发光的时候,你通常看到的就是放射光贴图(比如 机器人的眼,或是箱子上的灯带)。
现实世界的物体,对光产生不同的反应;针对镜面高光,也有不同的反应;物体在反射光的时候,如果散射的光比较少,则会产生较小的高光点,如果散射的光比较多,则会产生较大的高光点。
当描述一个物体的时候,一般是通过一个 材质颜色(Material Color) 和 反光度(Shininess) 来控制材质的属性;其中材质颜色包括:环境光照(Ambient Lighting)
、漫反射光照(Diffuse Lighting)
和 镜面光照(Specular Lighting)
。如下结构体:
1 | /* 材质属性 */ |
物体颜色
是相同的)。光源对 环境光
、漫反射
和 镜面光
分量也具有着不同的 强度。
1 | /* 光照属性 */ |
vec3(1.0)
(以最大强度发光)。冯氏光照模型的主要结构由 3 个分量组成:环境(Ambient)
、漫反射(Diffuse)
和 镜面(Specular)
光照。
环境光照常量
,永远会给物体一些颜色。一个简化的全局照明模型,使用一个很小的常量(光照)颜色,添加到物体片段的最终颜色中,这样子的话即便场景中没有直接的光源也能看起来存在有一些发散的光。环境光照添加到场景:
1 | /* fragmeng shader */ |
漫反射光照 使物体上与光线方向越接近的片段能从光源处获得更多的亮度,即光线与片段法向量
之间的夹角越小,该片段最终显示的颜色就越亮,反之,越暗。如图:
所以,计算漫反射光照需要:
颜色可以数字化的由红色(Red)、绿色(Green)和蓝色(Blue)三个分量组成,它们通常被缩写为RGB.
在现实生活中看到某一物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的(Reflected)颜色
物体颜色:指的是物体从一个光源反射各个颜色分量的大小。
教程来源:https://learnopengl.com/。