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
singlemodel3d
instance corresponding fieldparticle_model
addedmodel3dgroup
ofmainwindow
.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 inupdate
method can seen above.one solution attempted involved creating separate
aggregatecomponent
instance each particle each of these objects has associatedmodel3d
, corresponding brush.aggregatecomponentmanager
class created containedlist
of eachaggregatecomponent
. solution works, horrendously slow each component has updated every time particle added memory usage explodes - there way adapt can cache renderedaggregatecomponent
s without having callupdate
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.