Начало работы с Graphics3DControl¶
В этом руководстве демонстрируется, как создать 3D-модель и отобразить ее в контроле Graphics3DControl. В примере используется API, предоставляемый контролом, для определения сеток, вершин и материалов.
Вы можете отображать несколько 3D-моделей в Graphics3DControl одновременно. В этом руководстве создается одна 3D-модель. Он состоит из квадрата и двух треугольников, позиций, расположенных под прямым углом друг к другу. Каждая фигура отрисована с использованием своего собственного материала.

Создание Graphics3DControl¶
Создайте контрол Graphics3DControl в XAML, используя следующий код:
xmlns:mx3d="https://schemas.eremexcontrols.net/avalonia/controls3d"
<mx3d:Graphics3DControl Name="g3DControl" ShowAxes="True">
    <mx3d:Graphics3DControl.Camera>
        <mx3d:IsometricCamera/>
    </mx3d:Graphics3DControl.Camera>
</mx3d:Graphics3DControl>
Этот код отображает оси и включает изометрическую камеру для контрола Graphics3DControl. Вы также можете включить перспективную камеру. Для этой цели установите свойству Graphics3DControl.Camera значение объекта PerspectiveCamera.
Определение 3D-модели¶
Класс GeometryModel3D инкапсулирует 3D-модель для Graphics3DControl. Чтобы добавить 3D-модели в контрол, добавьте один или несколько объектов GeometryModel3D в коллекцию Graphics3DControl.Models.
using Eremex.AvaloniaUI.Controls3D;
GeometryModel3D model = new GeometryModel3D();
g3DControl.Models.Add(model);
3D-модель состоит из одной или нескольких сеток. Сетка - это часть модели, рисованная с использованием определенного материала.
Квадратные и треугольные фигуры в 3D-модели рисованы своими собственными материалами. Таким образом, необходимо создать три сетки.
Добавление сеток¶
Используйте коллекцию GeometryModel3D.Meshes для добавления ячеек. Каждая ячейка инкапсулируется объектом MeshGeometry3D.
using DynamicData;
MeshGeometry3D meshTriangle1 = new MeshGeometry3D();
MeshGeometry3D meshTriangle2 = new MeshGeometry3D();
MeshGeometry3D meshSquare = new MeshGeometry3D();
//...
model.Meshes.AddRange(new[] { meshTriangle1, meshTriangle2, meshSquare });
Graphics3DControl поддерживает три типа сеток:
- Сетка, определяемая набором треугольников (по умолчанию или когда для параметра MeshGeometry3D.FillTypeзадано значениеMeshFillType.Triangles)
- Сетка, определяемая набором линий (когда для MeshGeometry3D.FillTypeустановлено значениеMeshFillType.Lines)
- Сетка, определяемая набором точек (если для параметра MeshGeometry3D.FillTypeзадано значениеMeshFillType.Points)
В текущем примере сетки создаются из треугольников. Для этого типа сетки необходимо указать следующие свойства:
- 
MeshGeometry3D.Vertices— Массив всех вершин (объектовVertex3D), составляющих сетку. ОбъектVertex3Dобладает следующими основными свойствами:- Vertex3D.Position— объект- Vector3, который определяет координаты вершины.
- Vertex3D.Normal— Объект- Vector3, который определяет нормаль к вершине. Нормали к вершине - это векторы направления, используемые для вычисления отражения света от вершин и треугольника.
- Vertex3D.TextureCoord— объект- Vector2, который определяет координаты текстуры для текущей вершины.
 
- 
MeshGeometry3D.Indices— Массив индексов вершин в массивеVertices, которые определяют отдельные треугольники сетки. Этот массив содержит группы по три индекса в каждой. Первые три индекса в массиве относятся к вершинам первого треугольника сетки. Следующие три индекса относятся к вершинам второго треугольника сетки и так далее. Порядок расположения индексов для каждого треугольника важен, поскольку он определяет нормаль к поверхности. Нормаль к поверхности, в свою очередь, определяет переднюю и заднюю стороны треугольника, что важно для таких операций, как отбраковка обратной и лицевой сторон.
Определите сетки для фигур Треугольник 1 и треугольник 2¶
Сетки для фигур Triangle 1 и Triangle 2 легко определить, поскольку эти фигуры уже представляют собой треугольники.
Сначала давайте определим все вершины в созданной 3D-модели и их координаты (x, y, z).

В коде определите координаты всех вершин, используя объекты Vector3:
Vector3 pt1 = new(1, 0, 0);
Vector3 pt2 = new(0, 0, 0);
Vector3 pt3 = new(0, 0, 1);
Vector3 pt4 = new(1, 0, 1);
Vector3 pt5 = new(0, 1, 0);
Инициализируйте вершины и индексы для рисунка Triangle 1:
Vertex3D[] meshTriangle1Vertices = new Vertex3D[]
{
    new Vertex3D() { Position = pt2,  Normal = new Vector3(0, 0, 1) },
    new Vertex3D() { Position = pt5,  Normal = new Vector3(0, 0, 1) },
    new Vertex3D() { Position = pt1,  Normal = new Vector3(0, 0, 1) },
};
// Define a mesh triangle.
uint[] meshTriangle1Indices = new uint[] { 0, 1, 2 };
meshTriangle1.Vertices = meshTriangle1Vertices;
meshTriangle1.Indices = meshTriangle1Indices;
Здесь индексы 0, 1 и 2 относятся к первой, второй и третьей вершинам массива Vertices.
Аналогично, инициализируйте вершины и индексы для рисунка Triangle 2:
Vertex3D[] meshTriangle2Vertices = new Vertex3D[]
{
    new Vertex3D() { Position = pt2,  Normal = new Vector3(1, 0, 0) },
    new Vertex3D() { Position = pt5,  Normal = new Vector3(1, 0, 0) },
    new Vertex3D() { Position = pt3,  Normal = new Vector3(1, 0, 0) }
};
// Define a mesh triangle.
uint[] meshTriangle2Indices = new uint[] { 0, 1, 2 };
meshTriangle2.Vertices = meshTriangle2Vertices;
meshTriangle2.Indices = meshTriangle2Indices;
Определяем сетки для квадратной фигуры¶
Рисунок Square можно разделить на два сетчатых треугольника. Например:

Массив Vertices для сетки Square должен содержать четыре точки. Массив Indices должен содержать шесть индексов, которые идентифицируют два треугольника сетки. 
Vertex3D[] meshSquareVertices = new Vertex3D[]
{
    new Vertex3D() { Position = pt1,  Normal = new Vector3(0, 1, 0) },
    new Vertex3D() { Position = pt2,  Normal = new Vector3(0, 1, 0) },
    new Vertex3D() { Position = pt3,  Normal = new Vector3(0, 1, 0) },
    new Vertex3D() { Position = pt4,  Normal = new Vector3(0, 1, 0) }
};
// Define two mesh triangles.
// The first mesh triangle is formed by points pt1, pt2 and pt4.
// The second mesh triangle is formed by points pt2, pt3 and pt4.
uint[] meshSquareIndices = new uint[] { 0, 1, 3, 1, 2, 3 };
meshSquare.Vertices = meshSquareVertices;
meshSquare.Indices = meshSquareIndices;
Укажите материалы¶
Контрол Graphics3DControl поддерживает следующие материалы, производные от абстрактного класса Eremex.AvaloniaUI.Controls3D.Material:
- 
SimplePbrMaterial— Материал, который описывает визуальные свойства поверхности в виде числовых значений:- Albedo— Базовый цвет
- Alpha— Прозрачность
- Emission— Интенсивность света, излучаемого поверхностью
- AmbientOcclusion— Уровень затемнения, вызванного объектами, блокирующими окружающий свет
- Roughness— Гладкость поверхности
- Metallic— Отражательная способность поверхности.
 
- 
TexturedPbrMaterial— Текстурированный материал в формате PBR. Этот материал позволяет задать визуальные свойства (Albedo,Alpha,Emission,AmbientOcclusion,Roughness,MetallicиNormal) поверхности в виде растровых изображений.
Вам необходимо присвоить уникальные ключи (строковые значения) материалам, используя свойство Material.Key. 
Затем вы можете привязать материал к сетке с помощью свойства MeshGeometry3D.MaterialKey.
Следующий код добавляет три материала (объекты SimplePbrMaterial) с определенными базовыми цветами (Albedo). Созданные сетки связаны с материалами с помощью свойства MaterialKey.
using DynamicData;
g3DControl.Materials.AddRange(
    new[] {
        new SimplePbrMaterial(Color.FromUInt32(0xFF822c2e), "BrownColor"),
        new SimplePbrMaterial(Color.FromUInt32(0xffeb523f), "TomatoColor"),
        new SimplePbrMaterial(Color.FromUInt32(0xFFea3699), "VioletColor")
    }
);
//...
meshTriangle1.MaterialKey = "VioletColor";
meshTriangle2.MaterialKey = "TomatoColor";
meshSquare.MaterialKey = "BrownColor";
Запустите приложение¶
Теперь вы можете запускать приложение. Используйте мышь и клавиатуру для панорамирования, масштабирования и поворота созданной 3D-модели.

Полный код¶
<mx:MxWindow xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="using:G3DControl_Get_Started.ViewModels"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:mx="https://schemas.eremexcontrols.net/avalonia"
        xmlns:mx3d="https://schemas.eremexcontrols.net/avalonia/controls3d"
        xmlns:mxe="https://schemas.eremexcontrols.net/avalonia/editors"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        x:Class="G3DControl_Get_Started.Views.MainWindow"
        x:DataType="vm:MainWindowViewModel"
        Icon="/Assets/EMXControls.ico"
        Title="G3DControl_Get_Started">
    <Design.DataContext>
        <!-- This only sets the DataContext for the previewer in an IDE -->
        <vm:MainWindowViewModel/>
    </Design.DataContext>
    <mx3d:Graphics3DControl Name="g3DControl" ShowAxes="True">
        <mx3d:Graphics3DControl.Camera>
            <mx3d:IsometricCamera/>
        </mx3d:Graphics3DControl.Camera>
    </mx3d:Graphics3DControl>
</mx:MxWindow>
using Avalonia.Controls;
using Avalonia.Media;
using DynamicData;
using Eremex.AvaloniaUI.Controls.Common;
using Eremex.AvaloniaUI.Controls3D;
using System;
using System.Numerics;
namespace G3DControl_Get_Started.Views;
public partial class MainWindow : MxWindow
{
    public MainWindow()
    {
        InitializeComponent();
        InitG3DControlMaterials();
        InitG3DControlMeshes();
    }
    private void InitG3DControlMaterials()
    {
        g3DControl.Materials.AddRange(
            new[] {
                new SimplePbrMaterial(Color.FromUInt32(0xFF822c2e), "BrownColor"),
                new SimplePbrMaterial(Color.FromUInt32(0xffeb523f), "TomatoColor"),
                new SimplePbrMaterial(Color.FromUInt32(0xFFea3699), "VioletColor")
            }
        );
    }
    private void InitG3DControlMeshes()
    {
        GeometryModel3D model = new GeometryModel3D();
        g3DControl.Models.Add(model);
        Vector3 pt1 = new(1, 0, 0);
        Vector3 pt2 = new(0, 0, 0);
        Vector3 pt3 = new(0, 0, 1);
        Vector3 pt4 = new(1, 0, 1);
        Vector3 pt5 = new(0, 1, 0);
        // Triangle 1
        MeshGeometry3D meshTriangle1 = new MeshGeometry3D();
        // Setting the FillType property to 'Triangles' is not required
        // as 'Triangles' is the default value of the FillType property.
        //meshTriangle1.FillType = MeshFillType.Triangles;
        Vertex3D[] meshTriangle1Vertices = new Vertex3D[]
        {
            new Vertex3D() { Position = pt2,  Normal = new Vector3(0, 0, 1) },
            new Vertex3D() { Position = pt5,  Normal = new Vector3(0, 0, 1) },
            new Vertex3D() { Position = pt1,  Normal = new Vector3(0, 0, 1) },
        };
        // Define a mesh triangle.
        uint[] meshTriangle1Indices = new uint[] { 0, 2, 1 };
        meshTriangle1.Vertices = meshTriangle1Vertices;
        meshTriangle1.Indices = meshTriangle1Indices;
        meshTriangle1.MaterialKey = "VioletColor";
        // Triangle 2
        MeshGeometry3D meshTriangle2 = new MeshGeometry3D();
        Vertex3D[] meshTriangle2Vertices = new Vertex3D[]
        {
            new Vertex3D() { Position = pt2,  Normal = new Vector3(1, 0, 0) },
            new Vertex3D() { Position = pt5,  Normal = new Vector3(1, 0, 0) },
            new Vertex3D() { Position = pt3,  Normal = new Vector3(1, 0, 0) }
        };
        // Define a mesh triangle.
        uint[] meshTriangle2Indices = new uint[] { 0, 2, 1 };
        meshTriangle2.Vertices = meshTriangle2Vertices;
        meshTriangle2.Indices = meshTriangle2Indices;
        meshTriangle2.MaterialKey = "TomatoColor";
        // Square
        MeshGeometry3D meshSquare = new MeshGeometry3D();
        Vertex3D[] meshSquareVertices = new Vertex3D[]
        {
            new Vertex3D() { Position = pt1,  Normal = new Vector3(0, 1, 0) },
            new Vertex3D() { Position = pt2,  Normal = new Vector3(0, 1, 0) },
            new Vertex3D() { Position = pt3,  Normal = new Vector3(0, 1, 0) },
            new Vertex3D() { Position = pt4,  Normal = new Vector3(0, 1, 0) }
        };
        // Define two mesh triangles.
        // The first mesh triangle is formed by points pt1, pt2 and pt4.
        // The second mesh triangle is formed by points pt2, pt3 and pt4.
        uint[] meshSquareIndices = new uint[] { 0, 1, 3, 1, 2, 3 };
        meshSquare.Vertices = meshSquareVertices;
        meshSquare.Indices = meshSquareIndices;
        meshSquare.MaterialKey = "BrownColor";
        model.Meshes.AddRange(new[] { meshTriangle1, meshTriangle2, meshSquare });
    }
}
* Эта страница была создана автоматически с помощью сервиса машинного перевода Яндекс Переводчик.