一、功能及效果对照
-
程序在 3D 场景中显示一个浅蓝色的立方体,该立方体可绕 Y 轴旋转(通过下方的滚动条控制角度)。
-
三个按钮分别切换立方体的几何网格类型,演示顶点共享与法线设置对光照效果的影响:
- Shared Points:8 个顶点被多个三角形共享,但未指定法线,渲染结果通常不正确(全黑或异常)。
- Blended:8 个顶点,但手动指定了每个顶点的法线(不准确的平滑法线),导致表面呈现平滑着色(类似球体)。
- Faceted:每个面使用独立的顶点(共 24 个),每个顶点法线与面法线一致,呈现棱角分明的立体效果。
-
坐标轴用红(X)、绿(Y)、蓝(Z)三条线表示,辅助观察空间方位。
二、坐标轴的生成
-
第三方库 3DTools 中的 ScreenSpaceLines3D 可以绘制坐标轴。
该控件能在 3D 场景中绘制始终面对屏幕的线条。
-
但是WPF 的 3D 引擎(Viewport3D)没有直接提供画线图元,最直接的方式是用几何体(如长方体或圆柱)近似线条。
这种方法虽然无法实现屏幕对齐的"无限细线",但足以满足坐标轴指示需求,且完全内置于 WPF 中。
-
使用 纯 WPF 原生 3D 元素 模拟坐标轴:
- 定义了一个沿 X 轴方向的细长方体网格(AxisMesh),长度为 40,截面为 0.2×0.2。
- 该网格包含 24 个顶点(每个面 4 个独立顶点)和对应的法线,确保光照正确。
- 通过 RotateTransform3D 对该网格进行旋转,生成 Y 轴(绕 Z 轴旋转 -90°)和 Z 轴(绕 Y 轴旋转 90°),并赋予不同颜色材质。
- 坐标轴保持在原点,长度覆盖 -20 到 20
三、坐标轴网格构造详解
(以 AxisMesh 为例)
<MeshGeometry3D x:Key="AxisMesh"
Positions="
-20,-0.1,-0.1 20,-0.1,-0.1 20,0.1,-0.1 -20,0.1,-0.1 <!-- 前面 -->
-20,-0.1,0.1 -20,0.1,0.1 20,0.1,0.1 20,-0.1,0.1 <!-- 后面 -->
20,-0.1,-0.1 20,-0.1,0.1 20,0.1,0.1 20,0.1,-0.1 <!-- 右面 -->
-20,-0.1,-0.1 -20,0.1,-0.1 -20,0.1,0.1 -20,-0.1,0.1 <!-- 左面 -->
-20,0.1,-0.1 20,0.1,-0.1 20,0.1,0.1 -20,0.1,0.1 <!-- 上面 -->
-20,-0.1,-0.1 -20,-0.1,0.1 20,-0.1,0.1 20,-0.1,-0.1 <!-- 下面 -->
"
TriangleIndices="0,1,2 0,2,3 4,5,6 4,6,7 8,9,10 8,10,11
12,13,14 12,14,15 16,17,18 16,18,19 20,21,22 20,22,23"
Normals="0,0,-1 ..." />
-
每个面独立占据 4 个连续顶点,并指定该面的法线方向(如前面为 (0,0,-1))。
-
每个面由两个三角形组成(索引顺序保证逆时针,法线向外)。
-
由于每个面顶点独立,旋转后法线会随整体几何体正确变换,无需额外处理。
四、为什么会产生不同的渲染效果
1、SharedPoints
(共享顶点,无法线)

-
WPF 在无法线时会尝试自动计算,但默认情况下(无法线)光照计算会失效,因为法线向量为零向量,导致物体呈现黑色或不受光影响。实际上,这种设置下渲染出的立方体是全黑或仅有环境光,无法看出立体感。
-
演示不指定法线时会出现光照异常,强调法线对于 3D 渲染的重要性。
2、Blended
(共享顶点 + 手动法线)

-
手动指定了 8 个法线向量,但注意这些法线并不是该顶点在真实立方体表面的正确法线。
真实立方体的顶点法线应是该顶点相邻所有面法线的平均(用于平滑着色),但这里的法线值混乱(例如 (0,1,0) 和 (1,0,0) 反复出现),并没有正确计算。
-
然而,正因为有了法线值,WPF 会使用它们进行光照计算,每个顶点只关联一个法线,因此不同面共享的顶点拥有相同的法线,导致光照在面之间平滑过渡,呈现类似"球体"的柔和效果,即平滑着色(尽管法线不准确,但视觉效果是平滑的。
-
演示即使法线不准确,只要提供了法线,就能产生光照效果,并且由于顶点共享,会得到平滑插值着色。
3、Faceted
(独立顶点,自动法线)

-
法线:未显式指定。
但由于每个面的顶点都是独立的(不与其他面共享),WPF 在渲染时会根据每个三角形的三个顶点坐标自动计算面法线(通过叉积)。因为每个面的四个顶点只属于该面,所以该面的两个三角形的法线完全一致,且垂直于该面。于是每个面都拥有独立的、正确的面法线,光照在每个面上均匀,相邻面之间法线跳跃,产生棱角分明的平坦着色效果,即"面片状"立方体。
-
演示独立顶点时,WPF 能自动生成正确的面法线,实现清晰锐利的棱边效果,这是 3D 建模中最常见的"硬边"处理方式。
五、对比
| 特性 | SharedPoints | Blended | Faceted |
|---|---|---|---|
| 顶点数量 | 8(共享) | 8(共享) | 24(独立) |
| 顶点共享 | 是 | 是 | 否 |
| 法线来源 | 无(光照失效) | 手动指定(但不精确) | 自动计算(每个面独立) |
| 着色效果 | 黑色/无光照 | 平滑(类似球体) | 棱角分明(硬边) |
| 三角形索引 | 引用 8 个顶点 | 引用 8 个顶点 | 引用连续顶点,无共享 |
| 教学意义 | 强调法线必要性 | 展示平滑着色原理 | 展示平坦着色与硬边 |
六、法线设置原理
1、为什么 SharedPoints 没有法线就会黑?
- WPF 的光照模型需要每个顶点处的法线方向来计算漫反射和镜面反射。若法线为零向量,则光线与表面无夹角,反射亮度为零,物体呈现全黑(除非有环境光)。
2、为什么 Blended 中法线不准确但仍有颜色?
- 因为法线向量非零,即便不准确,WPF 仍会用它计算光照,产生随角度变化的亮度,但由于法线在顶点间共享,着色器会在三角形面内插值这些法线,形成平滑渐变。
3、为什么 Faceted 能自动生成正确法线?
- 当 WPF 遇到未指定法线的网格时,会为每个三角形计算其面法线,并将该法线赋给三角形的三个顶点。由于每个顶点只属于一个三角形(独立顶点),该顶点的法线就是该面的法线,从而得到硬边效果。
七、源码下载
https://download.csdn.net/download/dalong10/93227994