基于 HelixToolkit.SharpDX 渲染ply点云
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:Class="HelixToolkit.DX.PointCloud.MainWindow"
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.UseModernWindowStyle="True"
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>
<!-- Ctrl+E快捷键:缩放至整个模型 -->
<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);
}
}
}
四、效果图


浙公网安备 33010602011771号