介绍
计算机图形学(Computer Graphics,简称CG)是一种使用数学算法将二维或三维图形转化为计算机显示器的栅格形式的科学,所有计算机学科中正反馈最强的一个,没有之一。
大纲
1. 数学
2. 渲染管线
3. 光照模型
数学
一切科学都起源于数学
渲染管线
- 渲染管线,也称渲染流水线,是显示芯片内部处理图形信号相互独立的并行处理单元。渲染管线就是要把一系列的顶点数据,纹理等信息,最终转换成一张人眼可以看到的图像。这个过程由CPU和GPU共同完成。
顶点数据为[(1, 1, 1), [1, -1, 1]...]的正方形
↓
1. 准备阶段(Input Assembler)
通过索引来定义如何将顶点组成三角形,构成面片
↓
一个平面是由两个三角形组成的
2. 顶点着色器(Vertex Shader)
a. 局部坐标系(Local)
获取各个顶点的位置,并表示为矩阵[(1, 1, 1), [1, -1, 1]...]
b. 世界坐标系(World)
将模型通过平移、旋转、缩放操作,实质是矩阵操作,将模型从局部坐标轴统一到世界坐标轴。 这些平移旋转缩放矩阵相乘所得矩阵,称之为世界变换矩阵
c. 观察坐标系(View)
为了让模型在观察者的视角显示出,最后得把所有坐标系统一到观察坐标系,所乘矩阵称之为观察变换矩阵
d. 投影坐标系(Projection)
透视矩阵变换,产生近大远小的视觉效果
3. 曲面细分(Tessellator)
dx11引入,曲面细分,或者更准确的说“镶嵌化处理技术”,就是在顶点与顶点之间自动嵌入新的顶点。在自动插入大量新的顶点之后,模型的曲面会被分得非常细腻,看上去更加平滑致密
4. 几何着色器(Geometry Shader)
在顶点和片段着色器之间有一个可选的着色器,叫做几何着色器(Geometry Shader)。几何着色器以一个或多个表示为一个单独基本图形(primitive)的顶点作为输入,比如可以是一个点或者三角形。几何着色器有意思的地方在于它可以把(一个或多个)顶点转变为完全不同的基本图形(primitive),从而生成比原来多得多的顶点。 Unity2017开始支持,适用于发毛
5. 裁剪(Clipping)
视域体以外的顶点忽略
6. 光栅化(Rasterization)
a. 视口变换 当适配不同设备屏幕时,不同比例以及不同分辨率的矩阵变换。
b. 背面剔除(Culling) 为了优化,删除看不到的面的顶点数据,让计算机忽略对其的处理
- 剔除前:
- 剔除后:
c. 顶点属性插值
有没想过顶点有了,像素(屏幕所见的一切都是像素)怎么来?
7. 像素着色器(Fragment Shader)
像素着色引擎是以每像素为单位的图形处理功能。
像素都汇聚到这个地方了,接下来就可以为所欲为了
代码层面上逐像素光照可以涉及的领域,Lambert光照(漫射光)、Phong Specular高光等光照模型可以套用的地方。
总结一下
准备阶段(Input Assembler)
↓
顶点着色器(Vertex Shader)
↓
曲面细分(Tessellator)
↓
几何着色器(Geometry Shader)
↓
裁剪(Clipping)
↓
光栅化(Rasterization)
↓
像素着色器(Fragment Shader)
不同工种研究不同的领域,作为技术美术,应该深入研究其中的三个
顶点着色器(Vertex Shader)
几何着色器(Geometry Shader)
像素着色器(Fragment Shader)
什么是着色器?
所有复杂的两层关系,可以通过中间层解决,着色器就是程序员告诉计算机如何渲染的方式
讲得太抽象,结合实际代码走一遍
一个只显示白色的材质
//定义=告诉计算机
Shader "PeroPero/Unlit" //显示材质在Unity面板的位置,如上图
{
Properties
{
_MainTex ("Texture", 2D) = "white" {} //定义一个外部获取的贴图
}
SubShader
{
Tags { "LightMode"="ForwardBase" } //定义光照模式为ForwardBase
Pass //定义一个pass,代表一次渲染,多个pass代表多次渲染
{
CGPROGRAM //定义用CG语言的语法沟通
#pragma vertex vert //定义顶点着色器在vert函数中
#pragma fragment frag //定义像素着色器在frag函数中
#include "UnityCG.cginc" //引用外部程序集,用于一些快捷API
//定义一个数据结构
struct appdata
{
float4 vertex : POSITION; //释义,告诉计算机这个值用于缓存顶点的本地坐标的位置
};
struct v2f
{
float4 vertex : SV_POSITION; //释义,告诉计算机这个值用于缓存顶点的最终位置
};
//顶点着色器
v2f vert (appdata v)
{
v2f o;
//顶点坐标乘以世界坐标系的混合矩阵M,再乘以观察矩阵V,再乘以投影矩阵P,得到最终的坐标
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
//返回给计算机算出来的最终顶点坐标
return o;
}
//像素着色器
fixed4 frag (v2f i) : SV_Target
{
//像素的颜色都是白色
return fixed4(1, 1, 1, 1);
}
ENDCG
}
}
}
顶点着色器(Vertex Shader)
在这里可以获得所有顶点的控制权,可以做任何和顶点有关的效果。如UV动画,顶点动画,逐顶点光照
像素着色器(Fragment Shader)
在这里可以获得所有像素的控制权,可以做一切渲染相关的效果,如光照、贴图映射、凹凸贴图等。
什么是光照效果?如Lambert(漫射光)、Phong Specular(冯氏高光)、Ramp Texture(渐变贴图)、BRDF(双向反射分布函数)、Fresnel Reflection(菲涅尔反射)等
Lambert(漫反射)
Phong Specular(冯氏高光)
BRDF(双向反射分布函数))
Fresnel Reflection(菲涅尔反射)
把以上所有模拟真实环境的Shader都写到一个材质中
那么这个材质就是大家天天吹牛所说的PBR材质(Physically Based Rendering),即基于物理的渲染,没什么深奥的。它就是是基于很多光照模型。
所以说,所有复杂的东西都是简单的东西拼凑起来的。即积木原理,那大家知道什么叫拼图原理呢?
光照模型
什么是光照模型呢?
当光照射到物体表面时,物体对光会发生反射、透射、吸收、衍射、折射、和干涉,其中被物体吸收的部分转化为热,反射、透射的光进入人的视觉系统,使我们能看见物体。为模拟这一现象,我们建立一些数学模型来替代复杂的物理模型,这些模型就称为明暗效应模型或者光照明模型
简而言之,就是复杂的数学算法
Lambert漫反射
模拟漫反射。
漫反射,是投射在粗糙表面上的光向各个方向反射的现象。当一束平行的入射光线射到粗糙的表面时,表面会把光线向着四面八方反射,所以入射线虽然互相平行,由于各点的法线方向不一致,造成反射光线向不同的方向无规则地反射,这种反射称之为“漫反射”或“漫射”
Phong Specular高光
模拟高光。
Phong 高光模型是最基础且表现最友好的高光类型。它会计算出光在物体表面的反射方向与观察者视线方向之间的对比结果。它是一种非常常见的高光模型,从游戏到电影都有诸多的应用。虽然在镜面反射的精确建模上它并不是最接近现实的,但在大多数情况下它都显得极为逼真。
BlinnPhong Specular高光
廉价高效模拟高光。
Blinn 是另一种计算和估算镜面高光更有效的方式。它是通过视线方向和光线方向所形成的半角向量来完成的。它是由一位名叫吉姆·博林(Jim Blinn)的人带进CG 世界的。他发现使用半角向量而不是我们自己形成的反射向量来进行计算显得更加高效。这样既减少了代码量也减少了运算时间。
Anisotropic各向异性高光
模拟头发和金属丝的光照模型
(来自B站Aniraiden)
首先,经Anisotropic Normal Map扰动后,表面法线已经具备凹槽特性。
float3 anisoDir = normalize(s.Normal + s.AnisoDir);
float aniso = dot(anisoDir, halfVector);
其次,Sin函数的目的中为了产生一个环。如下图。如果没有sin,则不会产生光环。
最后,_AnisoOffset的作用是控制光环位置。使得光环可以水平位移,达到你想要的任何位置。
aniso = max(0, sin((aniso + _AnisoOffset) * 3.14));
如何成环呢,忽略_AnisoOffset
算式为 aniso = max(0, sin((aniso) * 3.14));
对比aniso = max(0, aniso);
则如下图
仅高光的图:
加入Anisotropic各向异性后