2017-08-27 55 views
0

我正在使用HelixToolkit3D作为一个小型学校项目,它需要根据现有列表与对象(自定义创建对象)生成3D对象(立方体),并且每个立方体的面应该是能够拥有自己的图像,它将作为字符串属性(图像的路径)到我之前提到的列表上的对象(例如front_image,back_image等)。我正在使用Wpf,我想使用绑定来生成3D元素。搜索后,我发现这个链接https://github.com/helix-toolkit/helix-toolkit/tree/develop/Source/Examples/WPF/ExampleBrowser/Examples/DataTemplate正是我所需要的,我能够使它工作,但只有立方体具有纯色。我试图从图像设置材质,但它不起作用。此外,我想为每个立方体添加像线框一样的边线。HelixToolkit 3D WPF每个立方体侧面的自定义图像

这是到目前为止我的代码:

3D视图XAML文件

<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视图.cs文件

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; 
    } 
} 

CubeElement.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"); 
     } 
    } 
} 

Shelf.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”如此之好(迄今为止),这就是为什么我需要一些帮助。

+0

你见过这个例子:http://www.helix-toolkit.org/demos/wpf/rubik – Isma

+0

@IsmaC。是的,我在发布问题后才看到它。我尝试过了,但是效果很差,而且我在华硕Rog gl75vt上运行该应用程序,它产生了很多三角形,所以我必须检查解决方法或使代码 – ASTeam

回答

0

我认为你应该能够使用这个代码为你的多维数据集,如果你适应它。

/// <summary> 
/// A visual element that renders a box. 
/// </summary> 
/// <remarks> 
/// The box is aligned with the local X, Y and Z coordinate system 
/// Use a transform to orient the box in other directions. 
/// </remarks> 
public class TextureBoxVisual3D : ModelVisual3D 
{ 

    /// <summary> 
    /// Identifies the <see cref="Center"/> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty CenterProperty = DependencyProperty.Register(
     "Center", typeof(Point3D), typeof(TextureBoxVisual3D), new UIPropertyMetadata(new Point3D(), GeometryChanged)); 



    /// <summary> 
    /// Identifies the <see cref="Height"/> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty HeightProperty = DependencyProperty.Register(
     "Height", typeof(double), typeof(TextureBoxVisual3D), new UIPropertyMetadata(1.0, GeometryChanged)); 

    /// <summary> 
    /// Identifies the <see cref="Length"/> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty LengthProperty = DependencyProperty.Register(
     "Length", typeof(double), typeof(TextureBoxVisual3D), new UIPropertyMetadata(1.0, GeometryChanged)); 


    /// <summary> 
    /// Identifies the <see cref="Width"/> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(
     "Width", typeof(double), typeof(TextureBoxVisual3D), new UIPropertyMetadata(1.0, GeometryChanged)); 

    /// <summary> 
    /// Identifies the <see cref="Source"/> dependency property. 
    /// </summary> 
    public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
     "Source", typeof(string), typeof(TextureBoxVisual3D), new UIPropertyMetadata(null, GeometryChanged)); 

    /// <summary> 
    /// The geometry changed. 
    /// </summary> 
    /// <param name="d"> 
    /// The d. 
    /// </param> 
    /// <param name="e"> 
    /// The event arguments. 
    /// </param> 
    private static void GeometryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((TextureBoxVisual3D)d).UpdateModel(); 
    } 

    /// <summary> 
    /// Gets or sets the center of the box. 
    /// </summary> 
    /// <value>The center.</value> 
    public Point3D Center 
    { 
     get 
     { 
      return (Point3D)this.GetValue(CenterProperty); 
     } 

     set 
     { 
      this.SetValue(CenterProperty, value); 
     } 
    } 

    /// <summary> 
    /// Gets or sets the height (along local z-axis). 
    /// </summary> 
    /// <value>The height.</value> 
    public double Height 
    { 
     get 
     { 
      return (double)this.GetValue(HeightProperty); 
     } 

     set 
     { 
      this.SetValue(HeightProperty, value); 
     } 
    } 

    /// <summary> 
    /// Gets or sets the length of the box (along local x-axis). 
    /// </summary> 
    /// <value>The length.</value> 
    public double Length 
    { 
     get 
     { 
      return (double)this.GetValue(LengthProperty); 
     } 

     set 
     { 
      this.SetValue(LengthProperty, value); 
     } 
    } 


    /// <summary> 
    /// Gets or sets the width of the box (along local y-axis). 
    /// </summary> 
    /// <value>The width.</value> 
    public double Width 
    { 
     get 
     { 
      return (double)this.GetValue(WidthProperty); 
     } 

     set 
     { 
      this.SetValue(WidthProperty, value); 
     } 
    } 

    /// <summary> 
    /// Gets or sets the panorama/skybox directory or file prefix. 
    /// </summary> 
    /// <remarks> 
    /// If a directory is specified, the filename prefix will be set to "cube". 
    /// If the filename prefix is "cube", the faces of the cube should be named 
    /// cube_f.jpg 
    /// cube_b.jpg 
    /// cube_l.jpg 
    /// cube_r.jpg 
    /// cube_u.jpg 
    /// cube_d.jpg 
    /// </remarks> 
    /// <value>The source.</value> 
    public string Source 
    { 
     get 
     { 
      return (string)this.GetValue(SourceProperty); 
     } 

     set 
     { 
      this.SetValue(SourceProperty, value); 
     } 
    } 


    /// <summary> 
    /// Do the tessellation and return the <see cref="MeshGeometry3D"/>. 
    /// </summary> 
    /// <returns>The mesh geometry.</returns> 
    protected void UpdateModel() 
    { 

     if (string.IsNullOrWhiteSpace(this.Source)) 
     { 
      return; 
     } 
     string directory = Path.GetDirectoryName(this.Source); 
     string prefix = Path.GetFileName(this.Source); 

     if (string.IsNullOrEmpty(prefix)) 
     { 
      prefix = "cube"; 
     } 



     var front = Path.Combine(directory, prefix + "_f.jpg"); 
     var left = Path.Combine(directory, prefix + "_l.jpg"); 
     var right = Path.Combine(directory, prefix + "_r.jpg"); 
     var back = Path.Combine(directory, prefix + "_b.jpg"); 
     var up = Path.Combine(directory, prefix + "_u.jpg"); 
     var down = Path.Combine(directory, prefix + "_d.jpg"); 

     var group = new Model3DGroup(); 

     group.Children.Add(this.AddCubeSide(front, new Vector3D(0, -1, 0), new Vector3D(0, 0, 1), this.Length, this.Width, this.Height)); 
     group.Children.Add(this.AddCubeSide(left, new Vector3D(-1, 0, 0), new Vector3D(0, 0, 1), this.Width, this.Length, this.Height)); 
     group.Children.Add(this.AddCubeSide(right, new Vector3D(1, 0, 0), new Vector3D(0, 0, 1), this.Width, this.Length, this.Height)); 
     group.Children.Add(this.AddCubeSide(back, new Vector3D(0, 1, 0), new Vector3D(0, 0, 1), this.Length, this.Width, this.Height)); 
     group.Children.Add(this.AddCubeSide(up, new Vector3D(0, 0, 1), new Vector3D(0, -1, 0), this.Height, this.Width, this.Length)); 
     group.Children.Add(this.AddCubeSide(down, new Vector3D(0, 0, -1), new Vector3D(0, 1, 0), this.Height, this.Width, this.Length)); 

     this.Content = group; 
    } 

    private static Dictionary<string, Material> _materialDict = new Dictionary<string, Material>(); 

    /// <summary> 
    /// The add cube side. 
    /// </summary> 
    /// <param name="normal"> 
    /// The normal. 
    /// </param> 
    /// <param name="up"> 
    /// The up. 
    /// </param> 
    /// <param name="fileName"> 
    /// The file name. 
    /// </param> 
    /// <returns> 
    /// </returns> 
    private GeometryModel3D AddCubeSide(string fileName, Vector3D normal, Vector3D up, double dist, double width, double height) 
    { 
     string fullPath = Path.GetFullPath(fileName); 

     if (!File.Exists(fullPath)) 
     { 
      return null; 
     } 

     Material material = null; 
     if (_materialDict.ContainsKey(fileName)) 
     { 
      material = _materialDict[fileName]; 
     } 
     else 
     { 
      var image = new BitmapImage(); 
      image.BeginInit(); 
      image.UriSource = new Uri(fullPath); 

      image.EndInit(); 

      var brush = new ImageBrush(image); 
      material = new DiffuseMaterial(brush); 

      _materialDict.Add(fileName, material); 
     } 

     var mesh = new MeshGeometry3D(); 
     var right = Vector3D.CrossProduct(normal, up); 
     var origin = Center; 

     var n = normal * dist/2; 
     up *= height/2; 
     right *= width/2; 

     // p1 is the lower left corner 
     // p2 is the upper left 
     // p3 is the lower right 
     // p4 is the upper right 
     var p1 = origin + n - up - right; 
     var p2 = origin + n + up - right; 
     var p3 = origin + n - up + right; 
     var p4 = origin + n + up + right; 

     mesh.Positions.Add(p1); 
     mesh.Positions.Add(p2); 
     mesh.Positions.Add(p3); 
     mesh.Positions.Add(p4); 

     //doublesided 
     mesh.Positions.Add(p1); // 4 
     mesh.Positions.Add(p2); // 5 
     mesh.Positions.Add(p3); // 6 
     mesh.Positions.Add(p4); // 7 


     mesh.TriangleIndices.Add(0); 
     mesh.TriangleIndices.Add(3); 
     mesh.TriangleIndices.Add(1); 
     mesh.TriangleIndices.Add(0); 
     mesh.TriangleIndices.Add(2); 
     mesh.TriangleIndices.Add(3); 


     //doublesided 
     mesh.TriangleIndices.Add(4); 
     mesh.TriangleIndices.Add(5); 
     mesh.TriangleIndices.Add(7); 
     mesh.TriangleIndices.Add(4); 
     mesh.TriangleIndices.Add(7); 
     mesh.TriangleIndices.Add(6);   



     mesh.TextureCoordinates.Add(new Point(0, 1)); 
     mesh.TextureCoordinates.Add(new Point(0, 0)); 
     mesh.TextureCoordinates.Add(new Point(1, 1)); 
     mesh.TextureCoordinates.Add(new Point(1, 0)); 

     //doublesided 
     mesh.TextureCoordinates.Add(new Point(1, 1)); 
     mesh.TextureCoordinates.Add(new Point(1, 0)); 
     mesh.TextureCoordinates.Add(new Point(0, 1)); 
     mesh.TextureCoordinates.Add(new Point(0, 0)); 


     return new GeometryModel3D(mesh, material); 
    } 
} 
+0

看起来很有趣。让我试试看,然后我会告诉你结果。 – ASTeam