- PVSM.RU - https://www.pvsm.ru -
Для работы с 3D моделями мы используем специальные конвейеры обработки — OpenGL [1] и DirectX [2]. Когда конвейеры строят картину, они используют информацию:
Любая модель начинается с геометрии. Геометрия модели — это набор точек в трехмерном пространстве и набор треугольников из этих точек. Треугольник компланарен — он лежит в плоскости, в отличие от фигур с большим числом точек, которые в общем случае не лежат в плоскости.
Если задать у треугольника направление обхода границы, он станет ориентированным треугольником. У ориентированного треугольника в трехмерном пространстве можно выделить внутреннюю и внешнюю стороны. По направлению обхода границы мы также определяем единственный по направлению вектор нормали для каждого треугольника. Так, в геометрию модели, помимо точек и треугольников, входит набор нормалей к каждому из треугольников. При отображении модели точки модели соответствуют точкам, треугольники модели соответствуют граням.
В примере мы сосредоточимся на геометрии модели, остальное будем использовать по мере необходимости. В качестве примера модели вполне подойдет Дельфин ниже:

Благодаря технологии WPF [3] мы создаем интерактивные интерфейсы приложений и работаем с 3D-графикой. В примере мы используем стандартные возможности архитектуры WPF [3]: привяжем данные и на их основе разделим модель данных и представление данных (MVVM [4]).
Основной элемент для отображения 3D-содержимого в библиотеке WPF [3]— Viewport3D [5]. Например, свойство Camera устанавливает камеру, и мы видим сцену. Второе необходимое свойство Viewport3D [5]— Children, коллекция элементов абстрактного типа Visual3D [6]. Конкретная реализация этого класса — класс ModelVisual3D [7]: чтобы его использовать, нужно указать свойство Content абстрактного типа Model3D [8].
Основные классы для установки свойства Content:
Необходимые свойства будем устанавливать по привязке.
В широком смысле любое приложение решает определенную задачу. Модель должна полностью отражать данные в решаемой приложением задаче. Мы упростим пример и исключим нормали — они будут определяться по умолчанию. Нормали важны для отображения текстур или заливки при расчете освещенности.
Подберем основные интерфейсы, которые определяют сущности модели данных MVVM и их связи:
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);
}
Конкретная реализация прямолинейна. Чтобы предупреждать об изменении свойств, используем привычный INotifyPropertyChanged [12].
В качестве базового класса для ViewModel мы используем:
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; }
}
Такая структура удобна тем, что позволяет двигаться по иерархии ViewModel в привязках. Классы Vector3D, Triangle3D, Point3D просты, поэтому создавать для них ViewModel не обязательно. Значит нам нужны только два класса ViewModel — Model3DSetVm и Model3DVm.
Чтобы построить представления, используем подстановку WPF с помощью атрибута DataType="{x:Type local:Type}" при объявлении DataTemplate в словарях ресурсов. В остальном реализация стандартная. Приложение для демонстрации выглядит так:

Проект с примером можно найти здесь... [13]
Буду рад, если статья вам в чем-то поможет…
Автор: Tinkoff.ru
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-2/252604
Ссылки в тексте:
[1] OpenGL: https://ru.wikipedia.org/wiki/OpenGL
[2] DirectX: https://ru.wikipedia.org/wiki/DirectX
[3] WPF: https://ru.wikipedia.org/wiki/Windows_Presentation_Foundation
[4] MVVM: https://ru.wikipedia.org/wiki/Model-View-ViewModel
[5] Viewport3D: https://msdn.microsoft.com/ru-ru/library/system.windows.controls.viewport3d(v=vs.110).aspx
[6] Visual3D: https://msdn.microsoft.com/ru-ru/library/system.windows.media.media3d.visual3d(v=vs.110).aspx
[7] ModelVisual3D: https://msdn.microsoft.com/ru-ru/library/system.windows.media.media3d.modelvisual3d(v=vs.110).aspx
[8] Model3D: https://msdn.microsoft.com/ru-ru/library/system.windows.media.media3d.model3d(v=vs.110).aspx
[9] GeometryModel3D: https://msdn.microsoft.com/ru-ru/library/system.windows.media.media3d.geometrymodel3d(v=vs.110).aspx
[10] Light: https://msdn.microsoft.com/ru-ru/library/system.windows.media.media3d.light(v=vs.110).aspx
[11] Model3DGroup: https://msdn.microsoft.com/ru-ru/library/system.windows.media.media3d.model3dgroup(v=vs.110).aspx
[12] INotifyPropertyChanged: https://msdn.microsoft.com/ru-ru/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx
[13] Проект с примером можно найти здесь...: https://github.com/klauth86/MS-Visual-Studio/tree/master/Simple3DModelEditor
[14] Источник: https://habrahabr.ru/post/326406/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.