WPF本身不支持直接的3D繪圖,但是它提供了一些用於實現3D效果的高級技術。 如果你想要在WPF中進行3D繪圖,你可以使用兩種主要的方法: WPF 3D:這是一種在WPF應用程式中創建3D圖形的方式。WPF 3D提供了一些基本的3D形狀(如立方體、球體和錐體)以及一些用於控制3D場景和對象的工具(如 ...
WPF本身不支持直接的3D繪圖,但是它提供了一些用於實現3D效果的高級技術。 如果你想要在WPF中進行3D繪圖,你可以使用兩種主要的方法:
- WPF 3D:這是一種在WPF應用程式中創建3D圖形的方式。WPF 3D提供了一些基本的3D形狀(如立方體、球體和錐體)以及一些用於控制3D場景和對象的工具(如相機、光源和材質)。
- DiffuseMaterial:漫反射,反射場景光效果
- EmissiveMaterial:自發光,類似於電燈
- SpecularMaterial:全反射,可以映射場景 貼圖
屬性 | 說明 | 備註 |
MeshGemetry3D | 網格標簽 | |
Positions | 點 | 呈現3D圖形的標簽 Positions="0,0,0(x,y,z) 3,0,0 3,2,0 0,2,0" 一個面的4個點 |
TraiangleIndices | 3 角形創建 | TriangleIndices ="0,3,2(第一組) 0,1,2(第二組)" 設置Positions的3個點組成一個三角行 |
OrthographicCamera | 正交相機(遠近比例都一樣-很少用) | |
PerspectiveCamera | 透視相機(近比例長遠比例小,符合我們正常觀察事物的視覺-常用) | |
TextureCoordinates | 設置平面對象與3D對象的映射關係-用來解決平面設置背景圖顯示問題-如果不設置這個屬性平面設置的背景圖不顯示 | TextureCoordinates="1,1 1,0 0,0 0,1" |
相機標簽對象屬性
屬性 | 說明 | 備註 |
Position | 相機的空間坐標(X,Y,Z) | Position="100,100,100" 設置視角x,y,z |
LookDirection | 觀察方向,向量,相機觀察口朝向 | LookDirection="-2,-2,-2" 設置相機的觀看視角-相機觀察的方向 |
FieldOfView | (透視相機屬性) / 視野範圍,一個值 | FieldOfView="90" 設置相機與觀看物體的距離,離得遠觀看物體區域範圍大,離得近觀看物體區域範圍小 |
Width | (正交相機屬性)(焦距),視野範圍 | Width="50" |
UpDirection | 相機上方方向,控制相機觀察口旋轉 | UpDirection="0,1,0" (x, y,z)設置相機視口的旋轉角度,斜著拍還是正著拍 |
FarPlaneDistance | 遠景距離,大於這個距離的場景不渲染 | FarPlaneDistance="1000" 設置相機遠處景色的渲染範圍,如果值設置的比較小,遠處景色是模糊的 |
NearPlaneDistance | 近景距離,小於這個距離的場景不渲染 | NearPlaneDistance="1" 設置相機近處的晶圓渲染範圍,如果值越大,近處景色是模糊的 |
<!--設置三維地球實例旋轉動畫--> <Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <BeginStoryboard> <!--RepeatBehavior="Forever" 設置旋轉動畫一直旋轉--> <Storyboard RepeatBehavior="Forever"> <!--Duration="0:0:7" 設置播放時長--> <!--Storyboard.TargetName="aar" 設置要旋轉的控制項--> <!--Storyboard.TargetProperty="Angle" 設置旋轉方式--> <!--From="0" 設置動畫起始值--> <!--To="360" 設置旋轉角度--> <DoubleAnimation Duration="0:0:7" Storyboard.TargetName="aar" Storyboard.TargetProperty="Angle" From="0" To="360"/> </Storyboard> </BeginStoryboard> </EventTrigger> </Window.Triggers> <Grid> <!--畫3D圖標簽--> <!--點動成線-線動成面-面動成體--> <Viewport3D> <!--第一步在3D世界通過相機來觀察這個世界,把這個世界呈現在平面圖上。--> <!--相機標簽-設置相機的相關參數--> <Viewport3D.Camera> <!-- PerspectiveCamera標簽-透視相機(近比例長遠比例小,符合我們正常觀察事物的視覺-常用)--> <!--Position="100,100,100" 設置視角x,y,z--> <!--LookDirection="-2,-2,-2" 設置相機的觀看視角-相機觀察的方向--> <!--FieldOfView="90" 調整相機焦距 設置相機與觀看物體的距離,離得遠觀看物體區域範圍大,離得近觀看物體區域範圍小 --> <!--UpDirection="0,1,0" (x, y,z)設置相機視口的旋轉角度,斜著拍還是正著拍 --> <!--FarPlaneDistance="1000" 設置相機遠處景色的渲染範圍,如果值設置的比較小,遠處景色是模糊的--> <!--NearPlaneDistance="1" 設置相機近處的晶圓渲染範圍,如果值越大,近處景色是模糊的--> <PerspectiveCamera Position="100,100,100" LookDirection="-2,-2,-2" FieldOfView="90" UpDirection="0,1,0" FarPlaneDistance="1000" NearPlaneDistance="1"> </PerspectiveCamera> <!--正交相機(遠近比例都一樣-很少用)--> <!--Width="50" 相當與透視相機的視野範圍屬性--> <!--<OrthographicCamera Position="100,100,100" LookDirection="-2,-2,-2" Width="50" UpDirection="0,1,0" FarPlaneDistance="1000" NearPlaneDistance="1"/>--> </Viewport3D.Camera> <!--第二步在3D世界設置光源進來,沒有光源全是黑的呀--> <!--光源標簽-設置光源的相關屬性--> <ModelVisual3D> <!--光源內容標簽--> <ModelVisual3D.Content> <!--多個光源可以組合使用-會出現不同的效果--> <Model3DGroup> <!--環境游標簽 --> <!--Color="White"-設置環境光顏色 --> <!--<AmbientLight Color="White"/>--> <!--平行光-設置某一個方向上照射的光-平行光不發散 --> <!--Direction="-1,-1,-1" (x,y,z)三個方向照射的光 設置平行光的照射方向--> <!--<DirectionalLight Color="White" Direction="-1,-1,-1"/>--> <!--點光源-點光源是向四面八方發散的光源 --> <!--Position="100,100,100" (x,y,z) 設置光源點--> <!--Range="200" 設置光源的照射範圍--> <!--<PointLight Color="White" Position="100,100,100" Range="200"/>--> <!--射燈光源(聚光燈,手電筒筒)-某一個方向去發射光源-相當於手電筒筒有一個中心的光柱(比較亮的)以及兩遍發散的光源(相對較暗) --> <!--InnerConeAngle="100" 設置中心範圍光柱的角度--> <!--OuterConeAngle="40" 設置兩遍光源的範圍角度--> <!--Position="50,50,50" 設置光源的中心位置--> <!--Direction="-1,-1,-1" (x,y,z)三個方向照射的光 設置光源的照射方向--> <SpotLight Color="Orange" InnerConeAngle="100" OuterConeAngle="40" Position="50,50,50" Direction="-1,-1,-1"/> </Model3DGroup> </ModelVisual3D.Content> </ModelVisual3D> <!--3D圖形的第一個面 可以把所有的面放在一起寫--> <!--3DUIElement標簽-固定寫法--> <ModelUIElement3D> <ModelUIElement3D.Model> <!--GeometryModel3D網格標簽--> <GeometryModel3D> <!--第三步物體需要呈現出來需要材質--> <!--3D的材質 標簽--> <GeometryModel3D.Material> <MaterialGroup> <!--漫反射的一種材質 材質是與網格屬性標簽組合在一起使用的--> <!--DiffuseMaterial 慢反射材質標簽--> <!--Brush 設置材質顏色或圖片--> <!--<DiffuseMaterial Brush="Orange"/>--> <!--3D面設置背景圖-需要在網格標簽中設置TextureCoordinates="0,1 0,0 1,0 1,1"屬性,背景圖顯示方向,才能顯示出背景圖 --> <DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource="Arrow.png"/> </DiffuseMaterial.Brush> </DiffuseMaterial> <!--自發光--> <!--<EmissiveMaterial Brush="Red"/>--> <!--<SpecularMaterial Brush="Blue"/>--> </MaterialGroup> </GeometryModel3D.Material> <!--網格標簽--> <GeometryModel3D.Geometry> <!-- 呈現3D圖形的標簽 Positions="0,0,0(x,y,z) 3,0,0 3,2,0 0,2,0" 一個面的4個點--> <!--TriangleIndices ="0,2,3(第一組-這裡的坐標點需要逆時針順序) 0,1,2(第二組)" 設置Positions的3個點組成一個三角行 --> <!--這裡如果呈現的是三角行而不是四邊行的畫,是因為TriangleIndices="0,2,3 0,1,2"的畫點順序需要逆時針順序--> <!--TextureCoordinates 設置平面對象與3D對象的映射關係-用來解決平面設置背景圖顯示問題-如果不設置這個屬性平面設置的背景圖不顯示--> <MeshGeometry3D Positions="0,0,0 3,0,0 3,2,0 0,2,0" TriangleIndices="0,2,3 0,1,2" TextureCoordinates="1,1 1,0 0,0 0,1"/> <!--箭頭向下--> <!--TextureCoordinates="1,1 0,1 0,0 1,0"/> 箭頭向左--> <!--TextureCoordinates="0,1 1,1 1,0 0,0"/> 箭頭向右--> <!--TextureCoordinates="0,1 0,0 1,0 1,1"/>--><!-- 箭頭向上--> </GeometryModel3D.Geometry> </GeometryModel3D> </ModelUIElement3D.Model> </ModelUIElement3D> <!--3D圖形的第二個面 可以把所有的面放在一起寫 這裡沒有放在一起寫是因為可以給每個面設置不同的顏色--> <!--3DUIElement標簽-固定寫法--> <ModelUIElement3D> <ModelUIElement3D.Model> <!--GeometryModel3D網格標簽--> <GeometryModel3D> <!--第三步物體需要呈現出來需要材質--> <!--3D的材質 標簽--> <GeometryModel3D.Material> <MaterialGroup> <!--漫反射的一種材質 材質是與網格屬性標簽組合在一起使用的--> <!--DiffuseMaterial 慢反射材質標簽--> <!--Brush 設置材質顏色或圖片--> <DiffuseMaterial Brush="Red"/> <!--<DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource="Arrow.png"/> </DiffuseMaterial.Brush> </DiffuseMaterial>--> <!--自發光 標簽-用於設置在沒有光源的情況下可以看見自發光顏色-在有光源的情況下自發光顏色會影響到材質顏色的顯示 --> <!--<EmissiveMaterial Brush="Green"/>--> <!--全反射標簽 目前只是瞭解一下--> <!--<SpecularMaterial Brush="Blue"/>--> </MaterialGroup> </GeometryModel3D.Material> <!--網格標簽--> <GeometryModel3D.Geometry> <!-- 呈現3D圖形的標簽 Positions="0,0,0(x,y,z) 3,0,0 3,2,0 0,2,0" 一個面的4個點--> <!--TriangleIndices ="0,2,3(第一組-這裡的坐標點需要逆時針順序) 0,1,2(第二組)" 設置Positions的3個點組成一個三角行 --> <!--這裡如果呈現的是三角行而不是四邊行的畫,是因為TriangleIndices="0,2,3 0,1,2"的畫點順序需要逆時針順序--> <MeshGeometry3D Positions="3,2,1 3,2,0 3,0,0 3,0,1" TriangleIndices="0,3,1 1,3,2"/> </GeometryModel3D.Geometry> </GeometryModel3D> </ModelUIElement3D.Model> </ModelUIElement3D> <!--三維地球實例--> <!--3DUIElement標簽-固定寫法--> <ModelUIElement3D> <!--3D圖像旋轉標簽--> <ModelUIElement3D.Transform> <!--旋轉標簽分組--> <Transform3DGroup> <!--設置旋轉中心--> <RotateTransform3D CenterX="0" CenterY="0" CenterZ="0"> <!--設置旋轉角度--> <RotateTransform3D.Rotation> <!--設置沿著x軸旋轉 -90度--> <AxisAngleRotation3D Axis="1,0,0" Angle="-90"/> </RotateTransform3D.Rotation> </RotateTransform3D> <RotateTransform3D CenterX="0" CenterY="0" CenterZ="0"> <RotateTransform3D.Rotation> <!--沿著Y軸旋轉-通過後臺可設置地球旋轉--> <AxisAngleRotation3D Axis="0,1,0" x:Name="aar"/> </RotateTransform3D.Rotation> </RotateTransform3D> </Transform3DGroup> </ModelUIElement3D.Transform> <!--3D標簽--> <ModelUIElement3D.Model> <!--GeometryModel3D網格標簽--> <GeometryModel3D x:Name="gm"> <!--3D的材質 標簽--> <GeometryModel3D.Material> <!--設置3D材質使用圖片--> <DiffuseMaterial> <DiffuseMaterial.Brush> <ImageBrush ImageSource="Earth.jpg"/> </DiffuseMaterial.Brush> </DiffuseMaterial> </GeometryModel3D.Material> </GeometryModel3D> </ModelUIElement3D.Model> </ModelUIElement3D> </Viewport3D> </Grid>
後臺關於3D地球的代碼
public MainWindow() { InitializeComponent(); // 綁定載入事件 this.Loaded += MainWindow_Loaded; } /// <summary> /// 窗體載入 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MainWindow_Loaded(object sender, RoutedEventArgs e) { this.gm.Geometry = this.SetEarth(180, 180, 50); } /// <summary> /// 生成三維地球演算法 /// 圓弧的計算公式 /// </summary> /// <param name="numx">緯度方向切多少份</param> /// <param name="numz">精度方向切多少份</param> /// <param name="r">地球半徑</param> /// <returns></returns> private MeshGeometry3D SetEarth(int numx, int numz, double r = 3) { MeshGeometry3D mesh = new MeshGeometry3D(); double dTh = 2 * Math.PI / numx; double dPhi = Math.PI / numz; double X(double th, double phi) => r * Math.Sin(phi) * Math.Cos(th); double Y(double th, double phi) => r * Math.Sin(phi) * Math.Sin(th); double Z(double phi) => r * Math.Cos(phi); // Make the points. for (int i = 0; i <= numx; i++) // 緯度方向迴圈次數 for (int j = 0; j <= numz; j++) // 精度方向迴圈次數 { // 這裡使用三角函數進行計算的 var th = i * dTh; var phi = j * dPhi; // 坐標點-用於畫三角形的坐標點 mesh.Positions.Add(new Point3D(X(th, phi), Y(th, phi), Z(phi))); // 用於建立與圖片的映射關係 mesh.TextureCoordinates.Add(new Point(th, phi)); } // 生成三角形-每三個坐標點組織一個面出來 for (int i = 0; i < numx; i++) for (int j = 0; j < numz; j++) { int i1 = i * (numz + 1) + j; int i2 = i1 + 1; int i3 = i2 + (numz + 1); int i4 = i3 - 1; mesh.TriangleIndices.Add(i1); mesh.TriangleIndices.Add(i2); mesh.TriangleIndices.Add(i3); mesh.TriangleIndices.Add(i1); mesh.TriangleIndices.Add(i3); mesh.TriangleIndices.Add(i4); } return mesh; }
代碼實例效果圖:
這個3D動畫地球是可以旋轉的
3D圖片用於輔助尋找3d坐標點順序
3D面設置背景圖顯示方向 通過TextureCoordinates屬性設置箭頭的顯示方向 TextureCoordinates="1,1 1,0 0,0 0,1"/> <!--箭頭向下--> <!--TextureCoordinates="1,1 0,1 0,0 1,0"/> 箭頭向左--> <!--TextureCoordinates="0,1 1,1 1,0 0,0"/> 箭頭向右--> <!--TextureCoordinates="0,1 0,0 1,0 1,1"/>--><!-- 箭頭向上-->
本文章大半部分素材來自於朝夕教育,技術整理的不好。。。