WPF 3D (System.Windows.Media.Media3D) 沒有線條、曲線、矩形,**所有物體皆由三角形組成**。三角形唯一確定一個平面,三角形集合可逼近任意立體。核心類 MeshGeometry3D 通過四個屬性定義幾何體:
| 屬性 | 類型 | 含義 |
|---|---|---|
| Positions | Point3DCollection | 所有頂點座標 (X,Y,Z),右手座標系:X右、Y上、Z向外 |
| TriangleIndices | Int32Collection | 三個一組的索引,引用 Positions 中頂點,定義三角形。逆時針順序為正面 |
| TextureCoordinates | PointCollection | 每個頂點對應的 2D 材質座標 (U,V∈[0,1]),(0,0)左上、(1,1)右下 |
| Normals | Vector3DCollection | 每個頂點法向量,決定光照反射。未提供時自動計算相鄰三角形平均法線 |
<MeshGeometry3D
Positions="-2 1 -1, 0 2 0, 2 1 -1, -2 -1 -1, 0 -2 0, 2 -1 -1"
TriangleIndices="0 3 1, 1 3 4, 1 5 2, 1 4 5"
TextureCoordinates="0 0, 0.5 0, 1 0, 0 1, 0.5 1, 1 1" />
DiffuseMaterial 用 VisualBrush 繪製 "Hello, World" 文字,背面紅色純色。MeshGeometry3D 僅適合簡單立方體、金字塔。MeshGeometry3D 是 sealed,無法繼承;Geometry3D 有 internal 建構函數,也無法直接繼承。ModelVisual3D 衍生類 + 依賴屬性ModelVisual3D?Media3D 命名空間中 唯一非 sealed、非 abstract 的具象類**。繼承它可直接放入 Viewport3D,擁有 Content (Model3D) 屬性,天然支援 XAML 實例化、資料綁定、動畫、樣式。
// 基類:統一管理 Geometry、Material、BackMaterial 依賴屬性
public abstract class ModelVisualBase : ModelVisual3D {
public static readonly DependencyProperty GeometryProperty = ...;
public static readonly DependencyProperty MaterialProperty = ...;
public static readonly DependencyProperty BackMaterialProperty = ...;
// PropertyChanged 回調觸發 RegenerateMesh()
}
// 圓柱體具體實現
public class Cylinder : ModelVisualBase {
// 幾何參數依賴屬性
public Point3D Point1 { get; set; } // 底面中心
public Point3D Point2 { get; set; } // 頂面中心
public double Radius1 { get; set; } // 底面半徑
public double Radius2 { get; set; } // 頂面半徑 (為 0 即圓錐)
public int Slices { get; set; } = 16; // 圓周分段
public int Stacks { get; set; } = 1; // 軸向分層
public enum TextureType { None, Drawing, Image }
public TextureType TextureType { get; set; }
public double Fold1 { get; set; } = 0.1; // 材質頂部折疊比例
public double Fold2 { get; set; } = 0.9; // 材質底部折疊比例
// 核心生成邏輯
protected override void RegenerateMesh() { ... }
}
void GeneratePositions() {
var mesh = (MeshGeometry3D)Geometry;
var points = mesh.Positions; // 重用現有集合
mesh.Positions = null; // 脫離觸發 Changed 事件
points.Clear();
// ... 計算頂點填充 points ...
mesh.Positions = points; // 重新掛載,單次觸發通知
}
new Point3DCollection(capacity)),避免擴容分配。RotateTransform3D、AxisAngleRotation3D 等轉換物件。Drawing (漸變/繪圖刷) → 三角形扇形映射,材質環繞頂底面 (圖 7 風格)。Image (位圖刷) → 矩形展開映射,避免頂底面額外接縫 (圖 8 風格)。None → 不生成 TextureCoordinates,純色/實體刷效能最佳。Point1→Point2 軸向旋轉基準向量)。
<pmg:Cylinder x:Name="cyl" Slices="32" TextureType="Image" Fold1="0.25" Fold2="0.75">
<pmg:Cylinder.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="https://example.com/texture.jpg" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</pmg:Cylinder.Material>
<pmg:Cylinder.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Axis="0 1 0" Angle="{Binding Value, ElementName=slider}" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</pmg:Cylinder.Transform>
</pmg:Cylinder>
Cylinder 精確對齊 Point1/Point2 端點,自動貼合無縫隙。Radius1/Radius2 獨立控制粗細,實現椅腿、椅背、扶手不同粗細。同樣模式衍生 Sphere、Tube、Pipe:
Sphere:參數 Center、Radius、PhiDiv/ThetaDiv,極座標生成。Tube:沿 3D 路徑 (Point3DCollection) 掃掠圓形剖面,需 Frenet 框架計算法向/切向。ModelVisualBase 確保依賴屬性、材質、轉換行為一致。RegenerateMesh,重用集合避免 GC 壓力。