generated from cotes2020/chirpy-starter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create "GAMES101 第8讲 着色(着色频率, 实时渲染管线, 纹理映射)"
- Loading branch information
1 parent
cbe1a2d
commit a8f8f83
Showing
13 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
--- | ||
title: GAMES101 第8讲 着色(着色频率, 实时渲染管线, 纹理映射) | ||
date: 2024-12-25 19:47:00 +0800 | ||
categories: [笔记, GAMES101] | ||
tags: [GAMES101, 计算机图形学] | ||
math: true | ||
--- | ||
|
||
## 着色频率 | ||
|
||
把颜色应用在一个面上, 应用在一个顶点上, 或者应用在一个像素上, 这些都是着色的频率. 通常来说, 着色的频率越高, 渲染的效果就越好, 但是性能也就越差. | ||
|
||
![着色频率](/assets/posts/GAMES101-Lecture08/01.png){:width="700px"} | ||
|
||
其中: 如果在顶点上着色(例如图中在矩形的四个顶点上着色), 那么在矩形内部的像素就会使用顶点的颜色进行**插值**. | ||
|
||
### 逐三角形着色 | ||
|
||
又叫 **平面着色 Flat Shading** | ||
|
||
一个三角面内的颜色完全相同, 根据三角形的法线(两条边的叉乘)等参数求得, 然后填充整个三角形. | ||
|
||
![逐三角形着色](/assets/posts/GAMES101-Lecture08/02.png){:width="400px"} | ||
|
||
- 三角形面是平坦的(只有一个法线方向) | ||
- 对于平滑的曲面, 逐三角形着色会导致边缘的颜色不连续 | ||
|
||
### 逐顶点着色 | ||
|
||
又叫 **Gouraud Shading** | ||
|
||
对任意一个顶点, 计算出它的法线, 以此为基础计算出顶点的颜色, 然后在三角形内部的像素上进行插值. | ||
|
||
![逐顶点着色](/assets/posts/GAMES101-Lecture08/03.png){:width="400px"} | ||
|
||
- 内部的颜色通过顶点颜色的插值得到 | ||
- 顶点法线的计算方法见[后文](#顶点法线的计算) | ||
- 又叫Phong Shading, 不是Blinn-Phong反射模型, 是一种Shading算法, 都是以Phong这个人的名字命名的 | ||
|
||
### 逐像素着色 | ||
|
||
又叫 **Phong Shading** | ||
|
||
对于每一个像素, 计算出它的法线, 以此为基础计算出像素的颜色. | ||
|
||
- 逐像素着色是最精确的着色方法 | ||
- 但是计算量也是最大的 | ||
- 通常用于高质量的渲染 | ||
|
||
### 着色频率的选择 | ||
|
||
![着色频率的选择](/assets/posts/GAMES101-Lecture08/04.png){:width="400px"} | ||
|
||
- 当面片数量已经很高时, 逐像素着色的计算量就会很大, 这时候可以考虑逐顶点着色或者逐三角形着色. | ||
- 当面片数量较少时, 逐像素着色的计算量就会很小, 这时候可以考虑逐像素着色. | ||
- 当然, 当面片数量大于了一定的阈值, 超过了像素数量, 那么逐像素着色就是最好的选择. | ||
|
||
### 顶点法线的计算 | ||
|
||
顶点法线的计算方法有很多种, 当我们只需要计算一个绝对光滑的球形时, 法线方向就是球心指向顶点的方向. | ||
|
||
![顶点法线的计算](/assets/posts/GAMES101-Lecture08/05.png){:width="400px"} | ||
|
||
当我们需要计算一个不规则的曲面时, 可以通过计算顶点的四周的面片的法线, 然后取平均值. | ||
|
||
![顶点法线的计算2](/assets/posts/GAMES101-Lecture08/06.png){:width="400px"} | ||
|
||
$$ | ||
N_v = \frac{\sum_{i} N_i}{\|\sum_{i} N_i\|} | ||
$$ | ||
|
||
但是想要更加精确的法线, 可以通过计算顶点的四周的面片的法线, 然后**根据面片的面积加权平均**. | ||
|
||
### 逐像素的法线插值 | ||
|
||
顶点的法线是已知的, 但是像素的法线是未知的, 所以需要对顶点的法线进行**重心坐标插值**. | ||
|
||
![逐像素的法线插值](/assets/posts/GAMES101-Lecture08/07.png){:width="400px"} | ||
|
||
插值后需要对法线进行归一化. | ||
|
||
## 实时渲染管线(图形管线) | ||
|
||
从场景到屏幕的过程, 通常被称为图形管线. | ||
|
||
![图形管线](/assets/posts/GAMES101-Lecture08/08.png){:width="700px"} | ||
|
||
1. **Application 应用**: 先输入三维(模型)空间中的顶点数据 | ||
2. **顶点处理 Vertex Processing**: 将顶点数据变换到屏幕空间(投影变换) | ||
3. **三角形处理 Triangle Processing**: 将顶点数据变换成三角形 | ||
4. **光栅化 Rasterization**: 将三角形变成片元(fragment, 又叫像素) | ||
5. **片元处理 Fragment Processing**: 着色, 计算像素的颜色(这里也有深度测试等操作) | ||
6. **帧缓冲 Framebuffer Operations**: 将像素写入帧缓冲 | ||
7. **显示 Display**: 将帧缓冲的内容显示到屏幕上 | ||
|
||
如果要着色: | ||
- **Gouraud Shading**: 顶点处理阶段计算顶点颜色, 片元处理阶段插值得到像素颜色 | ||
- **Phong Shading**: 顶点处理阶段计算顶点法线, 片元处理阶段插值得到像素法线, 然后计算像素颜色 | ||
|
||
这两个阶段(顶点处理和片元处理)是可以自定义的, 也成为可编程着色器, 我们称其为**着色器 Shader**. | ||
|
||
### 着色器 Shader | ||
|
||
现代GPU允许我们编写自定义的着色器(Shader), 用于顶点处理和片元处理. | ||
|
||
**着色器 Shader** 是一种可以在GPU硬件上执行的语言, OpenGL使用GLSL, DirectX使用HLSL. | ||
- **顶点着色器 Vertex Shader**: 用于顶点处理阶段, 计算顶点的位置, 颜色等 | ||
- **片元着色器 Fragment Shader**: 用于片元处理阶段, 计算像素的颜色 | ||
|
||
片元着色器例子: | ||
|
||
```glsl | ||
uniform sampler2D myTexture; // 纹理 | ||
varying vec3 lightDir; // 光线方向 | ||
varying vec2 uv; // 纹理坐标 | ||
varying vec3 norm; // 顶点法线 | ||
void diffuseShader() { | ||
vec3 kd; | ||
kd = texture2D(myTexture, uv); // 从纹理中获取颜色 | ||
kd *= clamp(dot(norm, lightDir), 0.0, 1.0); // 计算漫反射 | ||
gl_FragColor = vec4(kd, 1.0); // 设置像素颜色 | ||
} | ||
``` | ||
|
||
## 纹理映射 | ||
|
||
**纹理映射 Texture Mapping** 是一种将纹理映射到三维模型表面的技术. | ||
|
||
### 2D纹理 | ||
|
||
![2D纹理](/assets/posts/GAMES101-Lecture08/09.png){:width="700px"} | ||
|
||
我们认为: 任何一个三维物体的表面都可以看作是一个二维平面, 我们可以将一个二维的纹理贴到这个平面上. | ||
|
||
这个过程就是**纹理映射 Texture Mapping**, 一般由美术工程师完成, 也有自动化完成纹理映射的相关研究方向 | ||
|
||
### 纹理坐标(UV坐标) | ||
|
||
![纹理坐标](/assets/posts/GAMES101-Lecture08/10.png){:width="700px"} | ||
|
||
- 纹理坐标是二维的, 通常用 $u$ 和 $v$ 表示 | ||
- $u$ 和 $v$ 的范围通常认为是都在 $[0, 1]$ 区间内 | ||
- 三角形每一个顶点都对应一个uv坐标 | ||
|
||
### 纹理的重复 | ||
|
||
在下图中, 我们显示了一个建筑场景的uv坐标的可视化结果: | ||
|
||
![纹理的重复](/assets/posts/GAMES101-Lecture08/11.png){:width="400px"} | ||
|
||
我们可以很明显的看到, 纹理在建筑的表面上重复了很多次, 而且两个纹理的边界是很明显的; 但是在实际的渲染结果中, 并不能看到这种重复的现象: | ||
|
||
![纹理的重复2](/assets/posts/GAMES101-Lecture08/12.png){:width="400px"} | ||
|
||
这说明, 纹理本身在设计时是上下边界连续的, 这种纹理被称作**可平铺纹理 Tileable texture**. | ||
|
||
### 三角形内部的像素的纹理坐标 | ||
|
||
我们知道三角形三个顶点对应的纹理坐标, 那么三角形内部的像素的纹理坐标是如何计算的呢? | ||
|
||
这也是通过将顶点的纹理坐标进行插值得到的. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.