Skip to content

Обзор Graphics3DControl

Контрол Graphics3DControl позволяет встраивать 3D-модели в ваше приложение Avalonia. Контрол поддерживает операции поворота, панорамирования и масштабирования с помощью мыши и клавиатуры, позволяя пользователю взаимодействовать с моделями во время выполнения программы.

g3dControl-overview

Любая 3D-модель состоит из сеток, рисованных с использованием определенных материалов. Graphics3DControl предоставляет API для определения сеток, материалов, свойств камеры и освещения. Вы также можете использовать сторонние библиотеки для загрузки моделей в форматах OBJ и STL в контрол Graphics3DControl.

Основные характеристики

  • API для задания 3D-моделей
  • Одновременное отображение нескольких 3D-моделей
  • Перспективные и изометрические камеры
  • Поддерживаемые типы сеток: треугольные, линии и точки
  • Простые и текстурированные материалы
  • Преобразования 3D-моделей
  • Отбраковка спереди и сзади
  • Поддержка шаблона проектирования MVVM для определения 3D-моделей
  • Отображение осей и сеток

Взаимодействие с пользователем

  • Поворачивайте, перемещайте и масштабируйте модели с помощью мыши и клавиатуры
  • Подсказки
  • Выделение элементов

Смотрите раздел Взаимодействие пользователя с 3D-моделями

Начало работы

Демонстрации

Ознакомьтесь с приложением Eremex Avalonia Controls Demo, которое содержит примеры, демонстрирующие различные возможности Graphics3DControl:

  • Загрузка моделей Wavefront (Obj) и Stl из внешних файлов с использованием сторонних библиотек и создание 3D-моделей на основе загруженных данных.
  • Создание 3D-моделей с нуля.
  • Демонстрация поддерживаемых типов сеток: треугольных, линий и точек.
  • Использование шаблона проектирования MVVM для определения 3D-моделей и многого другого.

Система координат, оси и сетки

Graphics3DControl поддерживает правостороннюю (по умолчанию) и левостороннюю системы координат. Вы можете использовать свойство Graphics3DControl.CoordinateSystem, чтобы включить требуемую опцию.

<mx3d:Graphics3DControl Name="g3DControl" ShowAxes="True" CoordinateSystem="LeftHanded" ...>

Правосторонняя система координат

Положительные оси X, Y и Z направлены вправо, вверх и в сторону зрителя соответственно.

g3d-coordinate-system-righthanded

Левосторонняя система координат

Положительные оси X, Y и Z направлены вправо, вверх и в сторону от наблюдателя соответственно.

g3d-coordinate-system-lefthanded

Оси

Включите свойство Graphics3DControl.ShowAxes для отображения осей X, Y и Z в контроле.

g3d-showaxes

<mx3d:Graphics3DControl Name="g3DControl" ShowAxes="True"/>

Связанные опции

  • Свойство Graphics3DControl.AxisThickness — определяет толщину осей.

Gizmo

Graphics3DControl может отображать какую-либо штуковину. Это виджет, который визуально указывает текущую ориентацию осей.

g3d-gizmo

Чтобы включить Gizmo, инициализируйте свойство Graphics3DControl.Gizmo экземпляром класса Eremex.AvaloniaUI.Controls3D.Gizmo.

<mx3d:Graphics3DControl Name="g3DControl" >
        <!-- ... -->
    <mx3d:Graphics3DControl.Gizmo>
        <mx3d:Gizmo Name="gizmo" />
    </mx3d:Graphics3DControl.Gizmo>
</mx3d:Graphics3DControl>

Сетки

Свойство Graphics3DControl.ShowGrid позволяет отображать сетки на плоскостях XY, XZ и YZ.

![g3d-grid](../../images/g3d-grid.png)

<mx3d:Graphics3DControl Name="g3DControl" ShowGrid="True"/>

Связанные опции

  • Свойство Graphics3DControl.GridThickness — определяет толщину линий сетки.

Модели

Чтобы определить 3D-модели для Graphics3DControl, используйте API Graphics3DControl для создания объектов, представляющих модели, сетки, вершины, материалы, камеры и т.д.

Определение 3D-моделей

Класс GeometryModel3D инкапсулирует единую 3D-модель в Graphics3DControl. Используйте одно из следующих свойств, чтобы добавить 3D-модели в контрол:

  • Graphics3DControl.Models — Коллекция объектов GeometryModel3D.
  • Graphics3DControl.ModelsSource — Источник бизнес-объектов, используемых для создания 3D-моделей (объектов GeometryModel3D) в соответствии с шаблоном проектирования MVVM.
xmlns:mx3d="https://schemas.eremexcontrols.net/avalonia/controls3d"

<mx3d:Graphics3DControl Name="g3DControl" ShowAxes="True"/>
using Eremex.AvaloniaUI.Controls3D;

GeometryModel3D model = new GeometryModel3D();
g3DControl.Models.Add(model);

Сетки

3D-модель представляет собой набор сеток, отрисованных с использованием определенных материалов. Сетки определяют форму и структуру 3D-объекта.

Класс MeshGeometry3D представляет сетку в Graphics3DControl. Следующие свойства позволяют задавать сетки для модели:

  • GeometryModel3D.Meshes — Коллекция объектов MeshGeometry3D.
  • GeometryModel3D.MeshesSource — Источник бизнес-объектов, используемых для создания сеток (объекты MeshGeometry3D) в соответствии с шаблоном проектирования MVVM.

Контрол поддерживает три типа сетки, которые вы можете выбрать с помощью свойства MeshGeometry3D.FillType.

  • MeshFillType.Triangles (по умолчанию) — Треугольная сетка. Состоит из треугольных граней (плоских областей, ограниченных тремя ребрами).

g3d-mesh-triangle

  • MeshFillType.Lines — сетка линии. Вершины соединяются линиями, образуя каркас.

g3d-mesh-lines

  • MeshFillType.Points — Точечная сетка (облако точек). Состоит из вершин, которые не соединены линиями.

g3d-mesh-points

using DynamicData;

MeshGeometry3D meshTriangle1 = new MeshGeometry3D();
MeshGeometry3D meshSquare = new MeshGeometry3D();
MeshGeometry3D meshPoints = new MeshGeometry3D() { FillType = MeshFillType.Points };
//Define the meshes
//...
model.Meshes.AddRange(new[] { meshTriangle1, meshSquare, meshPoints });

При создании сетки используйте следующие свойства для определения вершин и граней/линий:

  • Массив MeshGeometry3D.Vertices — определяет массив всех вершин, составляющих сетку.
  • Массив MeshGeometry3D.Indices — определяет треугольные грани (для треугольной сетки) или линии (для сетки линий).

Вершины

Вершина - это точка в трехмерном пространстве, определяемая ее координатами (x, y, z).

Тип Vertex3D инкапсулирует единственную вершину в Graphics3DControl. Используйте массив MeshGeometry3D.Vertices для добавления вершин в сетку.

Тип Vertex3D предоставляет следующие основные свойства, которые необходимо инициализировать.

  • Vertex3D.Position — значение Vector3, которое определяет координаты вершины (x, y, z).
  • Vertex3D.Normal — Значение Vector3, задающее нормаль к вершине. Нормаль к вершине - это вектор, перпендикулярный поверхности 3D-модели в этой вершине. В 3D-графике нормали к вершинам используются для расчета освещения и затенения сетки. Нормали соседних треугольников должны быть выровнены для обеспечения плавного затенения (ребер).

g3d-vertex-normals

  • Vertex3D.TextureCoord — значение Vector2, задающее координаты (x, y) точки в текстурированном материале, которая сопоставлена с текущей вершиной.

Определяем треугольную сетку

Чтобы создать треугольную сетку, вам нужно разделить фигуру на треугольники. Вершины задают углы треугольников. Для свойства MeshGeometry3D.FillType необходимо установить значение по умолчанию (MeshFillType.Triangles).

Рассмотрим пример, в котором сетка имеет форму четырехугольника. Ее можно триангулировать, добавив одну диагональ.

g3d-triangle-mesh-quad-coords

Сначала добавьте все вершины в массив MeshGeometry3D.Vertices.

<mx3d:Graphics3DControl Name="g3DControl" ShowAxes="True"/>
using DynamicData;

GeometryModel3D model = new GeometryModel3D();
g3DControl.Models.Add(model);

Vector3 pt1 = new(2f, 0, 0);
Vector3 pt2 = new(0, 0, 0);
Vector3 pt3 = new(0, 0, 1);
Vector3 pt4 = new(2f, 0, 1);

MeshGeometry3D meshSquare = new MeshGeometry3D();
meshSquare.FillType = MeshFillType.Triangles;
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) }
};
meshSquare.Vertices = meshSquareVertices;
//...
model.Meshes.AddRange(new[] { meshSquare });

Затем используйте свойство MeshGeometry3D.Indices для формирования граней треугольника.

Для треугольной сетки свойство MeshGeometry3D.Indices представляет собой массив индексов вершин в массиве MeshGeometry3D.Vertices, которые определяют отдельные треугольники сетки. Этот массив содержит группы индексов three в каждой. Первые три индекса в массиве относятся к вершинам первого сетчатого треугольника. Следующие три индекса относятся к вершинам второго сетчатого треугольника и так далее. Порядок расположения индексов для каждого треугольника важен, поскольку он определяет нормаль к поверхности. Нормаль к поверхности, в свою очередь, определяет переднюю и заднюю стороны треугольника, что важно для таких операций, как отбраковка обратной и фронтальной сторон.

Для приведенной выше четырехъядерной сетки массив MeshGeometry3D.Indices должен содержать шесть индексов. Первые три индекса относятся к вершинам первого треугольника. Вторые три индекса относятся к вершинам второго треугольника.

uint[] meshSquareIndices = new uint[] { 0, 1, 3, 1, 2, 3 };
meshSquare.Indices = meshSquareIndices;

Определите сетку линий

В сетке с линиями вершины соединены линиями. Чтобы определить сетку линий, создайте объект MeshGeometry3D и установите для его свойства MeshGeometry3D.FillType значение MeshFillType.Lines. Затем используйте свойство MeshGeometry3D.Vertices, чтобы указать все вершины, и свойство MeshGeometry3D.Indices, чтобы соединить вершины линиями.

Рассмотрим следующую 3D-модель, состоящую из линий, соединяющих шесть точек.

g3d-triangle-mesh-lines-coords

Сначала добавьте все вершины в массив MeshGeometry3D.Vertices.

<mx3d:Graphics3DControl Name="g3DControl" ShowAxes="True"/>
GeometryModel3D model = new GeometryModel3D();
g3DControl.Models.Add(model);

Vector3 p0 = new(1, 0, 0);
Vector3 p1 = new(1, 1, 0);
Vector3 p2 = new(1, 1, 2);
Vector3 p3 = new(2, 1, 2);
Vector3 p4 = new(2, 1, 0);
Vector3 p5 = new(2, 2, 0);

MeshGeometry3D meshLines = new MeshGeometry3D();
meshLines.PrimitiveSize = 3;
meshLines.FillType = MeshFillType.Lines;
Vertex3D[] meshLinesVertices = new Vertex3D[]
{
    new Vertex3D() { Position = p0,  Normal = new Vector3(0, 1, 0) },
    new Vertex3D() { Position = p1,  Normal = new Vector3(0, 1, 0) },
    new Vertex3D() { Position = p2,  Normal = new Vector3(0, 1, 0) },
    new Vertex3D() { Position = p3,  Normal = new Vector3(0, 1, 0) },
    new Vertex3D() { Position = p4,  Normal = new Vector3(0, 1, 0) },
    new Vertex3D() { Position = p5,  Normal = new Vector3(0, 1, 0) }
};
meshLines.Vertices = meshLinesVertices;
//...
model.Meshes.Add(meshLines);

Используйте свойство MeshGeometry3D.Indices, чтобы соединить вершины линиями. Для сетки линий свойство MeshGeometry3D.Indices представляет собой массив индексов вершин в массиве MeshGeometry3D.Vertices, которые определяют отдельные линии. Этот массив содержит пары индексов. Первые два индекса в массиве относятся к вершинам первой линии. Следующие два индекса относятся к вершинам второй линии и так далее.

В приведенном выше примере массив MeshGeometry3D.Indices должен содержать 10 индексов. Первая пара индексов относится к точкам, которые определяют первую линию. Вторая пара индексов относится к вершинам второй линии и так далее.

uint[] meshLinesIndices = new uint[] { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5 };
meshLines.Indices = meshLinesIndices;

Толщина линий

В сетке линий используйте свойство PrimitiveSize, чтобы изменить толщину линий.

Определение точечной сетки

В точечной сетке вершины отображаются как отдельные точки.

Чтобы определить точечную сетку, создайте объект MeshGeometry3D и задайте его свойству MeshGeometry3D.FillType значение MeshFillType.Points. Затем используйте свойство MeshGeometry3D.Vertices, чтобы указать все вершины, и свойство MeshGeometry3D.Indices, чтобы указать, какие вершины отображать.

Давайте создадим точечную сетку, образующую спираль, в которой точки расположены в размещении в плоскости XY.

g3d-point-mesh-spiral

int pointCount = 500;

GeometryModel3D model = new GeometryModel3D();
g3DControl.Models.Add(model);
var vertices = new Vertex3D[pointCount];
var indices = new uint[pointCount];
MeshGeometry3D meshPoints = new MeshGeometry3D();
meshPoints.PrimitiveSize = 3;
meshPoints.MaterialKey = "pointsMaterial";
meshPoints.FillType = MeshFillType.Points;
double radius = 0;
double angle = 0;
double radiusStep = 0.1;
double angleStep = 0.1;
for (uint i = 0; i < pointCount; i++)
{
    double x = radius * Math.Cos(angle);
    double y = radius * Math.Sin(angle);
    vertices[i] = new Vertex3D() { 
        // Vertex coordinates:
        Position = new Vector3((float)x, (float)y, 0), 
        // Normalized coordinates of a position in the texture mapped to the current vertex:
        TextureCoord= new Vector2((float)i/pointCount, 0) 
    };
    radius += radiusStep;
    angle += angleStep;
    indices[i] = i;
}
meshPoints.Vertices = vertices;
meshPoints.Indices = indices;
model.Meshes.Add(meshPoints);

Вы можете раскрасить вершины в точечной сетке разными цветами. Например, вершины можно рисовать цветами, определяемыми их позициями или координатами.

Приведенный ниже код показывает, как использовать текстурированный материал для раскрашивания вершин. Индекс вершины определяет ее цвет (позицию в следующем цветовом градиенте).

g3d-point-mesh-color-gradient-example

  1. Добавьте текстурированный материал (TexturedPbrMaterial) в коллекцию Graphics3DControl.Materials. Текстурированный материал представляет собой набор растровых изображений, которые задают следующие свойства текстуры:

    • Albedo — Базовый цвет
    • Alpha — Прозрачность
    • Emission — Интенсивность света, излучаемого поверхностью
    • AmbientOcclusion — Уровень затемнения, вызванного объектами, блокирующими окружающий свет
    • Roughness — Гладкость поверхности
    • Metallic — свойства отражательной способности поверхности

    Вершины позже сопоставляются с определенными позициями в этих текстурных растровых изображениях.

    Чтобы убедиться, что вершины отображают реалистичные цвета из целевого цветового градиента, настройте текстурные растровые изображения следующим образом:

    • Установите для TexturedPbrMaterial.Emission значение градиентного растрового изображения, которое определяет реальный цвет вершин.
    • Установите для TexturedPbrMaterial.Albedo значение растрового изображения, заполненного черным цветом.
    • Установите для TexturedPbrMaterial.Roughness и TexturedPbrMaterial.AmbientOcclusion значения растровых изображений, которые будут заполнены белым цветом.
    using DynamicData;
    using Avalonia.Media;
    
    public void InitG3DControlMaterials()
    {
        g3DControl.Materials.AddRange(
            new[] {
                new TexturedPbrMaterial(){
                    Albedo = getSolidColorBitmap(Colors.Black),
                    Roughness = getSolidColorBitmap(Colors.White),
                    AmbientOcclusion = getSolidColorBitmap(Colors.White),
                    Emission = getGradientColorBitmap(Colors.DodgerBlue, Colors.Red), 
                    Key= "pointsMaterial"
                }
            }
        );
    }
    
    Bitmap getSolidColorBitmap(Color fillColor)
    {
        var bitmap = new RenderTargetBitmap(new PixelSize(pointCount, 1));
        using (var context = bitmap.CreateDrawingContext())
        {
            Brush brush = new SolidColorBrush(fillColor);
            context.FillRectangle(brush, new Rect(0, 0, pointCount, 1));
        }
        return bitmap;
    }
    
    Bitmap getGradientColorBitmap(Color fillColor1, Color fillColor2)
    {
        var bitmap = new RenderTargetBitmap(new PixelSize(pointCount, 1));
        using (var context = bitmap.CreateDrawingContext())
        {
            var gradientBrush = new LinearGradientBrush
            {
                StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
                EndPoint = new RelativePoint(1, 1, RelativeUnit.Relative),
                GradientStops = {
                    new GradientStop(fillColor1, 0.0),
                    new GradientStop(fillColor2, 1.0)
                }
            };
    
            context.FillRectangle(gradientBrush, new Rect(0, 0, pointCount, 1));
        }
        return bitmap;
    }
    

    Свойству материала TexturedPbrMaterial.Key присвоено значение уникального ключа (строки). Уникальные ключи позволяют идентифицировать материалы из коллекции Graphics3DControl.Materials.

  2. Назначьте созданный материал сетке, используя свойство MeshGeometry3D.MaterialKey. Свойство MeshGeometry3D.MaterialKey должно соответствовать значению свойства TexturedPbrMaterial.Key.

    meshPoints.MaterialKey = "pointsMaterial";
    
  3. Используйте свойство Vertex3D.TextureCoord для сопоставления вершин с определенными позициями в текстуре. Это свойство должно указывать нормализованные координаты. Значения TextureCoord.X и TextureCoord.Y должны находиться в диапазоне от 0 до 1, где 0 соответствует левому или верхнему краю текстурного растрового изображения, а 1 соответствует правому или нижнему краю текстурного растрового изображения.

    Когда вершины будут созданы, укажите свойство Vertex3D.TextureCoord для обращения к целевым позициям в текстуре.

    vertices[i] = new Vertex3D() { 
        // Vertex coordinates:
        Position = new Vector3((float)x, (float)y, 0), 
        // Normalized coordinates of a position in the texture mapped to the current vertex:
        TextureCoord= new Vector2((float)i/pointCount, 0) 
    };
    

    Теперь вершины раскрашиваются с использованием указанного градиента.

Количество точек

В точечной сетке используйте свойство PrimitiveSize, чтобы изменить толщину точек.

Видимость модели

Используйте свойство GeometryModel3D.Visible, чтобы временно скрыть, а затем восстановить модель.

GeometryModel3D model = new GeometryModel3D();
g3DControl.Models.Add(model);
//...
model.Visible = !model.Visible;

Преобразования моделей

Graphics3DControl позволяет выполнять преобразования моделей. Для этой цели создайте матрицу преобразования, которая поворачивает, масштабирует и/или преобразует модель. После создания присвойте этой матрице свойство GeometryModel3D.Transform.

Чтобы отменить текущее преобразование, присвойте свойству GeometryModel3D.Transform значение объекта Matrix4x4.Identity.

Класс Matrix4x4 предоставляет методы для генерации матриц преобразований для различных типов преобразований. Некоторые из этих методов включают:

  • Matrix4x4.CreateRotationX — Генерирует матрицу преобразования, которая представляет поворот вокруг оси X на заданный угол.
  • Matrix4x4.CreateRotationY — Генерирует матрицу преобразования, которая представляет поворот вокруг оси Y на заданный угол.
  • Matrix4x4.CreateRotationZ — Генерирует матрицу преобразования, которая представляет поворот вокруг оси Z на заданный угол.
  • Matrix4x4.CreateTranslation — Генерирует матрицу преобразования, которая перемещает объект на заданное смещение вдоль осей X, Y и Z.
  • Matrix4x4.CreateScale — Генерирует матрицу преобразования, которая масштабирует объект по осям X, Y и Z.

Чтобы применить несколько преобразований одновременно, вы можете умножить матрицы, которые выполняют отдельные преобразования.

Пример - Поворот модели

В следующем примере создается анимация, которая вращает 3D-модель (спираль, состоящую из точек). Метод Matrix4x4.CreateRotationZ вызывается для генерации матрицы преобразования, которая поворачивает модель на заданный угол вокруг оси Z. Чтобы применить преобразование, этой матрице присваивается свойство GeometryModel3D.Transform.

g3dControl-rotateZ-animation

GeometryModel3D model;
//Init the model
//...
float angleStep = MathF.PI / 180;
float angle = 0;

private void BtnRotate_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
    for (int i = 0; i < 180; i++) 
    {
        angle += angleStep;
        Matrix4x4 rotationMatrix = Matrix4x4.CreateRotationZ(angle);
        model.Transform = rotationMatrix;
        // Update the UI
        Dispatcher.UIThread.RunJobs();
        Thread.Sleep(12);
    }
}

Пример - Выполнение нескольких преобразований

В следующем примере создается 3D-модель, которая отображает треугольник, и показано, как выполнить несколько преобразований над моделью.

В примере операции масштабирования, поворота и перемещения объединены в единую матрицу преобразования, а затем для применения преобразований этой матрице присваивается свойство GeometryModel3D.Transform.

В этом примере к матрицам преобразования применяются небольшие постепенные изменения, создающие плавный анимационный эффект.

g3dControl-multiple-transformations-animation

xmlns:mx3d="https://schemas.eremexcontrols.net/avalonia/controls3d"

<mx3d:Graphics3DControl Name="g3DControl" ShowAxes="True" Grid.Row="1"/>
using DynamicData;

public MainWindow()
{
    InitG3dControl();
}

private void InitG3dControl()
{
    // Create a 3D model that renders a triangle.
    GeometryModel3D model = new GeometryModel3D();
    g3DControl.Models.Add(model);
    Vector3 pt1 = new(1f, 0, 0);
    Vector3 pt2 = new(0, 0, 0);
    Vector3 pt3 = new(0, 0, 1);
    MeshGeometry3D meshSquare = new MeshGeometry3D();
    meshSquare.FillType = MeshFillType.Triangles;
    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) }
    };
    uint[] meshSquareIndices = new uint[] { 0, 1, 2 };
    meshSquare.Indices = meshSquareIndices;
    meshSquare.Vertices = meshSquareVertices;
    model.Meshes.AddRange(new[] { meshSquare });
    this.model = model;
}

//Transform the model
private void BtnRotate_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
    int steps = 100;
    Vector3 stepTranslationVector = new Vector3(-0.5f, 0, 0)/steps;
    Vector3 stepScaleVector = new Vector3(-0.5f, 0, 0.1f)/steps;
    float stepRotationAngle = (MathF.PI/2)/steps;

    Vector3 translationVector = new Vector3(0,0,0), 
        scaleVector = new Vector3(1, 1, 1);
    float rotationAngle = 0;

    for (int i = 0; i < steps; i++)
    {
        rotationAngle += stepRotationAngle;
        translationVector += stepTranslationVector;
        scaleVector += stepScaleVector;

        // Translation Matrix (move by)
        Matrix4x4 translationMatrix = Matrix4x4.CreateTranslation(translationVector);
        // Scaling Matrix
        Matrix4x4 scalingMatrix = Matrix4x4.CreateScale(scaleVector);
        // Rotation Matrix
        Matrix4x4 rotationMatrix = Matrix4x4.CreateRotationY(rotationAngle);
        rotationMatrix *= Matrix4x4.CreateRotationX(rotationAngle);

        Matrix4x4 combinedMatrix = Matrix4x4.Identity;
        combinedMatrix *= scalingMatrix;
        combinedMatrix *= rotationMatrix;
        combinedMatrix *= translationMatrix;

        model.Transform = combinedMatrix;
        // Update the UI
        Dispatcher.UIThread.RunJobs();
        Thread.Sleep(12);
    }
}

Мультисэмплинг (сглаживание)

  • Graphics3DControl.MultisamplingMode — Активирует сглаживание с несколькими выборками (MSAA) или отключает его.

Функция сглаживания используется для уменьшения визуальных искажений, таких как неровные края (сглаживание псевдонимов), в визуализируемой графике, обеспечивая более плавные и точные результаты.

g3dcontrol-multisampling

Свойству MultisamplingMode можно присвоить следующие значения: None, X2, X4, X8, X16, X32, X64. X2...Значения X64 определяют количество точек выборки на пиксель для расчета конечного цвета пикселя. Большее количество выборок приводит к лучшим результатам, однако это также требует больших вычислительных затрат.

  • Значением свойства MultisamplingMode по умолчанию является X8.
  • Возможно, ваш графический процессор поддерживает не все режимы MSAA. Если выбран неподдерживаемый режим MSAA, система возвращается к более низкому доступному режиму. Вы можете использовать свойство Graphics3DControl.AvailableMultisamplingModes, чтобы вернуть список режимов MSAA, поддерживаемых вашим графическим драйвером.
  • Мультисэмплинг для больших 3D-моделей увеличивает использование памяти и вычислительные затраты. Чтобы повысить производительность приложения в таких случаях, рассмотрите возможность установки для свойства MultisamplingMode меньшего значения или отключения MSAA.

Материалы

Каждая сетка в контроле Graphics3DControl может быть рисована своим собственным материалом. Материал определяет, как поверхности взаимодействуют со светом, придавая объектам их визуальный вид.

Контрол Graphics3DControl поддерживает два типа материалов:

  • SimplePbrMaterial — Материал, который определяет визуальные свойства поверхности с помощью числовых значений, таких как цвета (например, альбедо и излучение) и свойства взаимодействия света (например, металлический оттенок и шероховатость). Для получения дополнительной информации смотрите Простые материалы (SimplePbrMaterial)

  • TexturedPbrMaterial — Текстурированный материал в формате PBR. Этот материал определяет визуальные свойства поверхности с помощью текстур (растровых изображений). Дополнительную информацию смотрите в разделе Текстурированные материалы (TexturedPbrMaterial)

Чтобы нанести материалы на сетки, выполните следующие действия:

  1. Создавайте и инициализируйте материалы.
  2. Присвойте свойству Key для материалов значение уникальных строк. Ключи позволяют идентифицировать материал при назначении материалов сеткам.
  3. Добавьте материалы в коллекцию Graphics3DControl.Materials.
  4. Используйте свойство MeshGeometry3D.MaterialKey, чтобы привязать сетку к определенному материалу. Для этой цели установите для свойства MeshGeometry3D.MaterialKey значение свойства Key целевого материала.

Пример - Назначение материала для сетки

В следующем примере создаются три материала (объекты SimplePbrMaterial) и один из этих материалов применяется к сетке. Созданные материалы идентифицируются с помощью уникальных строковых ключей ("BrownColor", "TomatoColor" и "VioletColor").

using DynamicData;

g3DControl.Materials.AddRange(
    new[] {
        new SimplePbrMaterial(Color.FromUInt32(0xFF822c2e), "BrownColor"),
        new SimplePbrMaterial(Color.FromUInt32(0xffeb523f), "TomatoColor"),
        new SimplePbrMaterial(Color.FromUInt32(0xFFea3699), "VioletColor")
    }
);

//...

mesh1.MaterialKey = "VioletColor";

Простые материалы (SimplePbrMaterial)

SimplePbrMaterial - это материал, который описывает визуальные свойства поверхности в виде числовых значений. Он предоставляет следующие элементы для указания визуальных свойств:

  • Albedo — Базовый цвет.

    Значением свойства является объект Vector3, элементы X, Y и Z которого задают нормализованные значения для компонентов красного, зеленого и синего цветов. Нормализованные значения находятся в диапазоне [0;1]. Чтобы преобразовать стандартную цветовую составляющую (0-255) в нормализованное значение, разделите ее на 255. Вы также можете использовать конструктор SimplePbrMaterial для инициализации свойств Albedo и Alpha из указанного объекта Color. Этот конструктор автоматически нормализует цветовые компоненты.

  • Alpha — Уровень прозрачности.

    Значение свойства должно находиться в диапазоне [0;1], где 0 означает полностью прозрачный, а 1 означает полностью непрозрачный.

  • Emission — Интенсивность света, излучаемого поверхностью.

    Значением свойства является объект Vector3, элементы X, Y и Z которого задают нормализованные значения для компонентов красного, зеленого и синего цветов. Нормализованные значения находятся в диапазоне [0;1]. Чтобы преобразовать стандартную цветовую составляющую (0-255) в нормализованное значение, разделите ее на 255.

  • AmbientOcclusion — Уровень затемнения, вызванного объектами, блокирующими окружающий свет.

    Значение свойства должно находиться в диапазоне [0;1], где 0 означает, что применяется максимальный эффект внешней окклюзии, а 1 означает, что внешняя окклюзия не применяется.

  • Roughness — Гладкость поверхности.

    Значение свойства должно находиться в диапазоне [0;1], где 0 означает идеально гладкую и глянцевую поверхность, а 1 означает полностью шероховатую и матовую поверхность.

  • Metallic — Отражательная способность поверхности.

    Значение свойства должно находиться в диапазоне [0;1], где 0 означает неметаллическую поверхность, а 1 означает полностью металлический материал.

Демонстрация

Пример Simple Materials в демонстрационном приложении демонстрирует 3D-модель, рисованную с использованием простого материала. Демонстрация позволяет вам настраивать свойства материала в режиме реального времени и мгновенно видеть последствия ваших изменений.

g3d-simplematerials-demo

Пример - Применение простого материала к модели

Следующий код создает простой материал (объект SimplePbrMaterial) и применяет его к первой сетке 3D-модели. Свойству SimplePbrMaterial.Albedo присваивается значение базового цвета (бирюзовый) с использованием нормализованных цветовых координат.

SimplePbrMaterial material = new SimplePbrMaterial();
material.Albedo = ToNormalizedVector3(Colors.Teal);
material.Emission = ToNormalizedVector3(Colors.Black);
material.Metallic = 0;
material.Roughness = 0.5f;
material.AmbientOcclusion = 1;
material.Key = "myFavMaterial";
g3DControl.Materials.Add(material);

// Apply the material to the first mesh of the model
g3DControl.Models[0].Meshes[0].MaterialKey = "myFavMaterial";


public static Vector3 ToNormalizedVector3(Color color)
{
    return new Vector3(color.R/255f, color.G/255f, color.B/255f);
}

Этот материал, нанесенный на образец 3D-модели, показан ниже:

g3d-simplematerial-example

Текстурированные материалы (TexturedPbrMaterial)

TexturedPbrMaterial - это материал, который использует PBR-текстуры (растровые изображения) для определения визуальных свойств поверхности. Класс TexturedPbrMaterial предоставляет следующие элементы для настройки свойств материала:

  • Albedo — Растровое изображение, задающее базовый цвет материала.

  • Alpha — Растровое изображение, задающее уровень прозрачности.

  • Emission — Растровое изображение, которое определяет интенсивность света, излучаемого поверхностью.

  • AmbientOcclusion — Растровое изображение, которое определяет уровень затенения, вызванного объектами, блокирующими окружающий свет.

  • Roughness — Растровое изображение, которое определяет гладкость поверхности.

  • Metallic — Растровое изображение, определяющее отражательную способность поверхности.

  • Normal — Растровое изображение, которое определяет карту нормалей.

Демо

Пример Textured Materials в демонстрационном приложении демонстрирует 3D-модель, отрисованную с использованием текстур PBR. Текстуры загружаются из графических файлов, хранящихся в ресурсах приложения.

g3d-texturedmaterials-demo

Следующий фрагмент кода из демонстрации Textured Materials заполняет коллекцию Materials модели представления материалами (объектами TexturedPbrMaterial). Эти материалы созданы для всех текстур, которые хранятся в виде ZIP-файлов в ресурсах приложения, найденных в папке DemoCenter.Resources.Graphics3D.Materials. Для каждого материала, если ZIP-файл с текстурой содержит растровые изображения для свойств Albedo, AmbientOcclusion, Metallic, Roughness, Normal и Emission, эти растровые изображения загружаются и применяются к материалу.

public partial class Graphics3DControlTexturedMaterialsViewModel : Graphics3DControlViewModel
{
    [ObservableProperty] ObservableCollection<TexturedPbrMaterial> materials = new();
    [ObservableProperty] TexturedPbrMaterial selectedMaterial;

    public Graphics3DControlTexturedMaterialsViewModel()
    {
        var assembly = Assembly.GetAssembly(typeof(Graphics3DControlViewModel));
        var textureNames = assembly!.GetManifestResourceNames().Where(name => name.StartsWith("DemoCenter.Resources.Graphics3D.Materials."));
        foreach (var textureName in textureNames)
            materials.Add(LoadMaterial(assembly, textureName));
        selectedMaterial = Materials.First();
        //...
    }

    static TexturedPbrMaterial LoadMaterial(Assembly assembly, string resourceName)
    {
        var stream = assembly!.GetManifestResourceStream(resourceName);
        using var archive = new ZipArchive(stream!, ZipArchiveMode.Read);
        var material = new TexturedPbrMaterial { Key = resourceName.Split('.')[^2] };
        foreach (var entry in archive.Entries)
        {
            using var entryStream = entry.Open();
            using var memoryStream = new MemoryStream();
            entryStream.CopyTo(memoryStream);
            memoryStream.Seek(0, SeekOrigin.Begin);
            var bitmap = new Bitmap(memoryStream);
            if (entry.Name.StartsWith("Albedo"))
                material.Albedo = bitmap;
            else if (entry.Name.StartsWith("AO"))
                material.AmbientOcclusion = bitmap;
            else if (entry.Name.StartsWith("Metallic"))
                material.Metallic = bitmap;
            else if (entry.Name.StartsWith("Roughness"))
                material.Roughness = bitmap;
            else if (entry.Name.StartsWith("Normal"))
                material.Normal = bitmap;
            else if (entry.Name.StartsWith("Emissive"))
                material.Emission = bitmap;
        }
        return material;
    }
}

Приведенный ниже XAML-код из демонстрационной версии Textured Materials привязывает контрол Graphics3DControl к коллекции материалов в модели представления (Graphics3DControlTexturedMaterialsViewModel.Materials). Применяемый в данный момент материал определяется свойством Graphics3DControlTexturedMaterialsViewModel.SelectedMaterial.

<mx3d:Graphics3DControl x:Name="DemoControl" MaterialsSource="{Binding Materials}">
    <mx3d:GeometryModel3D>
        <mx3d:MeshGeometry3D Vertices="{Binding Vertices}" Indices="{Binding Indices}" MaterialKey="{Binding SelectedMaterial.Key}" />
    </mx3d:GeometryModel3D>
</mx3d:Graphics3DControl>

Координаты текстуры

Когда вы используете текстурированный материал, вам необходимо сопоставить текстуру с поверхностью. Для этого инициализируйте свойство Vertex3D.TextureCoord для вершин в вашей сетке. Это свойство определяет координаты текстуры (часто называемые координатами UV).

Координаты текстуры - это двумерные координаты (x, y), к которым привязана вершина.

  • x представляет собой горизонтальную координату в текстуре в диапазоне [0; 1], где 0 представляет левый край, а 1 представляет правый край картинки.

  • y представляет вертикальную координату текстуры в диапазоне [0; 1], где 0 представляет верхний край, а 1 представляет нижний край картинки.

Например, координата (x, y) вместо координаты (0.5, 0.5) будет выборкой пикселя в центре текстуры.

Примеры

Примеры, демонстрирующие использование свойства Vertex3D.TextureCoord:

Отбраковка обратной и лицевой сторон

Свойство Graphics3DControl.CullMode позволяет вам включить отбраковку задней и передней граней для треугольных сеток . Режим отбраковки определяет, какие грани 3D-модели следует нарисовать, а какие следует отбросить. Вы можете присвоить свойству Graphics3DControl.CullMode следующие значения:

  • CullMode.Back — Позволяет выполнять выбраковку обратной стороны, при которой не отображаются задние грани треугольников.

  • CullMode.Front — Позволяет выполнять выбраковку передних граней, при которой передние грани треугольников не отображаются.

  • CullMode.None — Нарисованы передняя и задняя грани.

Определение лицевой и оборотной сторон

Когда вы определяете треугольные грани для сетки, вы используете свойство MeshGeometry3D.Indices, чтобы указать индексы вершин, которые образуют каждый треугольник.

Порядок индексов для каждого треугольника сетки важен, поскольку он определяет направление нормали к поверхности и, следовательно, переднюю и заднюю части треугольника:

  • Если индексы треугольника пронумерованы против часовой стрелки, нормаль к поверхности направлена в сторону наблюдателя, и наблюдатель видит переднюю часть треугольника.

  • Если индексы треугольника пронумерованы по часовой стрелке, нормаль поверхности направлена в сторону от наблюдателя, и наблюдатель видит обратную сторону треугольника.

g3d-surface-normals

Пример

В этом примере демонстрируется функция отбраковки лиц. В этом примере создается модель, состоящая из двух треугольников. При отображении зритель видит переднюю часть первого (левого) треугольника и заднюю часть второго (правого) треугольника.

g3d-cullmode-example-initial

xmlns:mx3d="https://schemas.eremexcontrols.net/avalonia/controls3d"

<mx3d:Graphics3DControl Name="g3DControl" ShowAxes="True"/>
using Avalonia.Media;
using DynamicData;

GeometryModel3D model = new GeometryModel3D();
g3DControl.Models.Add(model);

Vector3 pt1 = new(-1f, 0, 0);
Vector3 pt2 = new(-0.5f, 0.5f, 0);
Vector3 pt3 = new(0, 0, 0);
Vector3 pt4 = new(0, 0, 0);
Vector3 pt5 = new(0.5f, 0.5f, 0);
Vector3 pt6 = new(1f, 0, 0);

MeshGeometry3D mesh1 = new MeshGeometry3D();
mesh1.FillType = MeshFillType.Triangles;
Vertex3D[] meshVertices = new Vertex3D[]
{
    new Vertex3D() { Position = pt1,  Normal = new Vector3(0, 0, 1) },
    new Vertex3D() { Position = pt2,  Normal = new Vector3(0, 0, 1) },
    new Vertex3D() { Position = pt3,  Normal = new Vector3(0, 0, 1) },
    new Vertex3D() { Position = pt4,  Normal = new Vector3(0, 0, -1) },
    new Vertex3D() { Position = pt5,  Normal = new Vector3(0, 0, -1) },
    new Vertex3D() { Position = pt6,  Normal = new Vector3(0, 0, -1) }
};
mesh1.Vertices = meshVertices;
// Vertices of the first triangle are enumerated counter-clockwise (pt3->pt2->pt1),
// while vertices of the second triangle are enumerated clockwise (pt4->pt5->pt6):
uint[] meshIndices = new uint[] { 2, 1, 0, 3, 4, 5 };
mesh1.Indices = meshIndices;
model.Meshes.AddRange(new MeshGeometry3D[] { mesh1 });
g3DControl.Materials.Add(new SimplePbrMaterial(Colors.SeaGreen, "myMaterial"));
mesh1.MaterialKey = "myMaterial";

При установке для свойства Graphics3DControl.CullMode значения CullMode.Back задние грани не отображаются. Второй (правый) треугольник обращен в сторону от камеры, поэтому он не отображается.

g3d-cullmode-example-cull-back

Когда значение Graphics3DControl.CullMode равно значению CullMode.Front, передние грани не отображаются. Первый (левый) треугольник обращен к камере, поэтому он скрыт:

g3d-cullmode-example-cull-front

Гамма-коррекция и коррекция экспозиции

  • Graphics3DControl.Exposure — контролирует уровень коррекции экспозиции, который регулирует яркость отрисованного изображения. Значение по умолчанию равно 4.5. Свойству может быть присвоено неотрицательное значение.
  • Graphics3DControl.Gamma — контролирует гамма-коррекцию. Значение по умолчанию равно 2,2, что является стандартным значением гаммы для большинства дисплеев. Этому свойству можно присвоить неотрицательное значение.



* Эта страница была создана автоматически с помощью сервиса машинного перевода Яндекс Переводчик.