用WFP如何实现3D绘图

WPF本身不支持直接的3D绘图,但是它提供了一些用于实现3D效果的高级技术。

如果你想要在WPF中进行3D绘图,你可以使用两种主要的方法:

  1. WPF 3D:这是一种在WPF应用程序中创建3D图形的方式。WPF 3D提供了一些基本的3D形状(如立方体、球体和锥体)以及一些用于控制3D场景和对象的工具(如相机、光源和材质)。

在WPF中,3D对象模型的材质可以使用以下三种

  1. DiffuseMaterial:漫反射,反射场景光效果

  2. EmissiveMaterial:自发光,类似于电灯 

  3. SpecularMaterial:全反射,可以映射场景 贴图

在WPF中,一个3D模型的材质,就是决定模型看起来是什么样子的一种很重要的元素,如粗糙度、颜色、发光度等

WPF 3D对象模型光源如下

AmbientLight:环境光-  提供环境光,会照亮所有的对象,而不考虑对象的位置或方向。

DirectionalLight:平行光  -  它像远处的光源那样照亮(如太阳光),只具有一个Direction属性,没有位置信息,因此不直接投射到任何特定的对象上,而是照亮场景中的所有对象。

PointLight:点光源 -  像近处的光源那样照亮,具有一个位置并从该位置投射光,场景中的对象是根据对象相对于光源的位置和距离而被照亮的。

SpotLight:聚光灯  -  从PointLight继承,它的照亮方式与PointLight类似,但是它既具有位置又具有方向。

相关属性  

 Color:灯光颜色   

Direction:光线方向(平行光、聚光灯)   

Position:光源坐标(点光源、聚光灯)   

Range:灯光范围(点光源)  

 InnerConeAngle:内光柱照射角度(聚光灯)   

OuterConeAngle:外光柱照射角度(聚光灯)

属性

说明

备注

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" 设置相机近处的晶圆渲染范围,如果值越大,近处景色是模糊的

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

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

<!--设置三维地球实例旋转动画-->

 <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地球的代码

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

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"/>--><!--  箭头向上-->

 本文章大半部分素材来自于朝夕教育,技术整理的不好。。。

猜你喜欢

转载自blog.csdn.net/lwf3115841/article/details/133418324
今日推荐