#wpf #3d #point-clouds
Вопрос:
Я пытаюсь создать динамическое представление 3D-точек с помощью WPF, я могу нарисовать первый набор точек, но затем он выходит из строя, потому что Mesh3DGeometry заморожена .. есть ли способ разморозить Mesh3DGeomerty и очистить сетку, чтобы можно было нарисовать следующие наборы ?
var rand = new Random();
while (true)
{
points.Clear();
for (int i = 0; i < 100; i )
{
points.Add(new Point3D(rand.NextDouble(), rand.NextDouble(), rand.NextDouble()));
}
for (int i = 0; i < points.Count; i )
{
AddCubeToMesh(pointCloudMesh, points[i], 0.01);
}
pointCloudMesh.Freeze();
}
Также здесь есть XAML
<Grid Grid.Row="1" Grid.Column="1" Margin="0 20 0 -20" Background="LightGray" Name="MyCanvas" >
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera x:Name="camMain" Position="0 0 5" LookDirection="0 0 -5"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<Model3DGroup.Children>
<AmbientLight Color="#AAAAAA" />
</Model3DGroup.Children>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D x:Name="pointCloudMesh" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Red"/>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
Код для AddCubeToMesh
private void AddCubeToMesh(MeshGeometry3D mesh, Point3D center, double size)
{
if (mesh != null)
{
int offset = mesh.Positions.Count;
mesh.Positions.Add(new Point3D(center.X - size, center.Y size, center.Z - size));
mesh.Positions.Add(new Point3D(center.X size, center.Y size, center.Z - size));
mesh.Positions.Add(new Point3D(center.X size, center.Y size, center.Z size));
mesh.Positions.Add(new Point3D(center.X - size, center.Y size, center.Z size));
mesh.Positions.Add(new Point3D(center.X - size, center.Y - size, center.Z - size));
mesh.Positions.Add(new Point3D(center.X size, center.Y - size, center.Z - size));
mesh.Positions.Add(new Point3D(center.X size, center.Y - size, center.Z size));
mesh.Positions.Add(new Point3D(center.X - size, center.Y - size, center.Z size));
mesh.TriangleIndices.Add(offset 3);
mesh.TriangleIndices.Add(offset 2);
mesh.TriangleIndices.Add(offset 6);
mesh.TriangleIndices.Add(offset 3);
mesh.TriangleIndices.Add(offset 6);
mesh.TriangleIndices.Add(offset 7);
mesh.TriangleIndices.Add(offset 2);
mesh.TriangleIndices.Add(offset 1);
mesh.TriangleIndices.Add(offset 5);
mesh.TriangleIndices.Add(offset 2);
mesh.TriangleIndices.Add(offset 5);
mesh.TriangleIndices.Add(offset 6);
mesh.TriangleIndices.Add(offset 1);
mesh.TriangleIndices.Add(offset 0);
mesh.TriangleIndices.Add(offset 4);
mesh.TriangleIndices.Add(offset 1);
mesh.TriangleIndices.Add(offset 4);
mesh.TriangleIndices.Add(offset 5);
mesh.TriangleIndices.Add(offset 0);
mesh.TriangleIndices.Add(offset 3);
mesh.TriangleIndices.Add(offset 7);
mesh.TriangleIndices.Add(offset 0);
mesh.TriangleIndices.Add(offset 7);
mesh.TriangleIndices.Add(offset 4);
mesh.TriangleIndices.Add(offset 7);
mesh.TriangleIndices.Add(offset 6);
mesh.TriangleIndices.Add(offset 5);
mesh.TriangleIndices.Add(offset 7);
mesh.TriangleIndices.Add(offset 5);
mesh.TriangleIndices.Add(offset 4);
mesh.TriangleIndices.Add(offset 2);
mesh.TriangleIndices.Add(offset 3);
mesh.TriangleIndices.Add(offset 0);
mesh.TriangleIndices.Add(offset 2);
mesh.TriangleIndices.Add(offset 0);
mesh.TriangleIndices.Add(offset 1);
}
}
Мое решение, которое вроде как сработало для меня, состоит в том, чтобы добавить все это в отдельный пользовательский элемент управления и вызывать его каждый раз, когда поступают новые данные
Комментарии:
1. Я бы добавил реализацию метода AddCubeToMesh к этому вопросу.
Ответ №1:
Во-первых: Бесконечный цикл, который генерирует части пользовательского интерфейса, не давая времени потоку пользовательского интерфейса, не будет работать. Создайте данные в отдельном потоке и передайте данные в поток пользовательского интерфейса, чтобы создать модель и отобразить ее.
Затем размораживание замораживаемого устройства невозможно:
«Размораживание» Замораживаемый объект После замораживания замораживаемый объект никогда не может быть изменен или разморожен; однако вы можете создать размороженный клон с помощью метода Clone или CloneCurrentValue.
Поэтому, если вы считаете, что действительно нужно заморозить/разморозить, вы можете сделать это, сделав клон. Я не думаю, что это нужно здесь.
Комментарии:
1. Таким образом, бесконечный цикл предназначен только для демонстрации, а не для реального проекта. потому что данные поступают с аппаратного датчика .. однако я решил эту проблему, разделив 3D-представление на другой пользовательский элемент управления, а затем я могу удалить всех детей и создать их заново с новыми данными
2. Я думаю, что гораздо быстрее добавить 100 кубов в начало координат и обновлять их переводы при каждом тике.
Ответ №2:
решение, которое я придумал, состоит в том, чтобы разделить представление облака точек зрения на другой пользовательский элемент управления, и каждый раз, когда я хочу отобразить новый набор данных, я уничтожаю старый пользовательский элемент управления и перестраиваю его заново .. это агрессивный подход, но он сработал хорошо
XAML для нового пользовательского элемента управления
<UserControl x:Class="LPDTool.View3D"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:LPDTool"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="500"
KeyDown="Window_KeyDown">
<GroupBox x:Name="GBox" Margin="0 20 0 -20" Foreground="#AAAAAA" FontSize="18" FontWeight="Medium" Background="#DDDBDA" BorderBrush="#7B7704" BorderThickness="2" FontFamily="Abadi MT">
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera x:Name="camMain"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<Model3DGroup.Children>
<AmbientLight Color="#AAAAAA" />
</Model3DGroup.Children>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D x:Name="pointCloudMesh" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Red"/>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</GroupBox>
Конструктор инициализации
public View3D()
{
InitializeComponent();
PositionCamera();
for (int i = 0; i < LPDTest.points.Count; i )
{
AddCubeToMesh(pointCloudMesh, points[i], 0.02);
}
}
XAML для части включения
<Grid x:Name="My3dview">
</Grid>
Вот часть генерирующего кода (с пустыми данными)
var rand = new Random();
while (true)
{
My3dview.Children.Clear();
points.Clear();
for (int i = 0; i < 100; i )
{
points.Add(new Point3D(rand.NextDouble(), rand.NextDouble(), rand.NextDouble()));
}
My3dview.Children.Add(new View3D());
}