WPF:3D顶点共享与法线设置对光照效果的影响

一、功能及效果对照

  • 程序在 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
相关推荐
摩尔线程6 小时前
摩尔线程LiteGS入选ECCV 2026 高质量3DGS训练迎来效率突破
3d·摩尔线程
LateFrames9 小时前
CT(DCM)外轮廓实时识别 → 逐层拼3D → 导出STL到Blender
图像处理·3d·可视化·医疗·ct重建
柔蘭12 小时前
WPF中的CommunityToolkit.Mvvm框架
wpf
云飞云共享云桌面1 天前
广东精密机械设备工厂8-10人共享一台SolidWorks设计服务器
运维·服务器·3d·自动化·汽车·制造
AI视觉网奇1 天前
bambu-studio-ai 踩坑实战笔记
人工智能·3d
aGdF8E3gQ1 天前
【Application Insights】采样率对Function App日志收集的影响和解决方法
python·flask·wpf
MagicUrban1 天前
经纬管网MagicPipe3D V3.8.1发布,参数化自主可控三维管线建模工具
3d·gis·智慧城市·bim·地下管网
LONGZETECH1 天前
传统实训 vs 仿真实训:从技术架构拆解新能源汽车教学的范式之变
c语言·3d·unity·架构·汽车
程序员-Benothing2 天前
如何实现高并发系统订单30分钟自动关闭?
开发语言·c#·wpf