引言
在Windows Presentation Foundation (WPF) 中创建三维(3D)图形是一项既有趣又具有挑战性的任务。为了帮助开发者更好地理解如何使用WPF进行3D图形的渲染,本文将深入探讨GeometryModel3D类及其相关的材质和光源设置。
1、GeometryModel3D类简介
GeometryModel3D类是WPF中用于定义3D对象的基本单元之一,它包含了三个关键属性:Geometry、Material以及BackMaterial。Geometry属性通过MeshGeometry3D对象定义了3D对象的形状,而Material和BackMaterial则负责定义这些形状表面的外观特性。
- Geometry:使用MeshGeometry3D对象来定义3D模型的具体几何形状。
- Material:决定了物体正面的颜色或纹理,支持多种类型的材质效果。
- BackMaterial:决定了物体背面的颜色或纹理,如果不指定,则从背面观察时该物体会变得不可见。
2、材质类详解
WPF提供了四种继承自抽象的Material类的材质类型,每种类型都有其独特的视觉表现:
- DiffuseMaterial:模拟现实世界中最常见的无光泽表面,光线在其表面上均匀散射。
- SpecularMaterial:创造有光泽且高亮度的外观,如同金属或玻璃般反射光线。
- EmissiveMaterial:赋予物体自身发光的能力,但这种光不能照亮其他物体。
- MaterialGroup:允许组合多种材质以实现更复杂的视觉效果。
其中,DiffuseMaterial是最常用的材质类型,因为它能够最真实地模拟大多数日常材料的外观。
注意: DiffuseMaterial类提供了Brush属性,该属性获取希望用于绘制3D对象表面的Brush对象(如果使用除了SolidColorBrush画刷外的其他画刷,就需要设置MeshGeometry3D.TextureCoordinates属性,定义将画刷映射到对象上的方式,否则就会照成图像无法正确渲染颜色)。
3、设置材质示例
以下是一个简单的XAML代码片段,展示了如何为一个三角形配置黄色的DiffuseMaterial材质:
xml
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-1,0,0 0,1,0 1,0,0" TriangleIndices="0,2,1" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Red" />
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
这段代码创建了一个简单的三角形,并将其正面颜色设置为红色。由于没有设置BackMaterial属性,从背面观察时这个三角形将消失不见。

4、WPF中的光照模型
在Windows Presentation Foundation (WPF) 中,为了创建一个视觉效果逼真的已着色的3D对象,理解并应用光照模型是至关重要的。本文将探讨如何使用WPF中的光照系统来增强你的3D场景,并解释一些关键概念和简化处理。
a、光照基础
基本的概念是在3D场景中添加一或多个光源,然后根据选择的灯光类型、位置、方向以及强度来照亮对象。尽管WPF的光照模型被设计为模拟现实世界的光照行为,但需要注意的是,它与真实世界中的光照行为并不完全相同。
b、 简化处理
由于计算真实的灯光反射是一项处理器密集型任务,WPF在其光照系统中进行了一些简化以保证效率:
- 每个对象独立计算:从一个对象反射的灯光不会影响另一个对象。同样地,一个对象不会在另一个对象上投射阴影。
- 顶点光照计算:对于每个三角形的每个顶点进行灯光计算,然后在三角形表面插值。这意味着WPF决定了每个拐角的灯光强度,然后混合这些灯光强度来填充整个三角形。这种设计方式意味着,如果形状由很少的三角形组成,可能无法正确地实现照明效果。为了达到更好的光照效果,需要将形状细分为数百个甚至数千个三角形。
c、 实现理想的光照效果
要获得精确的光照效果,可能需要结合使用多种光源、不同的材质,甚至是添加额外的形状。这是3D场景设计艺术的一部分,通过实验和调整来达到期望的效果。
注意事项 即使没有提供光源,3D对象依然是可见的。然而,在没有光源的情况下,所看到的只是纯黑色的轮廓。因此,添加至少一个光源是必要的,以便观察到对象的真实颜色和纹理。
5、WPF中的灯光类与DirectionalLight详解
📌 四种灯光类
灯光类名称 | 说明 |
---|---|
DirectionalLight | 使用沿着指定方向传播的平行光线填充整个场景,类似于太阳光 |
AmbientLight | 提供均匀散射的光源,照亮场景中所有对象,不产生阴影或方向性 |
PointLight | 从空间中某一点向各个方向辐射光线,类似灯泡发出的光 |
SpotLight | 从一个点出发,以锥形方式向外发射光线,类似聚光灯 |
✅ DirectionalLight:最常用的光源类型
在实际开发中,DirectionalLight
是最常用的一种光源类型,尤其适用于模拟来自遥远光源(如太阳)的光照效果。它发出的是平行光线 ,并且覆盖整个3D空间。
📷示例代码:
xml
<DirectionalLight Color="White" Direction="-1,-1,-1" />
- Color:设置光源的颜色,此处为白色。
- Direction:定义光线的方向向量,表示光线从右上前方到左下后方传播。
⚠️ 注意:计算灯光方向时,向量的角度是关键,长度无关紧要 。例如,方向向量
(-2, -2, -2)
和标准化后的(-1, -1, -1)
效果相同,因为它们代表相同的光照角度。

csharp
<!--相机-->
<Viewport3D.Camera>
<PerspectiveCamera Position="10,10,10" LookDirection="-10,-10,-10" UpDirection="0,0,1" FieldOfView="10">
<PerspectiveCamera.Transform>
<RotateTransform3D CenterX="0" CenterY="0" CenterZ="0">
<RotateTransform3D.Rotation>
<!--视野可以绕物体中心轴旋转-->
<AxisAngleRotation3D Axis="0 0 1" Angle="0"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</PerspectiveCamera.Transform>
</PerspectiveCamera>
</Viewport3D.Camera>
<!--光源 离散的白色光源-->
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<AmbientLight Color="#999" />
<!--点光源-光影层次感-->
<PointLight Color="#DDD" Position="-10,10,-10"/>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-1,0,0 0,1,0 1,0,0" TriangleIndices="0,2,1" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Red" />
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>

🔍 光照角度与表面着色的关系
在这个示例中,光源的方向不是完全垂直于三角形表面(即未使用 (0, 0, -1)
),而是有一定倾斜角度(如 (-1, -1, -1)
)。这种设计是有意为之的,目的是为了让三角形表面呈现出更丰富的明暗变化,从而提升视觉效果。
💡 小贴士:定向光 vs 太阳光
- 定向光非常适合用来模拟太阳光。
- 因为其光线是平行的、无衰减的,因此特别适合用于大范围的室外场景渲染。
6、计算相机的位置
需要协调设置Position和LookDirection属性。如果使用 Position属性移动了摄像,但没有使用LookDirection属性在正确的方向上转回摄像机以进行补偿,就看不到在3D场景中创建的内容。为了确保正确地设置摄像机的方向,应选择一个希望从摄像机进行观察的点。然后可使用下面的公式计算观察方向:
CameraLookDirection = CenterPointofInterest - CameraPosition
在三角形示例中,使用位置(-2,2,2)将摄像机放到左上角。假定希望聚焦在原点(0,0,0),该点位于三角形底边的中点,应当使用下面这个观察方向:
CameraLookDirection = (0, 0, 0) - (-2, 2, 2)= (2, -2, -2)
这个方向相当于法线向量(1,-1,-1),因为它们描述的方向是相同的。DirectionalLight
类的Direction属性一样,重要的是向量的方向,而其长度并不重要。一旦设置 Position和LookDirection属性,可能还希望设置UpDirection属性。UpDirection属性决定了摄像机的倾斜角度。通常将UpDirection属性设置为(0,1,0),这意味着向量垂直向上。如下图所示:

7、总结
在WPF的3D图形编程中,合理选择和配置光源是创建真实感视觉效果的关键。通过掌握 DirectionalLight 的使用方法及其特性,开发者可以轻松构建出自然且富有层次感的光照场景。同时,理解其他三种光源(如环境光、点光源、聚光灯)的特性和应用场景,将有助于打造更加丰富和动态的3D界面。