Games101 Shadering 着色 07-08
本文最后更新于21 天前,其中的信息可能已经过时,如有错误请留言

回顾我们目前整个渲染流程:

  1. Model 变换:把物体从“模型本地坐标”放到“世界坐标系”里(决定物体在场景中的位置、旋转、缩放)。
  2. View 变换:用相机的位姿把整个世界“搬到相机面前”,等价于让相机看起来在原点、朝向约定方向(GAMES101 常用朝 -z)。
  3. Projection 投影:把 3D 场景做透视/正交投影,映射到标准化坐标,再映射到屏幕平面。
  4. Rasterization 光栅化:把连续的三角形区域离散成屏幕像素(生成片段),并计算每个像素的深度、颜色、纹理坐标等插值信息;最后通过 深度测试(Z-buffer) 决定哪个三角形真正显示在最上面。

当你能正确做投影、光栅化、反走样和消隐后,画面仍然可能“像纸片/像塑料”。为了更真实,我们还缺什么?

Shading着色

字典中的定义:是根据表面材质、光照、法线、观察方向等信息,计算物体表面点或片元最终颜色/亮度的过程。

在本课程中的定义:对不同的物体应用不同的材质 The process of applying a material to an object

  • 计算着色的玩意儿叫shader(着色器)
  • 以下着色计算都是考虑在一个点上进行计算,要应用到整个模型,则需要在所有点上进行着色计算

 一种简单的模型:Blinn-Phong反射模型 A Simple Shading Model (Blinn-Phong Reflectance Model)

Blinn-Phong模型是经验模型,与现实相比仍有很多不足

感性观察 Perceptual Observations

  • 高光(Specular highlights):光滑表面镜面反射处附近形成高光
  • 漫反射(Diffuse reflection):在整个杯子上变化比较柔和,粗糙表面形成漫反射
  • 环境光(Ambient lighting):上图中背光处仍然有颜色,因为其接受了周围环境的间接光照,为了简化模型,我们会使用一个环境光常量来表示环境光对物体的影响

着色具有局部性 Shading is Local

  • 着色点(Shading point)在局部上是一个平面,在这个平面上定义:
  • 观看方向v(Viewer direction)
  • 法线方向n(Surface normal)
  • 光照方向l(Light direction)
  • 表面参数颜色、光泽度等(Surface parameters color, shininess, …)

意思是看任意一点的着色只看他自己,忽略其他物体的存在,因此着色过程不包括阴影的生成 No shadows will be generated! (shading ≠ shadow)

也就是说着色的结果只是明暗变化,但看不到阴影

漫反射 Diffuse Reflection

兰伯特余弦定理(Lambert’s cosine law)

  • 定义:光线打到某一点后,光线均匀的向各个方向散射,表面的颜色在各个观察方向都相同 Light is scattered uniformly in all directions, surface color is the same for all viewing directi
  • 多少光被接受与面和光线的夹角有关,根据兰伯特余弦定理(Lambert’s cosine law),单位面积上接收到的光的能量的能量等于光线与法线夹角的余弦
  • 太阳能板在板面垂直于光照接受光能最大

因此我们能到一个结论:越正对光源(夹角小),cos 越大,漫反射越亮;越斜,越暗。

光线传播本身会衰减

  • I:光源强度(light intensity)
  • r:从表面点到光源的距离(distance)。

假设光是均匀发散出去,则在发射出去的一个球面上的光密度跟传播长度r成反比
定义光在传播到单位距离的时候,强度是I,则传播到r处时的能量 = I / r2

兰伯特(漫反射)着色 Lambertian (Diffuse) Shading

计算物体表面的漫反射(diffuse)亮度:

  • 漫反射只和物体本身与光线有关与观察方向v无关
  • 引入max是因为若点乘小于0说明是从下面射过来的,这里讨论的是反射不是折射,因此没有意义
  • 因为在着色中,法线 \(\boldsymbol{n}\) 和入射方向 \(\boldsymbol{l}\) 通常都被当作单位向量,根据点乘公式 \(\boldsymbol{n} \cdot \boldsymbol{l} = |\boldsymbol{n}||\boldsymbol{l}|\cos\theta\),此时 \(|\boldsymbol{n}|=|\boldsymbol{l}|=1\),所以 \(\boldsymbol{n} \cdot \boldsymbol{l}\) 就等于它们夹角 \(\theta\) 的余弦
  • 注意这些向量都是归一化处理过的,因此:若两个向量点乘接近1则离得很近,若接近0则离得很远

kd​ 决定颜色
如果 kd=(1,0,0)k_d = (1,0,0)kd​=(1,0,0),白光照上去主要反射红色 → 看起来就是红的
如果 kd=(0.2,0.8,0.2)k_d = (0.2,0.8,0.2)kd​=(0.2,0.8,0.2),就偏绿色

在一个石膏球上进行漫反射计算的结果
看单个球体随着光源跟法线夹角逐渐变大,颜色会越来越暗
从左到右每个球体的kd值越来越大,

镜面反射 Specular Term (Blinn-Phong)

  • 高光的强度取决于观察方向,观察方向与镜面反射方向接近时能看见高光 Intensity depends on view direction, b right near mirror reflection direction
  • 观察方向v与镜面反射方向接近说明半程向量h与法线n接近(这样计算更加高效) V close to mirror direction ⇔ half vector near normal
    利用半程向量与法向量的点积来判断高光程度
  • 在Blinn-Phong模型中镜面反射考虑了光线的衰减(I/r2),但没考虑吸收了多少光(n·l)
    经验模型,意思意思就行了
  • 使用观察方向和镜面反射方向判断是否接近是Phong模型
  • 由于cosα的容忍度太大,导致高光太大,所以引入p次幂来限制高光范围(小高光p大约在100到200),

环境光 Ambient Term

  • 环境光会照亮每一点,与直接光照方向,观察方向都无关,是一个常数 Shading that does not depend on anything, add constant color to account for disregarded illumination and fill in black shadows
  • 这是一个非常大胆的简化 This is approximate / fake! 后面的全局光照会解决这一点

Blinn-Phong反射模型 Blinn-Phong Reflection Model

前面的讨论都是对物体某一个点进行的计算,最终要对物体所有的点应用后(不一定是所有的点哦,计算量太大了),得到完整的渲染结果

着色频率 Shading Frequencies

逐三角形着色 Shade each triangle (flat shading)

面着色,每个面只有一个法线,进行一次着色计算,应用到该面内所有像素
所以每个面内部的颜色(明暗)没有差异

  • 对于平滑的表面表现不是很理想 Not good for smooth surfaces
  • 面的法线好算,通过任意两个边做个叉乘就行

逐顶点着色 Shade each vertex (Gouraud shading)

算出每个顶点的法线,然后对每个顶点计算着色,定点外其余部分的颜色通过插值计算出来

  • 顶点的法线:
    如果知道具体表示的几何体是什么样的,例如用多个顶点表示球体,则每个顶点的法线方向即为球心向顶点连线的方向 Best to get vertex normals from the underlying geometry, e.g. consider a sphere

否则必须从相邻三角形面推断出顶点法线,一个简单的方法是求相邻面法线的平均法线

逐像素着色 Shade each pixel (Phong shading)

  • 在每个三角形上插入法线向量 Interpolate normal vectors across each triangle
  • 在三角形内部每个像素都插值出一个法线方向,计算每个像素的完整着色模型 Compute full shading model at each pixel

假如在三角形内部,已经知道顶点的法线了,使用顶点法线的重心插值 Barycentric interpolation of vertex normals得到内部平滑过渡的一个法线
最后要对插值方向进行归一化 Don’t forget to normalize the interpolated directions

几种着色频率的对比 Shading Frequenciesy: Face, Vertex or Pixel

  • 模型几何较为复杂时,用简单的逐像素模型也能得到不错的效果,并且开销小
  • 在模型几何较为简单时,逐像素效果更好,但性能要求高一些

图形(实时渲染)管线 Graphics (Real-time Rendering) Pipeline

渲染管线:把一个场景经过一系列的处理,最后再显示器上显示一张图像,这一系列过程就叫渲染管线
虽然不够详细,但是流程大概可以描述为以下几个阶段
1、输入一堆三维空间中的点
2、经过MVPV变换后得到这些点在屏幕上的二维坐标
3、规定哪些点相互构成三角形(指定图元拓扑结构)
4、光栅化,得到被三角形覆盖的像素
5、着色计算,计算每个像素该显示什么,应该是什么颜色,Z-buffer的生成等
6、把计算结果存到一个缓存中,输出到显示器

着色器程序 Shader Programs

目前渲染管线都是在GPU中被编程完成了,只有顶点处理片段处理可以编程。描述对其处理过程的操作的程序就叫shader(本质能在硬件上执行的程序)
着色器会对每个顶点或片元执行一次,只写出单次操作即可 Shader function executes once per fragment.因此不需要写for循环
如果写的是对顶点的操作,就叫vertex shader,如果写的是对像素的操作就叫fragment / pixal shader片元着色器

顶点shader在改什么
  • 顶点位置
  • 顶点携带的数据

比如你可以让模型:

  • 变换位置
  • 旋转、缩放
  • 做波浪起伏
  • 骨骼动画
  • 地形抖动

也就是:物体的形状、位置、姿态怎么变。

片元 shader 在改什么

它主要改的是:外观

  • 每个像素的颜色
  • 亮暗
  • 材质观感

比如你可以让物体看起来:

  • 是红色还是蓝色
  • 有漫反射还是镜面高光
  • 像金属还是塑料
  • 有没有纹理
  • 有没有发光
  • 有没有卡通渲染、描边、噪声、火焰、水波纹

以下是一个GLSL片段着色器的程序代码:

uniform sampler2D myTexture; // 获取纹理 uniform是全局变量
uniform vec3 lightDir; //获取光照方向
varying vec2 uv;//获取uv坐标
varying vec3 norm; //获取法线坐标
void diffuseShader()
{
    vec3 kd;//获取kd系数
    kd = texture2d(myTexture, uv); 
    kd *= clamp(dot(–lightDir, norm), 0.0, 1.0); //Phong模型漫反射
    gl_FragColor = vec4(kd, 1.0); //输出该像素的颜色
} 

练习shader:https://www.shadertoy.com

用于执行图形管线的硬件:GPU Graphics Pipeline Implementation: GPUs

  • GPU分为独立显卡(Discrete GPU Card)与集成显卡(Integrated GPU)
  • 学过高性能计算的话,会知道GPU的并行度高,适合处理图形学的相关计算
学习笔记如有侵权,请提醒我,我会马上删除
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇