I am trying to create a dynamic view of 3D points using WPF, I am able to draw the first set of points but then it crashes bcuz the Mesh3DGeometry is frozen .. is there anyway to unfreeze the Mesh3DGeomerty and Clear the Grid so the next sets can be drawn ?
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();
}
Also XAML is here
<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>
Code for 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);
}
}
I solution that kinda worked for me is to add all of this into a separated UserControl and call it every time a new data arrive
the solution I came up with is to separate the Point Cloud view to another User Control and every time I wanna display a new set of data i destroy the old User Control and rebuild it .. it's an aggressive approach but worked fine
XAML for the new User Control
<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>
Initialization Constructor
public View3D()
{
InitializeComponent();
PositionCamera();
for (int i = 0; i < LPDTest.points.Count; i++)
{
AddCubeToMesh(pointCloudMesh, points[i], 0.02);
}
}
XAML for the inclusion part
<Grid x:Name="My3dview">
</Grid>
Here is the generating code part (with dumpy data)
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());
}