⬆️ ⬇️

Visualization of simple geometry in WPF

What is model geometry?



To work with 3D models, we use special processing pipelines - OpenGL and DirectX . When conveyors build a picture, they use information:





Any model starts with geometry. Model geometry is a set of points in three-dimensional space and a set of triangles from these points. The triangle is complanar - it lies in the plane, unlike figures with a large number of points, which in general do not lie in the plane.



If you set the direction of the border around the triangle, it will become an oriented triangle. For an oriented triangle in three-dimensional space, one can distinguish the inner and outer sides. In the direction of bypassing the border, we also determine the only in the direction of the normal vector for each triangle. Thus, in addition to points and triangles, the geometry of the model includes a set of normals for each of the triangles. When the model is displayed, the points of the model correspond to the points, the triangles of the model correspond to the faces.

')

In the example we will focus on the geometry of the model, the rest will be used as necessary. As an example, the model is quite suitable Dolphin below:



image



Thanks to WPF technology, we create interactive application interfaces and work with 3D graphics. In the example, we use the standard features of the WPF architecture: we will tie in the data and on the basis of them we will separate the data model and data presentation ( MVVM ).



The main element for displaying 3D content in the WPF library is Viewport3D . For example, the Camera property sets the camera, and we see the scene. The second necessary property of Viewport3D is Children , a collection of elements of the abstract Visual3D type. The concrete implementation of this class is the ModelVisual3D class: to use it, you must specify the Content property of the abstract Model3D type.



The main classes for setting the Content property are:





Necessary properties will be set by binding.



MVVM data model



In a broad sense, any application solves a specific task. The model should fully reflect the data in the problem solved by the application. We simplify the example and eliminate the normals - they will be defined by default. Normals are important for displaying textures or fills when calculating luminance.



We select the main interfaces that define the essence of the MVVM data model and their connections:



interface IModel3DSet { string Description { get; set; } ICollection<IModel3D> Models { get; } } interface IModel3D { string Description { get; set; } ICollection<IPoint3D> Points { get; } ICollection<ITriangle3D> Triangles { get; } } interface IPoint3D { double X { get; set; } double Y { get; set; } double Z { get; set; } string Coordinates { get; } IVector3D DistanceTo(IPoint3D endPoint); } interface ITriangle3D { IModel3D Model3D { get; } IPoint3D Point1 { get; set; } IPoint3D Point2 { get; set; } IPoint3D Point3 { get; set; } } interface IVector3D { double X { get; set; } double Y { get; set; } double Z { get; set; } double Norm { get; } IVector3D Add(IVector3D vector); IVector3D Subtract(IVector3D vector); IVector3D Multiply(double factor); IVector3D CrossProduct(IVector3D vector); double DotProduct(IVector3D vector); } 


The concrete implementation is straightforward. To warn about changing properties, use the familiar INotifyPropertyChanged .



Viewmodel



As a base class for the ViewModel, we use:



 public abstract class BaseVm<TModel> : Notifier { TModel _model; public TModel Model { get { return _model; } set { _model = value; NotifyWithCallerPropName(); } } } public abstract class BaseVm<TModel, TParentVM> : BaseVm<TModel> { public BaseVm(TModel model = default(TModel), TParentVM parentVM = default(TParentVM)) { Model = model; Parent = parentVM; } public TParentVM Parent { get; } } 


This structure is convenient in that it allows you to move along the ViewModel hierarchy in the bindings. The classes Vector3D , Triangle3D , Point3D are simple, so creating ViewModel for them is not necessary. So we need only two ViewModel classes - Model3DSetVm and Model3DVm .



Representation



To build views, we use WPF substitution using the DataType = "{x: Type local: Type}" attribute when declaring a DataTemplate in resource dictionaries. The rest of the implementation is standard. The application for the demonstration looks like this:







What else do you need to know



  1. In WPF, the TriangleIndices property is optional. If it is not specified, by default, triangles will be created for each of the three points. For this reason, even with an empty set of triangles, faces are displayed.



  2. To create a binding for a collection of models, you can use the binding from our example, but substitute an instance of Model3DGroup instead of GeometryModel3D . Use for this binding to the Children Viewport3D property does not work.



  3. If we change the geometry or rotation axis, the model will be rebuilt, the image will twitch - the animation will start anew. So that the process is not interrupted, save the intermediate values ​​of the model and apply animation to them.


An example project can be found here ...



I would be glad if the article will help you in some way ...

Source: https://habr.com/ru/post/326406/



All Articles