HelixToolkit.SharpDX 是 HelixToolkit 生态中基于 DirectX(DX) 底层本领封装的 .NET 开源 3D 可视化库;DirectX 是微软为 Windows 平台开辟的底层多媒体 API,可高效调用显卡、声卡等硬件实现高性能图形渲染,而该库基于此本领,兼容 .NET Framework/.NET Core/.NET 5+ 全平台,专为 Windows 桌面应用提供低门槛、高性能的 3D 渲染,完善适配呆板臂可视化、点云处理惩罚、装备仿真等工业开辟场景;
一、NuGet 包管理器中下载干系包
NuGet 依赖:安装 HelixToolkit.Wpf 和HelixToolkit.SharpDX.Core.Wpf
二、引入HelixToolkit.SharpDX
xmlns:hx="http://helix-toolkit.org/wpf/SharpDX"
三、示例工程文件
MainWindow.xaml- <Window
- x:
- 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:hx="http://helix-toolkit.org/wpf/SharpDX"
- xmlns:local="clr-namespace:HelixToolkit.DX.PointCloud"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:prism="http://prismlibrary.com/"
- xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
- xmlns:vm="clr-namespace:HelixToolkit.DX.PointCloud.ViewModels"
- prism:ViewModelLocator.AutoWireViewModel="True"
- ui:WindowHelper.SystemBackdropType="Mica"
- ui:WindowHelper.UseModernWindow
- mc:Ignorable="d">
- <Grid>
- <hx:Viewport3DX
- BackgroundColor="Black"
- EffectsManager="{Binding EffectsManager}"
- IsRotationEnabled="True"
- IsShadowMappingEnabled="True"
- RotateAroundMouseDownPoint="True"
- ShowCoordinateSystem="True"
- ShowFrameRate="True"
- ShowViewCube="True"
- ZoomAroundMouseDownPoint="True"
- ZoomExtentsWhenLoaded="True">
-
- <hx:Viewport3DX.InputBindings>
-
- <KeyBinding Command="hx:ViewportCommands.ZoomExtents" Gesture="Control+E" />
-
- <MouseBinding Command="hx:ViewportCommands.Rotate" Gesture="RightClick" />
-
- <MouseBinding Command="hx:ViewportCommands.Zoom" Gesture="MiddleClick" />
-
- <MouseBinding Command="hx:ViewportCommands.Pan" Gesture="LeftClick" />
- </hx:Viewport3DX.InputBindings>
-
- <hx:Viewport3DX.Camera>
- <hx:PerspectiveCamera
- LookDirection="0,0,-10"
- Position="0,0,10"
- UpDirection="0,1,0" />
- </hx:Viewport3DX.Camera>
-
- <hx:ShadowMap3D OrthoWidth="200" />
-
- <hx:AmbientLight3D Color="White" />
-
- <hx:DirectionalLight3D Direction="100, -100, -150" />
- <hx:PointGeometryModel3D
- Figure="Ellipse"
- Geometry="{Binding BatchedGeometry}"
- Size="1,1"
- Color="White" />
- </hx:Viewport3DX>
-
- <Button
- Margin="20"
- Padding="10,5"
- HorizontalAlignment="Left"
- VerticalAlignment="Top"
- Command="{Binding LoadPlyCommand}"
- Content="Load PLY File" />
- </Grid>
- </Window>
复制代码 MainWindowViewModel- using HelixToolkit.SharpDX.Core;
- using HelixToolkit.SharpDX.Core.Core;
- using HelixToolkit.Wpf.SharpDX;
- using Microsoft.Win32;
- using SharpDX;
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Media3D;
- using PerspectiveCamera = HelixToolkit.Wpf.SharpDX.PerspectiveCamera;
- namespace HelixToolkit.DX.PointCloud.ViewModels
- {
- public class MainWindowViewModel : BindableBase, IDisposable
- {
- /// <summary>
- /// 消息对话框实例
- /// </summary>
- private readonly IDialogHelper _dialogHelper;
- public MainWindowViewModel(IContainerExtension container)
- {
- _dialogHelper = container.Resolve<IDialogHelper>();
- }
- private DefaultEffectsManager _effectsManager = new();
- /// <summary>
- /// 特效管理器
- /// 管理渲染管线、着色器等
- /// </summary>
- public DefaultEffectsManager EffectsManager
- {
- get => _effectsManager;
- set => SetProperty(ref _effectsManager, value);
- }
- private PointGeometry3D? _batchedGeometry;
- /// <summary>
- /// 点云几何体
- /// 定义3D场景中的点云数据
- /// </summary>
- public PointGeometry3D? BatchedGeometry
- {
- get => _batchedGeometry;
- set => SetProperty(ref _batchedGeometry, value);
- }
- /// <summary>
- /// 选择PLY文件并加载点云事件
- /// </summary>
- public ICommand LoadPlyCommand => new DelegateCommand(SelectPlyFile);
- /// <summary>
- /// 选择PLY文件并加载点云
- /// </summary>
- private void SelectPlyFile()
- {
- var openFileDialog = new OpenFileDialog
- {
- Filter = "PLY files (*.ply)|*.ply|All files (*.*)|*.*",
- Title = "Select a PLY file"
- };
- if (openFileDialog.ShowDialog() == true)
- {
- try
- {
- LoadPlyFile(openFileDialog.FileName);
- }
- catch (Exception ex)
- {
- _dialogHelper.ShowMessageAsync("报错", $"Error loading file:\n{ex.Message}");
- }
- }
- }
- /// <summary>
- /// 加载PLY文件并创建点云几何体
- /// </summary>
- /// <param name="filePath"></param>
- private void LoadPlyFile(string filePath)
- {
- // 解析PLY,获取位置和颜色(所有点都包含颜色)
- var (positions, colors) = ParsePly(filePath);
- if (positions.Count == 0)
- {
- _dialogHelper.ShowMessageAsync("报错", "No points found in the file.");
- return;
- }
- // 创建几何体,设置位置和颜色
- var geometry = new PointGeometry3D
- {
- Positions = new Vector3Collection(positions),
- Colors = new Color4Collection(colors) // colors 一定存在且数量匹配
- };
- // 创建点云模型
- var pointModel = new PointGeometryModel3D
- {
- Geometry = geometry,
- Size = new Size(1, 1), // 点大小设大一点便于观察
- Figure = PointFigure.Ellipse,
- Color = Colors.White,
- };
- // 添加到视口
- BatchedGeometry = geometry;
- _dialogHelper.ShowMessageAsync("成功", $"成功加载 {positions.Count} 个点。");
- }
- /// <summary>
- /// 解析ASCII PLY文件,提取顶点位置和颜色。
- /// 假设文件包含:x y z red green blue (red/green/blue为uchar 0-255)
- /// </summary>
- private (List<Vector3> positions, List<Color4> colors) ParsePly(string filePath)
- {
- var positions = new List<Vector3>();
- var colors = new List<Color4>();
- bool readingData = false;
- foreach (string line in File.ReadLines(filePath))
- {
- string trimmed = line.Trim();
- if (string.IsNullOrEmpty(trimmed))
- continue;
- if (!readingData)
- {
- // 查找头部结束标志
- if (trimmed == "end_header")
- {
- readingData = true;
- }
- continue;
- }
- // 解析数据行,每行至少6个值:x y z r g b
- string[] parts = trimmed.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
- if (parts.Length < 6)
- continue; // 不符合要求,跳过(但你的数据应该都符合)
- try
- {
- float x = float.Parse(parts[0], CultureInfo.InvariantCulture);
- float y = float.Parse(parts[1], CultureInfo.InvariantCulture);
- float z = float.Parse(parts[2], CultureInfo.InvariantCulture);
- positions.Add(new Vector3(x, y, z));
- // 解析RGB值(0-255),转换为0-1范围的float
- byte r = byte.Parse(parts[3], CultureInfo.InvariantCulture);
- byte g = byte.Parse(parts[4], CultureInfo.InvariantCulture);
- byte b = byte.Parse(parts[5], CultureInfo.InvariantCulture);
- colors.Add(new Color4(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f));
- }
- catch (Exception ex)
- {
- // 如果某行解析失败,可以选择跳过或报错。这里简单跳过并输出警告
- _dialogHelper.ShowMessageAsync("警告", $"Skipping line due to error:\n{ex.Message}");
- continue;
- }
- }
- // 确保颜色数量与顶点数量一致(正常情况下应该一致)
- if (positions.Count != colors.Count)
- _dialogHelper.ShowMessageAsync("报错", $"Parsed {positions.Count} positions but {colors.Count} colors.");
- return (positions, colors);
- }
- /// <summary>
- /// 释放资源
- /// </summary>
- public void Dispose()
- {
- GC.SuppressFinalize(this);
- }
- }
- }
复制代码 四、结果图
|