Refresh the color of a single point. GeometryModel3D Material, not an entire point system

I am having trouble looking into the color / material system of C # WPF projects, I am currently updating the color of the entire point system every time I update the model, when I would just like to update the color of one point (how it is added).

Aggregate system class

public class AggregateSystem { // stack to store each particle in aggregate private readonly Stack<AggregateParticle> particle_stack; private readonly GeometryModel3D particle_model; // positions, indices and texture co-ordinates for particles private readonly Point3DCollection particle_positions; private readonly Int32Collection triangle_indices; private readonly PointCollection text_coords; // brush to apply to particle_model.Material private RadialGradientBrush rad_brush; // ellipse for rendering private Ellipse ellipse; private RenderTargetBitmap render_bitmap; public AggregateSystem() { particle_stack = new Stack<AggregateParticle>(); particle_model = new GeometryModel3D { Geometry = new MeshGeometry3D() }; ellipse = new Ellipse { Width = 32.0, Height = 32.0 }; rad_brush = new RadialGradientBrush(); // fill ellipse interior using rad_brush ellipse.Fill = rad_brush; ellipse.Measure(new Size(32,32)); ellipse.Arrange(new Rect(0,0,32,32)); render_bitmap = new RenderTargetBitmap(32,32,96,96,PixelFormats.Pbgra32)); ImageBrush img_brush = new ImageBrush(render_bitmap); DiffuseMaterial diff_mat = new DiffuseMaterial(img_brush); particle_model.Material = diff_mat; particle_positions = new Point3DCollection(); triangle_indices = new Int32Collection(); tex_coords = new PointCollection(); } public Model3D AggregateModel => particle_model; public void Update() { // get the most recently added particle AggregateParticle p = particle_stack.Peek(); // compute position index for triangle index generation int position_index = particle_stack.Count * 4; // create points associated with particle for circle generation Point3D p1 = new Point3D(p.position.X, p.position.Y, p.position.Z); Point3D p2 = new Point3D(p.position.X, p.position.Y + p.size, p.position.Z); Point3D p3 = new Point3D(p.position.X + p.size, p.position.Y + p.size, p.position.Z); Point3D p4 = new Point3D(p.position.X + p.size, p.position.Y, p.position.Z); // add points to particle positions collection particle_positions.Add(p1); particle_positions.Add(p2); particle_positions.Add(p3); particle_positions.Add(p4); // create points for texture co-ords Point t1 = new Point(0.0, 0.0); Point t2 = new Point(0.0, 1.0); Point t3 = new Point(1.0, 1.0); Point t4 = new Point(1.0, 0.0); // add texture co-ords points to texcoords collection tex_coords.Add(t1); tex_coords.Add(t2); tex_coords.Add(t3); tex_coords.Add(t4); // add position indices to indices collection triangle_indices.Add(position_index); triangle_indices.Add(position_index + 2); triangle_indices.Add(position_index + 1); triangle_indices.Add(position_index); triangle_indices.Add(position_index + 3); triangle_indices.Add(position_index + 2); // update colour of points - **NOTE: UPDATES ENTIRE POINT SYSTEM** // -> want to just apply colour to single particles added rad_brush.GradientStops.Add(new GradientStop(p.colour, 0.0)); render_bitmap.Render(ellipse); // set particle_model Geometry model properties ((MeshGeometry3D)particle_model.Geometry).Positions = particle_positions; ((MeshGeometry3D)particle_model.Geometry).TriangleIndices = triangle_indices; ((MeshGeometry3D)particle_model.Geometry).TextureCoordinates = tex_coords; } public void SpawnParticle(Point3D _pos, Color _col, double _size) { AggregateParticle agg_particle = new AggregateParticle { position = _pos, colour = _col, size = _size; } // push most-recently-added particle to stack particle_stack.Push(agg_particle); } } 

where AggregateParticle is the POD class consisting of Point3D position , Color color and double size fields, which do not require explanation.

Is there a simple and effective method for updating the color of an individual particle, since it is added in the Update method, and not the entire particle system? Or do I need to create a List (or similar data structure) of DiffuseMaterial instances for each particle in the system and apply brushes for the desired color for each?

[The latter is something that I want to avoid at all costs, partly because my code will require major structural changes, and I'm sure there is a better way to get close to this, i.e. there MUST be an easy way to apply color to a set of texture coordinates, of course?!.]

Additional Information

  • AggregateModel is the only Model3D instance corresponding to the particle_model field that is added to the Model3DGroup MainWindow .

  • I should note that what I am trying to achieve, in particular, is a “gradient” of colors for each particle in the overall structure, where the particle has Color in the “temperature gradient” (calculated elsewhere in the program), which depends on the order in which it was generated, i.e. particles have a colder color if generated earlier, and a warmer color if created later. This list of colors is pre-computed and transmitted to each particle using the Update method, as seen above.

  • In one attempt, I tried to create a separate instance of AggregateComponent for each particle, where each of these objects has an associated Model3D and, therefore, a corresponding brush. Then an AggregateComponentManager class was created containing a List for each AggregateComponent . This solution works, however it is terribly slow since each component needs to be updated every time a particle is added, so memory usage explodes - is there any way to adapt this when I can cache the already displayed AggregateComponent without having to call them Update every time is a particle being added?

The full source code (C # code in the DLAProject directory) can be found on GitHub: https://github.com/SJR276/DLAProject

+7
c # colors wpf
source share
1 answer

We are creating WPF 3D models for small point clouds (+/- 100 k points), where each point is added as an octahedron (8 triangles) in MeshGeometry3D.

To allow different colors for different points (we use this to select one or a subset of points) in such a point cloud, we assign texture coordinates from a small bitmap image.

At a high level, we have this code:

 BitmapSource bm = GetColorsBitmap(new List<Color> { BaseColor, SelectedColor }); ImageBrush ib = new ImageBrush(bm) { ViewportUnits = BrushMappingMode.Absolute, Viewport = new Rect(0, 0, 1, 1) // Matches the pixels in the bitmap. }; GeometryModel3D model = new GeometryModel3D { Material = new DiffuseMaterial(ib) }; 

and now the texture coordinates are just

 new Point(0, 0); new Point(1, 0); 

... etc.

Raster image of flowers:

 // Creates a bitmap that has a single row containing single pixels with the given colors. // At most 256 colors. public static BitmapSource GetColorsBitmap(IList<Color> colors) { if (colors == null) throw new ArgumentNullException("colors"); if (colors.Count > 256) throw new ArgumentOutOfRangeException("colors", "More than 256 colors"); int size = colors.Count; for (int j = colors.Count; j < 256; j++) { colors.Add(Colors.White); } var palette = new BitmapPalette(colors); byte[] pixels = new byte[size]; for (int i = 0; i < size; i++) { pixels[i] = (byte)i; } var bm = BitmapSource.Create(size, 1, 96, 96, PixelFormats.Indexed8, palette, pixels, 1 * size); bm.Freeze(); return bm; } 

We also try to cache and reuse the internal Geometry structure when updating the point cloud.

Finally, we show this with the awesome Helix Toolkit .

+7
source share

All Articles