天天看點

在WPF中添加3D特性

原文: 在WPF中添加3D特性

35.4  在WPF中添加3D特性

本節介紹WPF中的3D特性,其中包含了開始使用該特性的資訊。

提示:

WPF中的3D特性在System.Windows.Media.Media3D命名空間中。

為了了解WPF中的3D特性,一定要知道坐标系統之間的差別。圖35-22顯示了WPF 3D中的坐标系統。原點位于中心。X軸的正值在右邊,負值在左邊。Y軸是垂直的,正值在上邊,負值在下邊。Z軸在指向觀察者的方向上定義了正值。

表35-9描述了最重要的類及其功能。

表  35-9

說    明
ViewPort3D ViewPort3D定義了3D對象的渲染表面。這個元素包含3D繪圖的所有可見元素
ModelVisual3D ModelVisual3D包含在ViewPort3D中,它包含了所有可見元素。可以給完整的模型指定變換
GeometryModel3D GeometryModel3D包含在ModelVisual3D中,它包含網格和材質
Geometry3D Geometry3D是一個抽象基類,定義了幾何形狀。派生于Geometry3D的類是MeshGeometry3D。使用MeshGeometry3D可以定義三角形的位置,建立3D模型
Material Material是一個抽象基類,定義了MeshGeometry3D指定的三角形的前邊和後邊。Material包含在GeometryModel3D中。.NET 3.5定義了幾個材質類,例如DiffuseMaterial、EmissiveMaterial和SpecularMaterial。根據材質的類型,以不同的方式計算燈光。EmissiveMaterial利用燈光的計算,使材質發出等于筆刷顔色的光。DiffuseMaterial使用漫射光,SpecularMaterial定義了鏡面發光模型。使用MaterialGroup類可以建立由其他材質合并而成的材質
Light Light是燈光的抽象基類。其派生類有AmbientLight、DirectionalLight、PointLight和SpotLight。AmbientLight是不自然的光,會近似照亮整個場景。使用這種光看不到邊界。DirectionalLight定義了定向光。太陽光就是一種定向光,光線來自一邊,此時可以看到邊界和陰影。PointLight是一種位于指定位置的光,會照亮所有的方向。SpotLight照亮指定的方向。這個光定義了一個圓錐,會得到一個發出光亮的區域
Camera Camera是錄影機的抽象基類,用于把3D場景映射為2D顯示。其派生類是PerspectiveCamera、OrthographicCamera和MatrixCamera。在PerspectiveCamera中,3D對象離得越遠就越小,這不同于OrthographicCamera,在Orthographic Camera中,錄影機的距離對對象的大小沒有影響。在MatrixCamera中,可以在矩陣中定義視圖和變換
Transform3D Transform3D是3D變換的抽象基類。其派生類是RotateTransform3D、ScaleTransform3D、TranslateTransform3D、MatrixTransform3D和Transform3D Group。TranslateTransform3D允許在x、y和z向上變換對象,ScaleTransform3D可以重置對象的大小。RotateTransform3D可以在x、y和z向上把對象旋轉指定的角度。Transform3DGroup可以合并其他變換效果

三角形

本節從一個簡單的3D示例開始。3D模型由三角形組成,是以最簡單的模型是一個三角形。三角形用MeshGeometry3D的Positions屬性定義。3個頂點都使用相同的z坐标-4,x、y坐标分别為-1-1、1-1和01。屬性TriangleIndices指定了逆時針的位置順序。使用這個屬性可以确定三角形的哪一邊是可見的。三角形的一邊顯示了用GeometryModel3D類的Meterial屬性定義的顔色,其他邊顯示了BackMeterial屬性定義的顔色。

用于顯示場景的錄影機位于坐标0,0,0,其方向指向0,0,-8。把錄影機的位置改變到左邊,矩形就移動到右邊,反之亦然。改變錄影機的y位置,矩形就會變大或變小。

這個場景中使用的光線是AmbientLight,它用白色光照亮了整個場景。圖35-23顯示了三角形的效果。

< Window x:Class="Triangle3D.Window1"
xmlns="        http://schemas.microsoft.com/winfx/2006/xaml/presentation         "
xmlns:x="        http://schemas.microsoft.com/winfx/2006/xaml         "
Title="3D" Height="300" Width="300" >
< Grid >
< Viewport3D >
< Viewport3D.Camera >
< PerspectiveCamera Position="0 0 0" LookDirection="0 0 -8" / >
< /Viewport3D.Camera >      
< ModelVisual3D >
< ModelVisual3D.Content >
< AmbientLight Color="White" / >
< /ModelVisual3D.Content >
< /ModelVisual3D >      
< ModelVisual3D >
< ModelVisual3D.Content >
< GeometryModel3D >
< GeometryModel3D.Geometry >
< MeshGeometry3D
Positions="-1 -1 -4, 1 -1 -4, 0 1 -4"
TriangleIndices="0, 1, 2" / >
< /GeometryModel3D.Geometry >
< GeometryModel3D.Material >
< MaterialGroup >
< DiffuseMaterial >
< DiffuseMaterial.Brush >
< SolidColorBrush Color="Red" / >
< /DiffuseMaterial.Brush >
< /DiffuseMaterial >
< /MaterialGroup >
< /GeometryModel3D.Material >
< /GeometryModel3D >
< /ModelVisual3D.Content >
< /ModelVisual3D >
< /Viewport3D >
< /Grid >
< /Window >      

1. 改變光線

圖35-23僅顯示了一個簡單的三角形,它與2D的效果相同。但是,下面将繼續添加3D特性。例如,用SpotLight元素把環境光改為聚光燈,就可以看到三角形的另一個外觀,使用聚光燈可以定義光源的位置和光線的照射方向。給光源的位置指定-1 1 2,光就位于三角形的左邊頂點處,其y坐标是三角形的高度。之後,光線向下向左照射。圖35-24顯示了三角形的新外觀。

< ModelVisual3D >
< ModelVisual3D.Content >
< SpotLight Position="-1 1 -2" Color="White"
Direction="-1.5, -1, -5" / >
< /ModelVisual3D.Content >
< /ModelVisual3D >      

2. 添加紋理

除了給三角形的材質使用純色筆刷之外,還可以使用其他筆刷,例如LinearGradient- Brush,如下面的XAML代碼所示。用DiffuseMeterial定義的LinearGradientBrush元素指定了黃色、橙色、紅色、藍色和紫羅蘭色的漸變點。要把使用這種筆刷的對象的2D表面映射到3D幾何體上,必須設定TextCoordinates屬性。TextCoordinates定義了2D點的集合,它可以映射到3D位置上。圖35-25顯示了示例應用程式中筆刷的2D坐标。三角形中的第一個位置-1-1映射到筆刷坐标0 1上,右下角的位置1 -1映射到筆刷的1 1上,即紫羅蘭色;0 1映射到0.5 0上。圖35-26顯示了材質為漸變筆刷的三角形,這裡也使用了環境光。

< ModelVisual3D >
< ModelVisual3D.Content >
< GeometryModel3D >
< GeometryModel3D.Geometry >
< MeshGeometry3D
Positions="-1 -1 -4, 1 -1 -4, 0 1 -4"
TriangleIndices="0, 1, 2"
TextureCoordinates="0 1, 1 1, 0.5 0" / >
< /GeometryModel3D.Geometry >      
< GeometryModel3D.Material >
< MaterialGroup >
< DiffuseMaterial >
< DiffuseMaterial.Brush >
< LinearGradientBrush StartPoint="0,0"
EndPoint="1,1" >
< GradientStop Color="Yellow" Offset="0" / >
< GradientStop Color="Orange" Offset="0.25" / >
< GradientStop Color="Red" Offset="0.50" / >
< GradientStop Color="Blue" Offset="0.75" / >
< GradientStop Color="Violet" Offset="1" / >
< /LinearGradientBrush >
< /DiffuseMaterial.Brush >
< /DiffuseMaterial >
< /MaterialGroup >
< /GeometryModel3D.Material >
< /GeometryModel3D >
< /ModelVisual3D.Content >
< /ModelVisual3D >      

可以用類似的方式添加文本和其他控件。為此,隻需用要繪制的元素建立VisualBrush。VisualBrush詳見第34章。

3. 3D對象

下面研究真正的3D對象:立方體。立方體由5個矩形組成:後面、前面、左面、右面和底面。每個矩形都由兩個三角形組成,因為這是網格的核心。在WPF和3D術語中,網格用于描述建立3D形狀的基本三角形。

下面是立方體中前面矩形的代碼,該矩形由兩個三角形組成。三角形的位置按TriangleIndies定義的逆時針設定。立方體的前面用紅色的筆刷繪制,後面用灰色筆刷繪制。這兩個筆刷都是SolidColorBrush類型,用Window的資源定義。

< !-- Front -- >
< GeometryModel3D >
< GeometryModel3D.Geometry >
< MeshGeometry3D
Positions="-1 -1 1, 1 -1 1, 1 1 1, 1 1 1,
-1 1 1, -1 -1 1"
TriangleIndices="0 1 2, 3 4 5" / >
< /GeometryModel3D.Geometry >
< GeometryModel3D.Material >
< DiffuseMaterial Brush="{StaticResource redBrush}" / >
< /GeometryModel3D.Material >
< GeometryModel3D.BackMaterial >
< DiffuseMaterial Brush="{StaticResource grayBrush}" / >
< /GeometryModel3D.BackMaterial >
< /GeometryModel3D >      

其他矩形非常類似,隻是在不同的位置上。下面是立方體左面的XAML代碼:

< !-- Left side -- >
< GeometryModel3D >
< GeometryModel3D.Geometry >
< MeshGeometry3D
Positions="-1 -1 1, -1 1 1, -1 -1 -1, -1 -1 -1, -1 1 1,
-1 1 -1"
TriangleIndices="0 1 2, 3 4 5" / >
< /GeometryModel3D.Geometry >
< GeometryModel3D.Material >
< DiffuseMaterial Brush="{StaticResource redBrush}" / >
< /GeometryModel3D.Material >
< GeometryModel3D.BackMaterial >
< DiffuseMaterial Brush="{StaticResource grayBrush}" / >
< /GeometryModel3D.BackMaterial >
< /GeometryModel3D >      

示例代碼為立方體的每個面定義了一個GeometryModel3D,僅是為了更好地了解代碼。隻要每個面都使用相同的材質,就可以定義一個網格,它包含立方體所有面的全部10個三角形。

所有的矩形都在Model3DGroup中組合,是以可以對立方體的所有面進行變換:

< !-- the model -- >
< ModelVisual3D >
< ModelVisual3D.Content >
< Model3DGroup >      
< ! - GeometryModel3D elements for every side of the box -- >      
< /Model3DGroup >      

使用Model3DGroup的Transform屬性,就可以變換這個組中的所有幾何體。下面使用RotateTransform3D定義一個AxisAngleRotation3D。要在運作期間旋轉立方體,Angle屬性要綁定到Slider控件的值上。

< !-- Transformation of the complete model -- >
< Model3DGroup.Transform >
< RotateTransform3D CenterX="0" CenterY="0" CenterZ="0" >
< RotateTransform3D.Rotation >
< AxisAngleRotation3D x:Name="axisRotation"
Axis="0, 0, 0"
Angle="{Binding Path=Value,
ElementName=axisAngle}" / >
< /RotateTransform3D.Rotation >
< /RotateTransform3D >
< /Model3DGroup.Transform >      

為了檢視立方體,需要一個錄影機。這裡使用PerspectiveCamera,是以立方體離錄影機越遠,就越小。錄影機的位置的方向在運作期間設定。

< !-- Camera -- >
< Viewport3D.Camera >
< PerspectiveCamera x:Name="camera"
Position="{Binding Path=Text,
ElementName=textCameraPosition}"
LookDirection="{Binding Path=Text,
ElementName=textCameraDirection}" / >
< /Viewport3D.Camera >      

應用程式使用兩個不同的光源,其中一個光源是DirectionalLight:

< !-- directional light -- >
< ModelVisual3D >
< ModelVisual3D.Content >
< DirectionalLight Color="White" x:Name="directionalLight" >
< DirectionalLight.Direction >
< Vector3D X="1" Y="2" Z="3" / >
< /DirectionalLight.Direction >
< /DirectionalLight >
< /ModelVisual3D.Content >
< /ModelVisual3D >      

另一個光源是SpotLight。使用這個光源可以突出顯示立方體的一個特定區域。SpotLight定義了屬性InnerConeAngle和OuterConeAngle,以指定完全照亮的區域:

< !-- spot light -- >
< ModelVisual3D >
< ModelVisual3D.Content >
< SpotLight x:Name="spotLight"
InnerConeAngle="{Binding Path=Value,
ElementName=spotInnerCone}"
OuterConeAngle="{Binding Path=Value,
ElementName=spotOuterCone}"
Color="#FFFFFF"
Direction="{Binding Path=Text, ElementName=spotDirection}"
Position="{Binding Path=Text, ElementName=spotPosition}"
Range="{Binding Path=Value, ElementName=spotRange}" / >
< /ModelVisual3D.Content >
< /ModelVisual3D >      

運作應用程式,就可以改變立方體的旋轉角度、錄影機和燈光,如圖35-27所示。

建立僅包含矩形或三角形的3D模型是很簡單的。不應手工建立更複雜的模型,而應使用對應的工具。WPF的3D工具在

www.codeplex/3DTools

上。