c# - Update color of single point of GeometryModel3D Material rather than whole system of points -


i'm having trouble getting head around colour/material system of c# wpf projects, updating colour of entire system of points on each update of model when instead update colour of single point (as added).

aggregatesystem class

public class aggregatesystem {     // stack store each particle in aggregate     private readonly stack<aggregateparticle> particle_stack;     private readonly geometrymodel3d particle_model;     // positions, indices , texture co-ordinates particles     private readonly point3dcollection particle_positions;     private readonly int32collection triangle_indices;     private readonly pointcollection text_coords;     // brush apply particle_model.material     private radialgradientbrush rad_brush;     // ellipse 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() {         // added particle         aggregateparticle p = particle_stack.peek();         // compute position index triangle index generation         int position_index = particle_stack.count * 4;         // create points associated particle 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 particle positions collection         particle_positions.add(p1);         particle_positions.add(p2);         particle_positions.add(p3);         particle_positions.add(p4);         // create points 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 texcoords collection         tex_coords.add(t1);         tex_coords.add(t2);         tex_coords.add(t3);         tex_coords.add(t4);         // add position indices 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 apply colour 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 stack         particle_stack.push(agg_particle);     }  } 

where aggregateparticle pod class consisting of point3d position, color color , double size fields self-explanatory.

is there simple , efficient method update colour of single particle added in update method rather entire system of particles? or need create list (or similar data structure) of diffusematerial instances each , every particle in system , apply brushes necessary colour each?

[the latter want avoid @ costs, partly due fact require large structural changes code, , there better way approach - i.e. there must simple way apply colour set of texture co-ordinates, surely?!.]

further details

  • aggregatemodel single model3d instance corresponding field particle_model added model3dgroup of mainwindow.

  • i should note trying achieve, specifically, here "gradient" of colours each particle in aggregate structure particle has color in "temperature-gradient" (computed elsewhere in program) dependent upon order in generated - i.e. particles have colder colour if generated earlier , warmer colour if generated later. colour list pre-computed , passed each particle in update method can seen above.

  • one solution attempted involved creating separate aggregatecomponent instance each particle each of these objects has associated model3d , corresponding brush. aggregatecomponentmanager class created contained list of each aggregatecomponent. solution works, horrendously slow each component has updated every time particle added memory usage explodes - there way adapt can cache rendered aggregatecomponents without having call update method each time particle added?

full source code (c# code in dlaproject directory) can found on github: https://github.com/sjr276/dlaproject

we create wpf 3d models smallish point clouds (+/- 100 k points) each point added octahedron (8 triangles) meshgeometry3d.

to allow different colors different points (we use selecting 1 or subset of points) in such point cloud, assign texture coordinates small bitmap.

at high level have code this:

bitmapsource bm = getcolorsbitmap(new list<color> { basecolor, selectedcolor }); imagebrush ib = new imagebrush(bm)  {      viewportunits = brushmappingmode.absolute,      viewport = new rect(0, 0, 1, 1) // matches pixels in bitmap. };   geometrymodel3d model = new geometrymodel3d { material = new diffusematerial(ib) }; 

and texture coordinates

new point(0, 0); new point(1, 0); 

... etc.

the colors bitmap comes from:

// creates bitmap has single row containing single pixels given colors. // @ 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 256 colors");      int size = colors.count;     (int j = colors.count; j < 256; j++)     {         colors.add(colors.white);     }      var palette = new bitmappalette(colors);     byte[] pixels = new byte[size];     (int = 0; < 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 go effort cache , reuse internal geometry structure when updating point cloud.

finally display awesome helix toolkit.