Я использую HelixToolkit3D для небольшого школьного проекта, который требует создания 3D-объектов (кубов) на основе существующего списка с объектами (настраиваемые объекты), и каждая грань куба должна иметь свое собственное изображение, которое будет как строковый атрибут (путь к изображению) к объекту в списке, о котором я упоминал ранее (например, front_image, back_image и т. д.). Я использую Wpf, и я хотел использовать привязку для создания 3D-элементов. После поиска я нашел эту ссылку https://github.com/helix-toolkit/helix-toolkit/tree/develop/Source/Examples/WPF/ExampleBrowser/Examples/DataTemplate именно то, что мне было нужно, и я смог заставить его работать но только кубики со сплошным цветом. Я пытался установить материал из изображения, но это не работает. Также я хотел добавить краевые линии, как каркас для каждого куба.
Вот мой код:
XAML-файл 3D-просмотра
<Controls:MetroWindow x:Class="Project1._3DView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Planom"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:h="http://helix-toolkit.org/wpf"
Closing="Window_Closing"
Icon="Images/meIcon.ico"
mc:Ignorable="d"
PreviewKeyDown="MetroWindow_PreviewKeyDown"
WindowStartupLocation="CenterScreen" WindowState="Maximized"
Title="Pamja 3-Dimensionale" Height="768" Width="1024">
<Window.Resources>
<local:ColorConverter3D x:Key="colorConverter"/>
<local:DataTemplate3D x:Key="{x:Type local:CubeElement}">
<local:GenericUIElement3D widthX="{Binding Depth}" Material="{Binding Material}" heightZ="{Binding Height}" depthY="{Binding Width}" Color="{Binding color}">
<local:GenericUIElement3D.Transform>
<TranslateTransform3D OffsetX="{Binding Position.X}" OffsetY="{Binding Position.Y}" OffsetZ="{Binding Position.Z}" />
</local:GenericUIElement3D.Transform>
</local:GenericUIElement3D>
</local:DataTemplate3D>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="71*"/>
<RowDefinition Height="666*"/>
</Grid.RowDefinitions>
<h:HelixViewport3D ShowCoordinateSystem="True" ZoomExtentsWhenLoaded="True" ShowFrameRate="True" ShowCameraTarget="True" Grid.RowSpan="2">
<h:SunLight>
<h:SunLight.Transform>
<TranslateTransform3D OffsetX="200" OffsetY="-200" OffsetZ="200" />
</h:SunLight.Transform>
</h:SunLight>
<h:GridLinesVisual3D Center="0,0,0" Width="400" Length="400" MinorDistance="10" MajorDistance="10" Thickness="0.1" Fill="Black"/>
<local:ItemsVisual3D ItemsSource="{Binding ObservableElements}" RefreshChildrenOnChange="True"/>
</h:HelixViewport3D>
</Grid>
3D view .cs file
public partial class _3DView : MahApps.Metro.Controls.MetroWindow
{
Shelf currentShelf;
public ObservableCollection<Article> ObservableElements { get; set; }
public _3DView(Shelf currentShelf)
{
InitializeComponent();
this.ObservableElements = new ObservableCollection<CubeElement>();
this.DataContext = this;
this.currentShelf = currentShelf;
foreach (CubeElement a in currentShelf.books)
{
a.Position = new Point3D((a.Depth / 2) - (a.Depth * a.depthF) + currentShelf.Depth / 2 + 1, (a.Width / 2) + a.leftPush - currentShelf.Width / 2, 20);
ObservableElements.Add(a);
}
currentShelf.items3D = ObservableElements;
}
}
КубЭлемент.cs
public partial class CubeElement : INotifyPropertyChanged
{
public CubeElement()
{
fSize = 12;
changeTracking = false;
drawRatio = 1;
isSelectable = true;
}
public string Id { get; set; }
public string Name { get; set; }
public string left_image { get; set; }
public string front_image { get; set; }
public string back_image { get; set; }
public string right_image { get; set; }
public string top_image { get; set; }
public Shelf shelf{ get; set; }
private double _width { get; set; }
public virtual double Width
{
get { return _width; }
set
{
_width = value;
widthDraw = _width * mainDraw;
OnPropertyChanged("Width");
}
}
private double _height { get; set; }
public virtual double Height
{
get { return _height; }
set
{
_height = value;
heightDraw = _height * mainDraw;
OnPropertyChanged(nameof(Height));
}
}
public virtual double Depth { get; set; }
public double Weight { get; set; }
public string Color
{
get { return _Color; }
set
{
_Color = value;
color = (Color)ColorConverter.ConvertFromString(_Color);
OnPropertyChanged("Color");
}
}
private string _Color { get; set; }
public int _depthF { get; set; }
public int depthF
{
get { return _depthF; }
set
{
_depthF = value;
if (shelf!= null)
{
Position = new Point3D((Depth / 2) - (Depth * _depthF) + shelf.Depth / 2 + 1, (Width / 2) + leftPush - (shelf.Width / 2), 20);
}
OnPropertyChanged("depthF");
}
}
private double _leftPush { get; set; }
public double leftPush
{
get { return _leftPush; }
set
{
_leftPush = value;
leftPushP = value * drawRatioW;
OnPropertyChanged("leftPush");
Position = new Point3D((Depth / 2) - (Depth * depthF) + shelf.Depth / 2 + 1, (Width / 2) + (_leftPush / mainDraw) - (shelf.Width / 2), 20);
}
}
private string _imagePath { get; set; }
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
public string imagePath
{
get { return _imagePath; }
set
{
_imagePath = value; OnPropertyChanged("imagePath");
if(_imagePath != null)
{
Material = MaterialHelper.CreateEmissiveImageMaterial(_imagePath, Brushes.Red, UriKind.Absolute);
}
else
{
Material = MaterialHelper.CreateMaterial(color);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public object this[string propertyName]
{
get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
}
public Model3D Model { get; set; }
public Material Material { get; set; }
public Point3D _position;
public Point3D Position
{
get { return _position; }
set
{
_position = value;
OnPropertyChanged("Position");
}
}
public double Radius { get; set; }
private bool isVisible = true;
public bool IsVisible
{
get { return isVisible; }
set
{
if (IsVisible != value)
{
isVisible = value;
OnPropertyChanged("IsVisible");
}
}
}
private Color _color { get; set; }
public Color color
{
get { return _color; }
set
{
_color = value;
OnPropertyChanged("color");
}
}
}
Полка.cs
public partial class Shelf
{
public string Id { get; set; }
public string Name { get; set; }
private double _width { get; set; }
public virtual double Width
{
get { return _width; }
set
{
_width = value;
OnPropertyChanged("Width");
}
}
private double _height { get; set; }
public virtual double Height
{
get { return _height; }
set
{
_height = value;
OnPropertyChanged("Height");
}
}
public double Depth { get; set; }
public double Weight { get; set; }
public ObservableCollection<CubeElement> books{ get; set; }
}
GenericUIElement3D.cs
public class GenericUIElement3D : UIElement3D
{
protected GeometryModel3D Model { get; set; }
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register(
nameof(Color), typeof(Color), typeof(GenericUIElement3D), new UIPropertyMetadata((s, e) => ((GenericUIElement3D)s).ColorChanged()));
public static readonly DependencyProperty MaterialProperty = DependencyProperty.Register(
nameof(Material), typeof(Material), typeof(GenericUIElement3D), new PropertyMetadata(null));
public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(
nameof(widthX), typeof(double), typeof(GenericUIElement3D), new UIPropertyMetadata((s, e) => ((GenericUIElement3D)s).DimensionsChanged()));
public static readonly DependencyProperty HeightProperty = DependencyProperty.Register(
nameof(heightZ), typeof(double), typeof(GenericUIElement3D), new UIPropertyMetadata((s, e) => ((GenericUIElement3D)s).DimensionsChanged()));
public static readonly DependencyProperty DepthProperty = DependencyProperty.Register(
nameof(depthY), typeof(double), typeof(GenericUIElement3D), new UIPropertyMetadata((s, e) => ((GenericUIElement3D)s).DimensionsChanged()));
public Color Color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
public double widthX
{
get { return (double)GetValue(WidthProperty); }
set { SetValue(WidthProperty, value); }
}
protected override void OnMouseEnter(MouseEventArgs e)
{
base.OnMouseEnter(e);
//MessageBox.Show("OnMouseDown raised. " + e.OriginalSource);
}
public double heightZ
{
get { return (double)GetValue(HeightProperty); }
set { SetValue(HeightProperty, value); }
}
public double depthY
{
get { return (double)GetValue(DepthProperty); }
set { SetValue(DepthProperty, value); }
}
public Material Material
{
get { return (Material)GetValue(MaterialProperty); }
set { SetValue(MaterialProperty, value); }
}
public GenericUIElement3D()
{
Model = new GeometryModel3D();
BindingOperations.SetBinding(Model, GeometryModel3D.MaterialProperty, new Binding(nameof(Material)) { Source = this });
Visual3DModel = Model;
}
private void SetGeometry()
{
MeshBuilder meshBuilder = new MeshBuilder(false, false);
meshBuilder.AddBox(new Point3D(0, 0, heightZ / 2), widthX, depthY, heightZ);
Model.Geometry = meshBuilder.ToMesh();
}
private void ColorChanged()
{
Material = MaterialHelper.CreateMaterial(Color);
}
private void DimensionsChanged()
{
SetGeometry();
}
private void DepthChanged()
{
SetGeometry();
}
}
Этот проект о школьной библиотеке, поэтому там будут книги и полка. Код укорочен, чтобы было проще, если кто-то попытается поэкспериментировать (надеюсь, я не удалил важные строки). По сути, в начале будет 2D-вид, который будет использоваться для создания полки и добавления книг, а затем, при желании, пользователь может переключиться на 3D-вид в параллельных окнах. Я не могу понять 3D "VisualTree" так хорошо (пока что), поэтому мне нужна помощь.