為了使基於2D的紋理顯示在3D對象中,我們必須定義3D Mesh對象的紋理貼圖座標。在WPF中,此項功能則通過MeshGeometry3D.TextureCoordinates屬性。
2D紋理的對應座標和WPF的LinearGradientBrush的StartPoint和EndPoint一樣。
來自MSDN關於LinearGradientBrush的StartPoint的說明:
(0,0)代表整個圖形的左上方,(1,1)則代表右下角。(0,1)則代表左下角……當然單位是相對的,可以用0到1之間的小數來代表中間的相對位置。
對於最簡單的沒有共用頂點的Mesh定義(MeshGeometry3D.Positions屬性沒有共用點),TextureCoordinates則對應Mesh中的每一個三角形的座標相對應,當然這個和MeshGeometry3D.TriangleIndices屬性定義相關。
比如定義一個簡單的3D平面矩形,首先一次根據三角形分布定義MeshGeometry的外殼。此時紋理座標要根據三角形的分布位置來定義紋理座標位置,比如第一個點是0, 0, 0,顯然對應3D空間內矩形的左下角,那麼第一個對應的TextureCoordinates是0 1,以此類推,這樣定義好整個平面。
<MeshGeometry3D Positions="0 0 0, 5 5 0, 0 5 0, 0 0 0, 5 0 0, 5 5 0"
TriangleIndices="0 1 2 3 4 5"
TextureCoordinates="0 1, 1 0, 0 0,
0 1, 1 1, 1 0"/>
最終紋理被正確顯示:
如果我把上面的三角形的材質定義翻轉一下(由於是逆時針定義,翻轉可以通過調換前兩個點)
<MeshGeometry3D Positions="0 0 0, 5 5 0, 0 5 0, 0 0 0, 5 0 0, 5 5 0"
TriangleIndices="0 1 2 3 4 5"
TextureCoordinates="1 0, 0 1, 0 0,
0 1, 1 1, 1 0"/>
結果就是:
對於有共用頂點的Mesh定義(MeshGeometry3D.TriangleIndices屬性來指定頂點),紋理座標則直接對應每個定義在3D圖形中的位置,還是上面那個例子,定義一個3D平面矩形,四個點,則四個對應的紋理位置相對座標。
如下代碼:
<MeshGeometry3D Positions="0 0 0, 5 0 0, 5 5 0, 0 5 0"
TriangleIndices="0 1 2 0 2 3"
TextureCoordinates="0 1, 1,1 1,0 0,0"/>
輸出結果和上面的一致!
當然上面的一切都為了簡單易懂而在3D空間內做平面圖形,下面用上述知識在一個3D的帶紋理的錐形(用LinearGradientBrush):
或者ImageBrush:
完整代碼:
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="0 0 20" LookDirection="0 0 -2"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<!-- 通過AmbientLight和DirectionalLight的結合,我們可以讓紋理更清晰同時不缺乏陰影製作效果 -->
<AmbientLight Color="#555555"/>
<DirectionalLight Direction="1,0,-7"
Color="White"/>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="0,5,0 -5,-5,0 0,0,5 -5,-5,0 5,-5,0 0,0,5 0,0,5 5,-5,0 0,5,0"
TriangleIndices="0 1 2 3 4 5 6 7 8"
TextureCoordinates="0,0 0,1 1,1 0,0 0,1 1,1 0,0 0,1 1,1"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="YellowGreen" Offset="0"/>
<GradientStop Color="Green" Offset="1"/>
</LinearGradientBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
通過替換DiffuseMaterial的Brush屬性,讀者可以使用其他紋理。