3D開發基礎知識和簡單示例


引言

222249124196156

現在物聯網概念這么火,如果監控的信息能夠實時在手機的客服端中以3D形式展示給我們,那種體驗大家可以發揮自己的想象。

image

那生活中我們還有很多地方用到這些,如上圖所示的Kinect 在醫療上的應用,當然還有體感游戲等等。

 

3D 用來增加視覺效果,給人以更加直觀,真實的感覺。

3D如此美妙,那我們在WPF中又該從何處入手開啟我們的3D編程旅程?

 

WPF中3D開發技術的基礎知識應該有以下幾點:

  • 3D開發基礎知識
  • WPF中3D開發的基礎元素(Elements)
  • WPF中3D變換和動畫
  • 常用輔助類

3D開發基礎知識

坐標系 Coodinate System

WPF中二維圖形的坐標系將原點定位在呈現區域(通常是屏幕)的左上角。 在二維系統中,x 軸上的正值朝右,y 軸上的正值朝下。而在三維坐標系中,原點位於呈現區域的中心,x 軸上的正值朝右,但是 y 軸上的正值朝上,z 軸上的正值從原點向外朝向觀察者。傳統的二維和三維坐標系表示形式如下圖

 

CoordinateSystem

由這些軸定義的空間是三維對象在 WPF 中的固定參考框架。

當您在該空間中生成模型並創建光源和照相機以查看這些模型時,一定要在向每個模型應用變換時,將固定參考框架或“全局空間”與您為該模型創建的局部參考框架區分開。

另請記住,根據光源和照相機設置,全局空間中的對象可能會看上去完全不同或者根本不可見,但是照相機的位置不會改變對象在全局空間中的位置。

3D的世界都是三角形的王國

 

如下圖:

 

triangle_model

在3D的世界里所有的東西都是用一些列的“三角形”來描述的。那你一定會問為什么是“三角形”?

原因是三角形是用來描述一個平面的最細微的幾何體,渲染引擎能夠依據每個三角形的材質以及場景中的燈光角度來計算它的顏色。

其實就是三點確定一個平面,在一個平面上做計算最簡單,考慮的因素最少。如果用三維空間中大於三個點來做渲染基本單位,那么如果這些點不在同一個平面上的話,渲染計算是相當復雜的。

3D 對象的表面叫做網格(Mesh),一個網格是由許多3D 點來定義的,這些點叫做頂點(vertices)。這些頂點通過纏繞模式(winding pattern)連接在一起組成一個一個的三角形(facet)(如下圖箭頭所示)。

vertex

三角形(facet)又分為“前”和“后”兩面,能看到的部分為前面,看不到的部分為后面。

那怎么判定是前面還是后面?

如果三角形的三個點順時針方向組成的面那么這個面就是前面。如下圖

Facet

按照0,1,2的順序三個點組成了的這個面是上面我們可以看到

目前主流(Direct3D and/or OpenGL)都會把三角形分為兩個面(前面和后面)。

 

為幫助大家記憶(facet)“前面”的三維坐標,大拇指是Z+的方向正對着我們(及前面圖示中Up方向),食指是y+方向,而中指是Y+方向。(+表示正數的方向)

righthandrule

 

 

WPF 3D的關鍵元素(Elements)

maciej-progtech-wpf-3d-projection-2d

3D 畫布

要畫畫總的有個畫布,WPF中呈現3D也需要一個類似功能的東西。Viewport3D(投影3D場景的平面)是WPF中的3D畫布,類於2D中的Canvas。其實WPF中也有一個名字開起來類似的東東Viewbox ,不過和3D沒啥關系,它處理的都是2D的。

1

2

3

<Viewport3D>

Children…

</Viewport3D>

該圖形系統將 Viewport3D 視為一個像 WPF 中的許多其他元素一樣的二維可視化元素。 Viewport3D充當三維場景中的窗口(即視區)。 更准確地說,它是三維場景所投影到的圖面。

相機

處理二維對象的開發人員習慣於將繪圖基元置於二維屏幕上。 當您創建三維場景時,一定要記住您實際上是要創建三維對象的二維表示形式。 由於三維場景的外觀會因觀察者的觀察位置不同而異,因此您必須指定觀察位置。而觀察位置就是由相機(Camera 類)來為三維場景指定的。

 

另一種理解三維場景在二維圖上的描述方法就是,將3D場景投影到一個2D平面的表面。如下圖:

3d2d

從坐標系的角度來看下我們的ProjectionCamera(透視相機)和3D模型的位置,以及2D 投影屏幕的位置關系:

IC210304

更詳細的圖解如下:

Graphics3D_ClipVolume

 

ProjectionCameraNearPlaneDistanceFarPlaneDistance 屬性限制照相機的投影范圍。由於照相機可以位於場景中的任何位置,因此照相機實際上可能會位於模型內部或者緊靠模型,這使正確區分對象變得很困難。 通過 NearPlaneDistance,可以指定一個距離照相機的最小距離,超過該距離后即不繪制對象。 相反,使用 FarPlaneDistance,可以指定一個距離照相機的距離(即,在超過該距離后將不繪制對象),從而確保因距離太遠而無法識別的對象將不包括在場景中。

 

對比WPF中兩種相機

  • PerspectiveCamera 可以指定不同的投影及其屬性以更改觀察者查看三維模型的方式。
  • OrthographicCamera 指定三維模型到二維可視化圖面上的正投影與其他照相機一樣,它指定位置、觀察方向和“向上”方向。 但是,與 PerspectiveCamera 不同的是,OrthographicCamera 描述了不包括透視收縮的投影。或者說OrthographicCamera 描述了一個側面平行的取景框,而不是側面匯集在場景中一點的取景框。

下圖演示使用PerspectiveCameraOrthographicCamera 查看同一模型時的不同效果。

 

42450b_figure2

 

燈光

和現實生活中一樣,如果沒有光我們將什么也看不到。因此我們需要在我們的場景中至少放置一盞燈來照亮我們場景中的模型。

WPF中支持不同類型的光源,如下:

  • AmbientLight(環境光) 它所提供的環境光會照亮所有的對象,而不考慮對象的位置或方向。
  • DirectionalLight(平行光) 像遠處的光源那樣照亮(如太陽光)。將方向光的 Direction 指定為 Vector3D,但是沒有為方向光指定位置。
  • PointLight(點光源) 像近處的光源那樣照亮。 PointLight 具有一個位置並從該位置投射光。 場景中的對象是根據對象相對於光源的位置和距離而被照亮的。 PointLightBase 公開 Range 屬性,該屬性確定一個距離,超過該距離后模型將無法由光源照亮。 PointLight 還公開了多個衰減屬性,這些屬性確定光源的亮度如何隨距離的增加而減小。 您可以為光源的衰減指定恆定、線性或二次內插算法。
  • SpotLight(聚光燈) 從 PointLight 繼承。 Spotlight 的照亮方式與 PointLight 類似,但是它既具有位置又具有方向。 它們在 InnerConeAngle 和 OuterConeAngle 屬性所設置的錐形區域(以度為單位指定)中投射光。

下圖展示了各種光源的情況:

lights

光源是 Model3D 對象,因此您可以轉換光源對象並對光源屬性(包括位置、顏色、方向和范圍)進行動畫處理。

組合燈光的效果

  • Ambient color : Red
  • Difusse color : Red

emisive-ambient-specular-diffuse_3_m

 

3D模型

說了半天啦,怎么主角還沒出現了 ??

對,所有的一切都服務於我們的3D Model。

image

Model3D 是三維對象的抽象基類。若要生成三維場景,需要一些要查看的對象,而且構成場景圖的對象必須派生自 Model3D。 目前,WPF 支持用 GeometryModel3D 對幾何形狀進行建模。 此模型的 Geometry 屬性采用網格基元。

要生成模型,首先生成一個基元或網格。 三維基元是一系列構成單個三維實體的頂點。 大多數三維系統都提供在最簡單的閉合圖(由三個頂點定義的三角形)上建模的基元。 由於三角形的三個點在一個平面上,因此您可以繼續添加三角形,以便對網格這樣較為復雜的形狀建模。

WPF 三維系統目前提供 MeshGeometry3D 類,使用該類可以指定任何幾何形狀;它目前不支持預定義的三維基元(如球體和立方體)。 首先通過將三角形頂點的列表指定為它的Positions 屬性來創建 MeshGeometry3D。 每個頂點都指定為 Point3D。 (在可擴展應用程序標記語言 (XAML) 中,將該屬性指定為三個一組的數字列表,每組中的三個數字表示每個頂點的坐標)。根據網格的幾何形狀,網格可能會由多個三角形組成,其中的一些三角形共用相同的角(頂點)。 若要正確地繪制網格,WPF 需要有關哪些頂點由哪些三角形共用的信息。 可以通過指定具有 TriangleIndices 屬性的三角形索引列表來提供此信息。 此列表指定在 Positions 列表中指定的點將按哪種順序確定三角形。

 

材質(Material )

我們生活在多彩的世界中,也不能讓我們的3D模型如此單調,這時我們就用到了材質。

imageimage

在二維中,可以使用 Brush 類來向屏幕中的區域應用顏色、圖案、漸變或其他可視化內容。 但是,三維對象的外觀是照明模型的功能,而不只是應用於它們的顏色或圖案。 實際對象的圖面質量不同,它們反射光的方式也會有所不同:光亮的圖面與粗糙或不光滑的圖面看上去不同,某些對象似乎可以吸收光,而某些對象似乎能夠發光。 您可以向三維對象應用與應用於二維對象的完全相同的畫筆,但是您不能直接應用它們。

Material 的具體子類用來確定模型圖面的某些外觀特征,每個子類還提供一個可以向其傳遞 SolidColorBrush、TileBrush 或 VisualBrush 的 Brush 屬性。

  • DiffuseMaterial 使用 DiffuseMaterial 與直接針對二維模型使用畫筆非常相似;模型表面不反射光,就好像是自發光一樣。使用 DiffuseMaterial 與直接針對二維模型使用畫筆非常相似;模型表面不反射光,就好像是自發光一樣
  • SpecularMaterial 可以通過為 SpecularPower 屬性指定一個值來設置系統將為紋理的反射特質(或“發光”)建議的度數。
  • EmissiveMaterial  可以指定將應用紋理,就好像模型所發出的光與畫筆的顏色相同。這不會使模型成為光源;但是,它參與陰影設置的方式將不同於用 DiffuseMaterial 或 SpecularMaterial 設置紋理時的情況。

 

42370_figure6

 

為進一步提高性能,可以從場景中精選 GeometryModel3D 的背面(由於它們相對於照相機位於模型的背面,因此您將看不到這些面)。若要指定要應用於模型(如飛機)背面的Material,請設置模型的 BackMaterial 屬性。

為了實現某些圖面質量(如發光或發射效果),您可能希望向模型連續應用幾個不同的畫筆。 可以使用 MaterialGroup 類來應用和重用多個 Material。 MaterialGroup 的子級在多個呈現過程中按照從頭到尾的順序來應用。

 

WPF中3D變換和動畫

RotatingTransTetra

變換

當您創建模型時,它們在場景中具有固定的位置。為了在場景中移動、旋轉這些模型或者更改這些模型的大小而更改用來定義模型本身的頂點是不切實際的。 相反,您可以像在二維模型一樣應用轉換。

每個模型對象都有一個可用來對模型進行移動、重定向或調整大小的 Transform 屬性。 當您應用轉換時,實際上是按照由Transform 屬性指定的向量或值來偏移模型的所有點。

也就是說變換了定義模型的坐標系(“模型空間”)而模型所在的整個場景的坐標系(“全局空間”)卻沒有改變,從而實現了3D模型的變換。

動畫

WPF 三維實現與二維圖形參與同一個計時和動畫系統。也就是說,要對三維場景進行動畫處理,也就是對其模型的屬性進行動畫處理。 可以直接對基元的屬性進行動畫處理,但是通常很容易更改模型位置或外觀的變換進行動畫處理。 由於可以向 Model3DGroup 對象及其各個模型應用轉換,因此可以向 Model3DGroup 中某個對象應用一組動畫,也可以向這一組子對象應用一組動畫。 還可以通過對場景的照明屬性進行動畫處理來實現各種可視化效果。 最后,您可以選擇通過對照相機的位置或視野進行動畫處理來對投影本身進行動畫處理。

 

要對 WPF 中的對象進行動畫處理,可以創建時間線、定義動畫(實際上是隨着時間的推移而更改某個屬性值)並指定要向其應用動畫的屬性。 由於三維場景中的所有對象都是Viewport3D 的子節點,因此要應用於場景的任何動畫所面向的屬性都是 Viewport3D 的屬性。

 

常用輔助類

  1. HelixToolkit
  2. 3DTool
  3. slimdx

實例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

<UserControl x:Class="HostingWpfUserControlInWf.UserControl1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    >

 

    <Grid>

 

      <!-- Place a Label control at the top of the view. -->

      <Label

                HorizontalAlignment="Center"

                TextBlock.TextAlignment="Center"

                FontSize="20"

                Foreground="Red"

                Content="Model: Cone"/>

 

      <!-- Viewport3D is the rendering surface. -->

      <Viewport3D Name="myViewport" >

 

        <!-- Add a camera. -->

        <Viewport3D.Camera>

          <PerspectiveCamera

                        FarPlaneDistance="20"

                        LookDirection="0,0,1"

                        UpDirection="0,1,0"

                        NearPlaneDistance="1"

                        Position="0,0,-3"

                        FieldOfView="45" />

        </Viewport3D.Camera>

 

        <!-- Add models. -->

        <Viewport3D.Children>

 

          <ModelVisual3D>

            <ModelVisual3D.Content>

 

              <Model3DGroup >

                <Model3DGroup.Children>

 

                  <!-- Lights, MeshGeometry3D and DiffuseMaterial objects are added to the ModelVisual3D. -->

                  <DirectionalLight Color="#FFFFFFFF" Direction="3,-4,5" />

 

                  <!-- Define a red cone. -->

                  <GeometryModel3D>

 

                    <GeometryModel3D.Geometry>

                      <MeshGeometry3D

    Positions="0.293893 -0.5 0.404509  0.475528 -0.5 0.154509  0 0.5 0  0.475528 -0.5 0.154509  0 0.5 0  0 0.5 0  0.475528 -0.5 0.154509  0.475528 -0.5 -0.154509  0 0.5 0  0.475528 -0.5 -0.154509  0 0.5 0  0 0.5 0  0.475528 -0.5 -0.154509  0.293893 -0.5 -0.404509  0 0.5 0  0.293893 -0.5 -0.404509  0 0.5 0  0 0.5 0  0.293893 -0.5 -0.404509  0 -0.5 -0.5  0 0.5 0  0 -0.5 -0.5  0 0.5 0  0 0.5 0  0 -0.5 -0.5  -0.293893 -0.5 -0.404509  0 0.5 0  -0.293893 -0.5 -0.404509  0 0.5 0  0 0.5 0  -0.293893 -0.5 -0.404509  -0.475528 -0.5 -0.154509  0 0.5 0  -0.475528 -0.5 -0.154509  0 0.5 0  0 0.5 0  -0.475528 -0.5 -0.154509  -0.475528 -0.5 0.154509  0 0.5 0  -0.475528 -0.5 0.154509  0 0.5 0  0 0.5 0  -0.475528 -0.5 0.154509  -0.293892 -0.5 0.404509  0 0.5 0  -0.293892 -0.5 0.404509  0 0.5 0  0 0.5 0  -0.293892 -0.5 0.404509  0 -0.5 0.5  0 0.5 0  0 -0.5 0.5  0 0.5 0  0 0.5 0  0 -0.5 0.5  0.293893 -0.5 0.404509  0 0.5 0  0.293893 -0.5 0.404509  0 0.5 0  0 0.5 0  "

    Normals="0.7236065,0.4472139,0.5257313  0.2763934,0.4472138,0.8506507  0.5308242,0.4294462,0.7306172  0.2763934,0.4472138,0.8506507  0,0.4294458,0.9030925  0.5308242,0.4294462,0.7306172  0.2763934,0.4472138,0.8506507  -0.2763934,0.4472138,0.8506507  0,0.4294458,0.9030925  -0.2763934,0.4472138,0.8506507  -0.5308242,0.4294462,0.7306172  0,0.4294458,0.9030925  -0.2763934,0.4472138,0.8506507  -0.7236065,0.4472139,0.5257313  -0.5308242,0.4294462,0.7306172  -0.7236065,0.4472139,0.5257313  -0.858892,0.429446,0.279071  -0.5308242,0.4294462,0.7306172  -0.7236065,0.4472139,0.5257313  -0.8944269,0.4472139,0  -0.858892,0.429446,0.279071  -0.8944269,0.4472139,0  -0.858892,0.429446,-0.279071  -0.858892,0.429446,0.279071  -0.8944269,0.4472139,0  -0.7236065,0.4472139,-0.5257313  -0.858892,0.429446,-0.279071  -0.7236065,0.4472139,-0.5257313  -0.5308242,0.4294462,-0.7306172  -0.858892,0.429446,-0.279071  -0.7236065,0.4472139,-0.5257313  -0.2763934,0.4472138,-0.8506507  -0.5308242,0.4294462,-0.7306172  -0.2763934,0.4472138,-0.8506507  0,0.4294458,-0.9030925  -0.5308242,0.4294462,-0.7306172  -0.2763934,0.4472138,-0.8506507  0.2763934,0.4472138,-0.8506507  0,0.4294458,-0.9030925  0.2763934,0.4472138,-0.8506507  0.5308249,0.4294459,-0.7306169  0,0.4294458,-0.9030925  0.2763934,0.4472138,-0.8506507  0.7236068,0.4472141,-0.5257306  0.5308249,0.4294459,-0.7306169  0.7236068,0.4472141,-0.5257306  0.8588922,0.4294461,-0.27907  0.5308249,0.4294459,-0.7306169  0.7236068,0.4472141,-0.5257306  0.8944269,0.4472139,0  0.8588922,0.4294461,-0.27907  0.8944269,0.4472139,0  0.858892,0.429446,0.279071  0.8588922,0.4294461,-0.27907  0.8944269,0.4472139,0  0.7236065,0.4472139,0.5257313  0.858892,0.429446,0.279071  0.7236065,0.4472139,0.5257313  0.5308242,0.4294462,0.7306172  0.858892,0.429446,0.279071  "                   TriangleIndices="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 " />

                    </GeometryModel3D.Geometry>

 

                    <GeometryModel3D.Material>

                      <DiffuseMaterial>

                        <DiffuseMaterial.Brush>

                          <SolidColorBrush

                            Color="Red"

                            Opacity="1.0"/>

                        </DiffuseMaterial.Brush>

                      </DiffuseMaterial>

                    </GeometryModel3D.Material>

 

                  </GeometryModel3D>

 

                </Model3DGroup.Children>

              </Model3DGroup>

 

            </ModelVisual3D.Content>

 

          </ModelVisual3D>

 

        </Viewport3D.Children>

 

      </Viewport3D>

    </Grid>

 

</UserControl>

 

 

Make a 3D cube with pictures on its sides with XAML and C# 源碼

howto_xaml_cube_sides

總結

3D開發首先要把三維坐標系搞清楚,才能構建出想要的3D Model,才能把燈光合理的照在3D模型上(環境光除外)得到不同的燈光效果,才能指定合適的相機(Camera)位置從而看到自己想要看到3D投影。

3D開發中所有的幾何體最終都是由一系列的三角形來組成的。所以在您吧三維坐標系高清的前提下,您還需要考慮把您的3D模型分解成三角形。聽來就很繁瑣,幸運的是現在有一些輔助類幫助大家來處理這些三角形的分解,而您所做的就是提供關鍵點的坐標系。

 

由於WPF 3D 是基於Direct 3D,和WPF 2D一樣直接利用顯卡渲染的,並且默認開啟了全景反鋸齒(有個條件,需要你的顯卡支持 兼容WDDM-Compliant)。

 

3D開發和2D開發復雜了很多,考慮的東西多了不少。但為了那更真實的,更炫酷的效果,這一切都值得您去學習。

 

祝各位在3D開發的旅途,一路愉快!

參考

WPF 3D Article, Tutorial with Chart Graphics C# Code

WPF-3D-Primer

Getting started with 3D in WPF

三維圖形概述

Rendering Transparent 3D Surfaces in WPF with C#

Ambient, diffuse, emissive and specular colors : some examples

VoreenVE 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM