我无法理解C#WPF项目的颜色/材质系统,目前我正在更新模型每次更新时整个点系统的颜色,而我只想更新单个颜色点(因为它被添加).
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);
}
}
Run Code Online (Sandbox Code Playgroud)
其中AggregateParticle包含POD类Point3D position,Color color以及double size不言自明的字段.
是否有任何简单有效的方法来更新单个粒子的颜色,因为它是在Update方法中而不是整个粒子系统中添加的?或者我是否需要为系统中的每个粒子创建一个List(或类似的数据结构)DiffuseMaterial实例,并为每个粒子应用必要颜色的画笔?
[后者是我要不惜一切代价避免,部分原因是它需要我的代码较大的结构性变化的事实,我敢肯定有一个更好的方式来处理这个比-即有必须有一些简单的将颜色应用于一组纹理坐标的方法,当然?!]
更多详情
AggregateModel是一个单一的Model3D对应于该字段实例particle_model,其被添加到Model3DGroup的MainWindow.
我应该注意到我想要实现的目标,具体来说,这里是聚合结构中每个粒子的"渐变"颜色,其中粒子具有Color"温度梯度"(在程序中的其他地方计算),这是依赖的按照生成它的顺序 - 即,如果先前生成,则粒子具有较冷的颜色,如果稍后生成则具有较暖的颜色.Update如上所示,该颜色列表被预先计算并传递给方法中的每个粒子.
我尝试的一个解决方案涉及AggregateComponent为每个粒子创建一个单独的实例,其中每个对象都有一个关联的Model3D,因此有一个相应的画笔.然后AggregateComponentManager创建了一个包含List每个类的类AggregateComponent.这个解决方案有效,但是它非常慢,因为每次添加粒子时都必须更新每个组件,因此内存使用量会爆炸 - 是否有一种方法可以适应这种情况,我可以缓存已经渲染AggregateComponent的内容而无需Update每次都调用它们的方法粒子加?
完整的源代码(DLAProject目录中的C#代码)可以在GitHub上找到:https://github.com/SJR276/DLAProject
我们为小点云(+/- 100 k点)创建WPF 3D模型,其中每个点作为八面体(8个三角形)添加到MeshGeometry3D.
为了在这样的点云中允许不同点的不同颜色(我们使用它来选择一个点或一个子集),我们从一个小的位图分配纹理坐标.
从高层次来看,我们有一些像这样的代码:
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) };
Run Code Online (Sandbox Code Playgroud)
现在纹理坐标正好
new Point(0, 0);
new Point(1, 0);
Run Code Online (Sandbox Code Playgroud)
...等
Bitmap的颜色来自:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
在更新点云时,我们还会尝试缓存和重用内部几何结构.
最后,我们使用了很棒的Helix Toolkit来展示它.
| 归档时间: |
|
| 查看次数: |
875 次 |
| 最近记录: |