简化版 GAMES 101 计算机图形学 13:从光栅化到着色------赋予三维像素光影灵魂
- [🔗 前置回顾:完整三维渲染流水线闭环](#🔗 前置回顾:完整三维渲染流水线闭环)
- [🎨 着色的核心定义:不止简单上色,是光线与材质的双向交互](#🎨 着色的核心定义:不止简单上色,是光线与材质的双向交互)
-
- [📖 权威定义解析](#📖 权威定义解析)
- [☕ 光影三重维度:Blinn-Phong 模型核心分量全解](#☕ 光影三重维度:Blinn-Phong 模型核心分量全解)
-
- [🌫️ 环境光 Ambient:暗部不死寂的温柔底色](#🌫️ 环境光 Ambient:暗部不死寂的温柔底色)
- [📐 环境光核心公式](#📐 环境光核心公式)
- [💻 环境光核心代码实现(极简版)](#💻 环境光核心代码实现(极简版))
- [🪨 漫反射 Diffuse:哑光材质的质感核心](#🪨 漫反射 Diffuse:哑光材质的质感核心)
- [1. Lambert 余弦定律(角度衰减)](#1. Lambert 余弦定律(角度衰减))
- [2. 距离平方衰减(距离衰减)](#2. 距离平方衰减(距离衰减))
- [📐 漫反射完整公式](#📐 漫反射完整公式)
- [💻 漫反射核心代码实现](#💻 漫反射核心代码实现)
- [✨ 高光 Specular:光滑材质的质感点睛之笔](#✨ 高光 Specular:光滑材质的质感点睛之笔)
- [📍 核心易错点:着色 ≠ 阴影](#📍 核心易错点:着色 ≠ 阴影)
- [🌟 课程总结与下期预告](#🌟 课程总结与下期预告)
在计算机图形学的世界里,三维模型的顶点、三角面只是冰冷的几何骨架🗿。无论模型精度多高,若仅依靠基础渲染流程,最终呈现的终究是扁平、单调、毫无层次的色块。
我们所见的真实画面------石膏的温润哑光、金属的锐利高光、陶瓷的细腻质感、物体明暗的自然过渡,所有逼真视觉效果的底层核心,皆源于**着色(Shading)**技术✨。
着色,是打通「几何结构」与「真实视觉」的最后关卡,也是计算机模拟自然光影、复刻现实质感的核心魔法。
🔗 前置回顾:完整三维渲染流水线闭环
在正式踏入着色领域前,我们先串联整套三维渲染链路,厘清着色在整个管线中的定位,形成完整知识闭环。从三维模型建模到屏幕像素输出,全程遵循固定变换逻辑,层层递进、环环相扣。
#mermaid-svg-ikRDnoB4gxZzERUx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ikRDnoB4gxZzERUx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ikRDnoB4gxZzERUx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ikRDnoB4gxZzERUx .error-icon{fill:#552222;}#mermaid-svg-ikRDnoB4gxZzERUx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ikRDnoB4gxZzERUx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ikRDnoB4gxZzERUx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ikRDnoB4gxZzERUx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ikRDnoB4gxZzERUx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ikRDnoB4gxZzERUx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ikRDnoB4gxZzERUx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ikRDnoB4gxZzERUx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ikRDnoB4gxZzERUx .marker.cross{stroke:#333333;}#mermaid-svg-ikRDnoB4gxZzERUx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ikRDnoB4gxZzERUx p{margin:0;}#mermaid-svg-ikRDnoB4gxZzERUx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ikRDnoB4gxZzERUx .cluster-label text{fill:#333;}#mermaid-svg-ikRDnoB4gxZzERUx .cluster-label span{color:#333;}#mermaid-svg-ikRDnoB4gxZzERUx .cluster-label span p{background-color:transparent;}#mermaid-svg-ikRDnoB4gxZzERUx .label text,#mermaid-svg-ikRDnoB4gxZzERUx span{fill:#333;color:#333;}#mermaid-svg-ikRDnoB4gxZzERUx .node rect,#mermaid-svg-ikRDnoB4gxZzERUx .node circle,#mermaid-svg-ikRDnoB4gxZzERUx .node ellipse,#mermaid-svg-ikRDnoB4gxZzERUx .node polygon,#mermaid-svg-ikRDnoB4gxZzERUx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ikRDnoB4gxZzERUx .rough-node .label text,#mermaid-svg-ikRDnoB4gxZzERUx .node .label text,#mermaid-svg-ikRDnoB4gxZzERUx .image-shape .label,#mermaid-svg-ikRDnoB4gxZzERUx .icon-shape .label{text-anchor:middle;}#mermaid-svg-ikRDnoB4gxZzERUx .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ikRDnoB4gxZzERUx .rough-node .label,#mermaid-svg-ikRDnoB4gxZzERUx .node .label,#mermaid-svg-ikRDnoB4gxZzERUx .image-shape .label,#mermaid-svg-ikRDnoB4gxZzERUx .icon-shape .label{text-align:center;}#mermaid-svg-ikRDnoB4gxZzERUx .node.clickable{cursor:pointer;}#mermaid-svg-ikRDnoB4gxZzERUx .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ikRDnoB4gxZzERUx .arrowheadPath{fill:#333333;}#mermaid-svg-ikRDnoB4gxZzERUx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ikRDnoB4gxZzERUx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ikRDnoB4gxZzERUx .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ikRDnoB4gxZzERUx .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ikRDnoB4gxZzERUx .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ikRDnoB4gxZzERUx .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ikRDnoB4gxZzERUx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ikRDnoB4gxZzERUx .cluster text{fill:#333;}#mermaid-svg-ikRDnoB4gxZzERUx .cluster span{color:#333;}#mermaid-svg-ikRDnoB4gxZzERUx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ikRDnoB4gxZzERUx .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ikRDnoB4gxZzERUx rect.text{fill:none;stroke-width:0;}#mermaid-svg-ikRDnoB4gxZzERUx .icon-shape,#mermaid-svg-ikRDnoB4gxZzERUx .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ikRDnoB4gxZzERUx .icon-shape p,#mermaid-svg-ikRDnoB4gxZzERUx .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ikRDnoB4gxZzERUx .icon-shape .label rect,#mermaid-svg-ikRDnoB4gxZzERUx .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ikRDnoB4gxZzERUx .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ikRDnoB4gxZzERUx .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ikRDnoB4gxZzERUx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 三维模型数据
模型变换Model Transform
视图变换View Transform
投影变换Projection Transform
视口映射Viewport Mapping
光栅化Rasterization
着色计算Shading
屏幕像素输出
图1:三维渲染完整流水线示意图 ,该流程图清晰展示了三维数据从建模到成像的全流程,着色是光栅化后的核心像素处理步骤,直接决定画面最终质感。
各阶段核心作用详解:
-
模型变换:对模型进行平移、旋转、缩放,赋予物体空间姿态,让静态几何模型拥有多样形态;
-
视图变换:统一坐标系,将摄像机固定于坐标原点、沿负Z轴观测场景,规范全局观测视角;
-
投影变换:完成3D空间到2D平面的降维转换,模拟人眼透视效果,实现近大远小的视觉规律;
-
视口映射+光栅化:将虚拟三维场景的几何图形,映射到屏幕像素网格,把矢量几何图形转化为离散的像素片元。
但仅完成以上步骤,渲染出的画面存在致命短板:所有三角面仅显示单一固有色,无明暗、无光影、无质感。旋转模型时无法通过光影区分结构层次,画面扁平空洞、视觉虚假。
根源问题十分明确:流水线仅完成了「形状的绘制」,却未赋予每一个像素「光影的灵魂」,而着色技术,正是填补这一视觉缺陷的核心方案。
🎨 着色的核心定义:不止简单上色,是光线与材质的双向交互
多数初学者会误区着色的本质,认为其只是「给模型填充颜色」。实则不然,着色是一套基于物理规律的光影模拟算法体系。
📖 权威定义解析
韦氏词典中,Shading(着色)的释义为:通过色块、明暗线条,为平面画面赋予层次与立体感的绘画手法。
在计算机图形学专业语境下,定义更为精准严谨:
着色,是根据物体材质属性、光照参数、观测视角,定量计算每一个像素片元的最终色彩亮度,模拟光线与物体表面相互作用的全过程。
现实世界中,不同物体的质感差异,本质是材质对光线的反射、吸收、散射能力不同:
-
石膏、墙面、磨砂纸:表面粗糙,光线均匀散射,呈现温润哑光质感;
-
金属、镜面、抛光陶瓷:表面光滑,光线定向反射,形成锐利高光质感;
-
木头、皮革:材质特殊,兼具漫反射与微弱高光,呈现质朴肌理。
而我们核心学习的 Blinn-Phong 反射模型,是图形学工业界最经典、最通用的基础着色模型✅。它以极简的数学公式,高度还原自然光影规律,是真实感渲染的基石,也是后续PBR物理渲染的前置基础。
☕ 光影三重维度:Blinn-Phong 模型核心分量全解
自然光影千变万化,但 Blinn-Phong 模型将其高度抽象、拆解为三大核心分量:环境光、漫反射、高光。三者叠加融合,即可模拟绝大多数日常物体的光影质感。
| 光影分量 | 核心作用 | 视觉特征 | 是否与视角相关 |
|---|---|---|---|
| 环境光 Ambient | 填充暗部底色,杜绝画面死黑 | 全局均匀、柔和微弱、无明暗差异 | 无关 |
| 漫反射 Diffuse | 还原物体固有色,形成基础明暗层次 | 哑光质感、过渡自然、均匀柔和 | 无关 |
| 高光 Specular | 模拟光滑表面反光,凸显材质质感 | 局部亮斑、锐利集中、亮度极高 | 强相关 |
表1:Blinn-Phong 三大光影分量核心属性对比表,清晰区分三种光影的作用与特性,是理解材质质感的核心依据。
🌫️ 环境光 Ambient:暗部不死寂的温柔底色
从纯物理角度分析,物体背光面无法接收任何直射光源,理应呈现纯黑色。但在现实场景中,我们从未见过绝对漆黑的物体暗部------这便是间接光照的作用。
真实环境中,光线会经墙面、地面、家具等物体多次反射、折射,最终微弱抵达物体背光面,为暗部赋予基础亮度与色彩。
若精准模拟全局所有光线的多次反射,计算量极大、性能开销极高,完全不适合实时渲染。因此 Blinn-Phong 模型做出理想化工程简化假设:
环境光是全局恒定的常量光照,均匀包裹物体所有表面,无方向差异、无距离衰减、无角度变化。
📐 环境光核心公式
I a m b i e n t = k a c d o t I l i g h t I_{ambient} = k_a cdot I_{light} Iambient=kacdotIlight
-
k a k_a ka:环境光反射系数(RGB三通道,取值0~1),决定物体对环境光的反射能力;
-
I l i g h t I_{light} Ilight:全局环境光基础强度,统一作用于整个场景。
💻 环境光核心代码实现(极简版)
c++
// 计算环境光:全局恒定,无任何方向、距离变化
Color calcAmbient(Color lightIntensity, Color ka) {
// 环境光 = 环境光系数 * 光源基础强度
return ka * lightIntensity;
}
性能说明 :环境光计算无循环、无向量运算,仅简单数值相乘,性能开销趋近于0,是实时渲染中性价比极高的补光方案。
🪨 漫反射 Diffuse:哑光材质的质感核心
漫反射是自然界最普遍的光影现象,也是石膏、墙面、磨砂、布料等哑光材质的核心质感来源。
其物理本质为:光线击中粗糙不规则的物体表面,会向四面八方均匀散射,无固定反射方向,因此无论观察者处于哪个角度,看到的表面亮度基本一致。
#mermaid-svg-WZvCOXAME4DKYkox{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WZvCOXAME4DKYkox .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WZvCOXAME4DKYkox .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WZvCOXAME4DKYkox .error-icon{fill:#552222;}#mermaid-svg-WZvCOXAME4DKYkox .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WZvCOXAME4DKYkox .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WZvCOXAME4DKYkox .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WZvCOXAME4DKYkox .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WZvCOXAME4DKYkox .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WZvCOXAME4DKYkox .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WZvCOXAME4DKYkox .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WZvCOXAME4DKYkox .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WZvCOXAME4DKYkox .marker.cross{stroke:#333333;}#mermaid-svg-WZvCOXAME4DKYkox svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WZvCOXAME4DKYkox p{margin:0;}#mermaid-svg-WZvCOXAME4DKYkox .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WZvCOXAME4DKYkox .cluster-label text{fill:#333;}#mermaid-svg-WZvCOXAME4DKYkox .cluster-label span{color:#333;}#mermaid-svg-WZvCOXAME4DKYkox .cluster-label span p{background-color:transparent;}#mermaid-svg-WZvCOXAME4DKYkox .label text,#mermaid-svg-WZvCOXAME4DKYkox span{fill:#333;color:#333;}#mermaid-svg-WZvCOXAME4DKYkox .node rect,#mermaid-svg-WZvCOXAME4DKYkox .node circle,#mermaid-svg-WZvCOXAME4DKYkox .node ellipse,#mermaid-svg-WZvCOXAME4DKYkox .node polygon,#mermaid-svg-WZvCOXAME4DKYkox .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WZvCOXAME4DKYkox .rough-node .label text,#mermaid-svg-WZvCOXAME4DKYkox .node .label text,#mermaid-svg-WZvCOXAME4DKYkox .image-shape .label,#mermaid-svg-WZvCOXAME4DKYkox .icon-shape .label{text-anchor:middle;}#mermaid-svg-WZvCOXAME4DKYkox .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WZvCOXAME4DKYkox .rough-node .label,#mermaid-svg-WZvCOXAME4DKYkox .node .label,#mermaid-svg-WZvCOXAME4DKYkox .image-shape .label,#mermaid-svg-WZvCOXAME4DKYkox .icon-shape .label{text-align:center;}#mermaid-svg-WZvCOXAME4DKYkox .node.clickable{cursor:pointer;}#mermaid-svg-WZvCOXAME4DKYkox .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WZvCOXAME4DKYkox .arrowheadPath{fill:#333333;}#mermaid-svg-WZvCOXAME4DKYkox .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WZvCOXAME4DKYkox .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WZvCOXAME4DKYkox .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WZvCOXAME4DKYkox .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WZvCOXAME4DKYkox .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WZvCOXAME4DKYkox .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WZvCOXAME4DKYkox .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WZvCOXAME4DKYkox .cluster text{fill:#333;}#mermaid-svg-WZvCOXAME4DKYkox .cluster span{color:#333;}#mermaid-svg-WZvCOXAME4DKYkox div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WZvCOXAME4DKYkox .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WZvCOXAME4DKYkox rect.text{fill:none;stroke-width:0;}#mermaid-svg-WZvCOXAME4DKYkox .icon-shape,#mermaid-svg-WZvCOXAME4DKYkox .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WZvCOXAME4DKYkox .icon-shape p,#mermaid-svg-WZvCOXAME4DKYkox .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WZvCOXAME4DKYkox .icon-shape .label rect,#mermaid-svg-WZvCOXAME4DKYkox .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WZvCOXAME4DKYkox .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WZvCOXAME4DKYkox .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WZvCOXAME4DKYkox :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 入射光线
粗糙物体表面
散射光线
散射光线
散射光线
散射光线
图2:漫反射光线散射原理图,光线接触粗糙表面后全方位散射,无定向性,这也是漫反射与观测视角无关的根本原因。
漫反射的亮度变化严格遵循两大物理法则,也是代码实现的核心依据:
1. Lambert 余弦定律(角度衰减)
物体表面接收的光能量,由表面法线 与光照方向的夹角决定:光线垂直直射时能量最大、亮度最高;光线斜射时夹角越大,接收能量越少、画面越暗;背光面无光照,漫反射亮度为0。
2. 距离平方衰减(距离衰减)
点光源的能量会随传播距离均匀扩散,根据能量守恒定律,物体接收的光能量与「光源距离的平方」成反比,完美模拟现实中"远暗近亮"的光照规律。
📐 漫反射完整公式
I d i f f u s e = k d c d o t I l i g h t c d o t m a x ( 0 , v e c n c d o t v e c l ) c d o t f r a c 1 1 + f d c d o t d 2 I_{diffuse} = k_d cdot I_{light} cdot max(0,vec{n}cdotvec{l}) cdot frac{1}{1+f_d cdot d^2} Idiffuse=kdcdotIlightcdotmax(0,vecncdotvecl)cdotfrac11+fdcdotd2
-
k d k_d kd:漫反射系数,定义物体固有色,控制光线吸收与反射比例;
-
v e c n vec{n} vecn:物体表面单位法线向量, v e c l vec{l} vecl:指向光源的单位光照向量;
-
m a x ( 0 , c d o t ) max(0,cdot) max(0,cdot):剔除背光面负亮度,避免画面异常;
-
d d d:着色点到光源距离, f d f_d fd:距离衰减系数。
💻 漫反射核心代码实现
c++
// 计算漫反射:遵循Lambert定律+距离平方衰减
Color calcDiffuse(Vec3 point, Vec3 normal, PointLight light, Color kd) {
// 1. 求解光照方向向量并归一化(必须单位化,保证点积结果为余弦值)
Vec3 lightDir = (light.pos - point).normalize();
// 2. 计算着色点到光源距离,实现距离衰减
float dist = (light.pos - point).len();
float distAtten = 1.0f / (1.0f + light.falloff * dist * dist);
// 3. Lambert余弦计算,背光面亮度置0
float lambert = std::max(0.0f, normal.dot(lightDir));
// 4. 计算最终漫反射颜色
return kd * light.intensity * lambert * distAtten;
}
关键特性验证 :代码中未使用任何视线方向参数,完美印证「漫反射与观测角度无关」的核心特性。
✨ 高光 Specular:光滑材质的质感点睛之笔
高光是区分哑光与光滑材质的核心标识,常见于金属、镜面、抛光陶瓷、漆面等光滑物体表面。
其物理本质为镜面反射:光滑物体表面平整度极高,光线入射后不会杂乱散射,而是沿固定方向定向反射。只有当观测视角贴合反射路径时,人眼才能捕捉到明亮的高光光斑。
#mermaid-svg-JuCrF6CsAqcG3AOz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JuCrF6CsAqcG3AOz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JuCrF6CsAqcG3AOz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JuCrF6CsAqcG3AOz .error-icon{fill:#552222;}#mermaid-svg-JuCrF6CsAqcG3AOz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JuCrF6CsAqcG3AOz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JuCrF6CsAqcG3AOz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JuCrF6CsAqcG3AOz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JuCrF6CsAqcG3AOz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JuCrF6CsAqcG3AOz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JuCrF6CsAqcG3AOz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JuCrF6CsAqcG3AOz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JuCrF6CsAqcG3AOz .marker.cross{stroke:#333333;}#mermaid-svg-JuCrF6CsAqcG3AOz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JuCrF6CsAqcG3AOz p{margin:0;}#mermaid-svg-JuCrF6CsAqcG3AOz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JuCrF6CsAqcG3AOz .cluster-label text{fill:#333;}#mermaid-svg-JuCrF6CsAqcG3AOz .cluster-label span{color:#333;}#mermaid-svg-JuCrF6CsAqcG3AOz .cluster-label span p{background-color:transparent;}#mermaid-svg-JuCrF6CsAqcG3AOz .label text,#mermaid-svg-JuCrF6CsAqcG3AOz span{fill:#333;color:#333;}#mermaid-svg-JuCrF6CsAqcG3AOz .node rect,#mermaid-svg-JuCrF6CsAqcG3AOz .node circle,#mermaid-svg-JuCrF6CsAqcG3AOz .node ellipse,#mermaid-svg-JuCrF6CsAqcG3AOz .node polygon,#mermaid-svg-JuCrF6CsAqcG3AOz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JuCrF6CsAqcG3AOz .rough-node .label text,#mermaid-svg-JuCrF6CsAqcG3AOz .node .label text,#mermaid-svg-JuCrF6CsAqcG3AOz .image-shape .label,#mermaid-svg-JuCrF6CsAqcG3AOz .icon-shape .label{text-anchor:middle;}#mermaid-svg-JuCrF6CsAqcG3AOz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JuCrF6CsAqcG3AOz .rough-node .label,#mermaid-svg-JuCrF6CsAqcG3AOz .node .label,#mermaid-svg-JuCrF6CsAqcG3AOz .image-shape .label,#mermaid-svg-JuCrF6CsAqcG3AOz .icon-shape .label{text-align:center;}#mermaid-svg-JuCrF6CsAqcG3AOz .node.clickable{cursor:pointer;}#mermaid-svg-JuCrF6CsAqcG3AOz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JuCrF6CsAqcG3AOz .arrowheadPath{fill:#333333;}#mermaid-svg-JuCrF6CsAqcG3AOz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JuCrF6CsAqcG3AOz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JuCrF6CsAqcG3AOz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JuCrF6CsAqcG3AOz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JuCrF6CsAqcG3AOz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JuCrF6CsAqcG3AOz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JuCrF6CsAqcG3AOz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JuCrF6CsAqcG3AOz .cluster text{fill:#333;}#mermaid-svg-JuCrF6CsAqcG3AOz .cluster span{color:#333;}#mermaid-svg-JuCrF6CsAqcG3AOz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JuCrF6CsAqcG3AOz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JuCrF6CsAqcG3AOz rect.text{fill:none;stroke-width:0;}#mermaid-svg-JuCrF6CsAqcG3AOz .icon-shape,#mermaid-svg-JuCrF6CsAqcG3AOz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JuCrF6CsAqcG3AOz .icon-shape p,#mermaid-svg-JuCrF6CsAqcG3AOz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JuCrF6CsAqcG3AOz .icon-shape .label rect,#mermaid-svg-JuCrF6CsAqcG3AOz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JuCrF6CsAqcG3AOz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JuCrF6CsAqcG3AOz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JuCrF6CsAqcG3AOz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 入射光线
光滑物体表面
固定反射光线
观测视角
图3:高光镜面反射原理图,仅观测方向与反射方向重合时,才可看到高光亮斑。
高光的形态由**光泽度(Shininess)**参数绝对把控:
-
光泽度数值越大:高光光斑越小、边缘越锐利、质感越精致(适配金属、镜面);
-
光泽度数值越小:高光光斑越大、过渡越柔和(适配磨砂玻璃、抛光塑料)。
高光与观测视角强相关,这也是旋转金属模型时,高光光斑会随视角移动的核心原因(本节仅做原理铺垫,完整公式与代码将在下一节补齐)。
📍 核心易错点:着色 ≠ 阴影
绝大多数初学者都会混淆这两个核心概念,在此重点区分:
当前阶段的局部着色,仅计算「单个着色点本身的光影交互」,完全不考虑场景中其他物体的遮挡关系。
简单来说:
-
着色(Shading):计算单点像素的明暗、色彩、质感,赋予物体本身光影层次,无遮挡判断;
-
阴影(Shadow) :判断着色点是否被其他物体遮挡、无法接收光照,属于场景全局遮挡计算。
核心结论 :局部着色可以让物体有明暗、有质感,但无法生成阴影。阴影的映射、计算、渲染,是后续进阶渲染课程的核心内容,二者各司其职、不可混淆。
🌟 课程总结与下期预告
从扁平单调的几何色块,到层次丰富、质感逼真的三维画面,着色技术是真实感渲染的核心起点。
本次我们深度拆解了 Blinn-Phong 模型的底层逻辑:梳理了渲染流水线中着色的定位,详解了环境光补暗、漫反射塑质感、高光提层次的核心作用,同时搭配公式、代码、原理图,打通了「理论-数学-代码」的完整学习链路。
目前我们已完成环境光+漫反射两大核心分量的落地,补齐了物体基础光影与固有色。
下期预告 :我们将完整推导高光分量公式,融合三大光影分量,实现完整版 Blinn-Phong 着色模型,彻底区分金属、石膏、木头、陶瓷的材质差异,亲手渲染出具备逼真质感的三维场景🌌。

光影有迹,质感可循,以数学为笔,以光线为墨,解锁计算机图形学的视觉浪漫✨。