PointsVisual3D different Point Colors

Oct 1, 2012 at 4:20 PM

Hi,

i have a PointsVisual3D object and I would like to use different colors for the points. As objo mentioned in this post, creating different materials (by creating different PointsVisual3D subobjects) for each point is too slow in rendering. But I don't understand what objo means by "This only supports a single color, but can be extended to support a material containing a 'palette' of colors (then you can set different colors for each point by texture coordinates)." Could you explain it to me or give me an example?

Kind regards, Dave_evaD

Oct 1, 2012 at 7:36 PM
Edited Oct 1, 2012 at 7:45 PM

I have some pieces that might get you started:

You can create a small bitmap with one row of colors, maybe like this:

 

		// 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("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;
		}

 

Then your model might use this Bitmap as its Brush (only two colors used here):

 

	BitmapSource bm = Mesh3DUtil.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() { Geometry = mesh, Material = new DiffuseMaterial(ib) };

And then for the TextureCoordinates you pick points halfway along the Bitmap:

 

    mesh.TextureCoordinates.Add(new Point(0.5, 0.5));

 

This is for each little mesh of triangles that forms the little sphere for a point.

Oct 1, 2012 at 8:00 PM

Hi govert,

thank you for your reply. I think I've finally understood what the ImageBrush idea is about. But there remains a problem:

As far as I see, I can't set the material/brush for the PointsVisual3D object since it is set in a private method in ScreenSpaceVisual3D. Furthermore I can't access the TextureCoordinates.

Looks like I have to modify the code a bit. I hope the license allows that ;)

 

Oct 2, 2012 at 9:21 PM

Hi govert,

is there a way to use more than 256 colors? I've found nothing for an ImageBrush, what about a BitmapCacheBrush?

Oct 2, 2012 at 9:37 PM

The 256 color limitation might just be a result of the PixelFormat I chose in the BitmapSource.Create call. So if you pick another PixelFormat it might work with more colors. I don't think it has anything to do with the ImageBrush itself. I don't know anything about BitmapCacheBrush, but that seems like a performance optimisation.

This was done a few years ago, though, and I remember that getting the Bitmap and the colors to work right was rather fiddly. You have to get into this stuff a bit: http://msdn.microsoft.com/en-us/magazine/cc534995.aspx.

Oct 2, 2012 at 9:53 PM

I tried changing the PixelFormat but the restriction comes from the BitmapPalette. Here's what I found out up to now:

You could use a Brush that draws an ImageSource or a Visual.

If you want to use the ImageSource, you have certain possibilities:

-You could draw a Drawing which offers the possibility to draw an ImageSource (among others which I don't think about that they will be useful)

-You could draw a Direct3D image which does not seem to be what I want

-You could draw a BitmapSource (which has certain subtypes as shown in your link). But each of them has a BitmapPalette which is restricted to 256 colors

If you want to use a Visual, you also have different options:

-A Viewport3DVisual does not seem to be the right thing

-You can draw a Drawing which results in drawing an ImageSource

-You can draw a UIElement. Maybe I could use a Canvas on which I have drawn an Image before, but I wonder whether there is no way to use an Image or Bitmap (not BitmapSource) directly?

Oct 2, 2012 at 10:12 PM

I don't think you have to use an indexed Bitmap format with a fixed palette. You should be able to use one of the other Bitmap formats which give the color of each pixel ? I'd expect WPF to handle most of these formats fine when used with an ImageBrush. You just have to figure out how to encode the actual Bitmap data - maybe first make some bitmaps in Paint or something, and see if you can map those colors into TextureCoordinates.

Oct 2, 2012 at 10:50 PM

Hi,

you were right, I realized that I didn't have to use the palette. I use the Bgra32-Format now.

Thanks for your tips.