How to implement 3D drawing using WFP

WPF itself does not support direct 3D drawing, but it provides some advanced techniques for achieving 3D effects.

If you want to do 3D drawing in WPF, you can use two main methods:

  1. WPF 3D: This is a way to create 3D graphics in WPF applications. WPF 3D provides some basic 3D shapes (such as cubes, spheres, and cones) as well as some tools for controlling 3D scenes and objects (such as cameras, lights, and materials).

In WPF, the following three materials can be used for 3D object models:

  1. DiffuseMaterial: diffuse reflection, reflection scene light effect

  2. EmissiveMaterial: self-illuminating, similar to an electric light 

  3. SpecularMaterial: total reflection, can map scene maps

In WPF, the material of a 3D model is a very important element that determines what the model looks like, such as roughness, color, luminosity, etc.

The WPF 3D object model light source is as follows

AmbientLight: Ambient Light - Provides ambient light that illuminates all objects regardless of their position or orientation.

DirectionalLight: directional light - it illuminates like a distant light source (such as sunlight), has only a Direction property and no position information, so it does not cast directly on any specific object, but illuminates all objects in the scene .

PointLight: Point light - Illuminates like a nearby light source, has a position and casts light from that position, objects in the scene are illuminated based on the object's position and distance relative to the light source.

SpotLight: Spotlight - Inherited from PointLight, it lights similarly to PointLight, but it has both position and direction.

Related properties  

 Color: light color   

Direction: light direction (parallel light, spotlight)   

Position: light source coordinates (point light source, spotlight)   

Range: light range (point light source)  

 InnerConeAngle: inner light beam illumination angle (spotlight)   

OuterConeAngle: External light beam illumination angle (spotlight)

Attributes

illustrate

Remark

MeshGemetry3D

grid label

Positions

point

Labels that present 3D graphics Positions="0,0,0 (x,y,z) 3,0,0 3,2,0 0,2,0" 4 points of a surface

TraiangleIndices

3 Angular creation

TriangleIndices="0,3,2 (first group) 0,1,2 (second group)" Set the 3 points of Positions to form a triangle row

OrthographicCamera  

Orthographic camera (near and far ratios are the same - rarely used)

PerspectiveCamera    

Perspective camera (the near ratio is small and the long distance ratio is small, in line with our normal vision of observing things - commonly used)

TextureCoordinates

Set the mapping relationship between plane objects and 3D objects - used to solve the problem of displaying the background image of plane settings - if this property is not set, the background image of plane settings will not be displayed.

TextureCoordinates="1,1 1,0 0,0 0,1"

Camera tag object properties

Attributes illustrate Remark
Position Camera spatial coordinates (X, Y, Z) Position="100,100,100" Set the viewing angle x,y,z
LookDirection Observation direction, vector, camera observation port orientation LookDirection="-2,-2,-2" sets the camera's viewing angle - the direction of the camera's observation
FieldOfView (perspective camera property) / field of view, one value FieldOfView="90" sets the distance between the camera and the viewing object. The farther away the viewing object area is, the larger the viewing area is, and the closer the viewing object area is smaller.
Width (orthographic camera properties) (focal length), field of view Width="50"
UpDirection The direction above the camera, controls the rotation of the camera observation port UpDirection="0,1,0" (x, y, z) sets the rotation angle of the camera viewport, whether to shoot at an angle or straight up.
FarPlaneDistance Distant distance. Scenes larger than this distance will not be rendered. 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"/>--><!--  箭头向上-->

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

Guess you like

Origin blog.csdn.net/lwf3115841/article/details/133418324