Nearest-neighbor image sampling in 3D WPF - c#

I'm desperately trying to render images onto a 3D surface in WPF using nearest-neighbor sampling. Below is an example of what I currently have, in all its blurriness. The ImageBrush is given a 64x64 texture.
I've tried decorating the XAML with RenderOptions.BitmapScalingMode="NearestNeighbor" everywhere from the Window to the ImageBrush without fortune. I've tried writing a custom pixel shader, and couldn't get a satisfactory result. It even appears that I cannot set the texture sampler's filtering mode from within the shader code. I've considered work-arounds, such as scaling up the source texture myself, but this would still leave artifacts at two of the edges where it begins interpolating into the next pixel.
Bottom line: Is there any way I can accomplish the effect of nearest neighbor image sampling on a 3D model in WPF?

Just had the same problem, the answer in this thread provides a workaround.
You can use a VisualBrush with an Image then WPF will respect the BitmapScalingMode on the image. You can also set the CachingHint (also on RenderOptions) which might improve performance (did not measure it though).
var image = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/Resources/image.png")) };
RenderOptions.SetCachingHint(image, CachingHint.Cache);
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.NearestNeighbor);
var material = new DiffuseMaterial(new VisualBrush(image));
That works for simple scenes, as I said I didn't measure the performance, but I imagine the VisualBrush will hurt for bigger stuff (compared to an ImageBrush). Personally I'll switch over to Direct3D interop and render the scene via SharpDX when I hit that problem.

Related

DrawingGroup.ClipGeometry insights (Performance)

i am refactoring some code that used System.Drawing classes and GDi in order to draw a complex map image. The image consists of objects like lines and polygons.
In order to clip the objects, we used a implementation of a clipping algorithm, that first checked wether the object ist within the borders of a bitmap or not. If it was intersecting, the object got clipped.
We now want to draw the same map image with WPF methods. I am using drawinggroups to create the geometry drawings. DrawingGroups offer the possibility of adding a ClipGeometry, like that:
TileSize = new RectangleGeometry(new Rect(tileOrigin, new Size(Width, Height)));
mapDrawing.ClipGeometry = TileSize;
The result looks good, and i can "feel" no difference in performance. Problem is, i have a hard time to measure that. I can definetly say how long it took to clip the objects with our algorithem, but i cant measure what time is needed for the clipping with the ClipGeometry. I guess the clipping is done when the UI starts rendering the drawings.
My questions:
How could i measure the time needed for clipping with WPF ClipGeometry?
Does anyone know how exactly ClipGeometry does the clipping?
Thanx for your input!

How to get a ScrollViewer to zoom in to see individual pixels?

I'm making an app for Windows 8.1 where it is important to be able to zoom in and examine images in detail. If I just open up the bitmap and zoom in it looks like.
However when I load the image into my app and use the ScrollViewer to zoom in I get.
As it appears to be trying to interpolate pixel values for some sort of anti-aliasing.
How can I get it so that when I zoom in it shows (as best it can) the exact pixels of the image? In particular I'm using the image as the background to a canvas which is contained in a scroll viewer.
I've looked around on here and MSDN and found a pair of related questions, but as yet they don't seem to have solved my exact problem.
A discussion on WPF
A similar issue with a canvas
Older related question on pixel art
A way to use bitmap encoding (which I couldn't get to work)
Similarly phrased question
There is no easy way to go about this, your best option is to use DirectX to render the image much larger so that you can mitigate the effect of WinRT automatically interpolating pixel values.
As someone explained on MSDN and based on this outstanding request I can't see any other way to accomplish this.
Use Win2D
Win2D is a DirectX inter-op library for WinRT. With this you can render the image at a much larger size, and then set the default zoom level for the scrollViewier to be very small. Because of this when you zoom in it will appear to be that you can see the individual pixels without any fuzzy/blurry interpolation because you will actually be seeing groups of 64 pixels or so all as one color. I couldn't find any way to actually override what kind of interpolation gets done so this seems to be the best method.
Download Win2D as a NuGet package using Visual Studio, Win2D's
quickstart guide does a good job explaining some of the setup
Set up your canvas and the draw event and use the DrawImage function to render the image larger
<ScrollViewer x:Name="Scroller" ZoomMode="Enabled"
MinZoomFactor="0.1" MaxZoomFactor="20">
<canvas:CanvasControl x:Name="canvas" Draw="canvas_Draw" CreateResources="create"/>
</ScrollViewer>
In the canvas_draw function.
canvas.Width = original.Width * 10;
canvas.Height = original.Height * 10;
args.DrawingSession.DrawImage(bitmap,new Rect(0,0,original.Width*10,original.Height*10), new Rect(0,0,original.Width,original.Height), 1.0f, CanvasImageInterpolation.NearestNeighbor);
Make sure to set your canvas to be larger as well
In your code behind set the default zoom of your ScrollVieiwer to be appropriate so your image appears to be the same size.
In the page constructor
Scroller.ZoomToFactor (0.1f);
Other Ways Which I Looked Into and Didn't Work
Making the canvas very large and using BitmapEncoder/BitmapDecoder with the interpolation mode set to NearestNeighbor, this introduced lots of visual artifacts even when scaled to a power of 2 size
Render options only appear to be usable in WPF and not WinRT
It may also be possible to use some image manipulation library to simply make the bitmap 10x or so as large and then use that, but I ended up using Win2D instead.

How do I create 3D text in a 3D ViewPort object in a C# WPF project?

(Sorry if this is in the wrong place. I have been bouncing around SO and Programmers SE Sites all day and I keep getting flagged. Some insight as to what I am doing wrong would be helpful). Now on to my question:
I have been following the 3D WPF C# tutorial here: http://kindohm.com/technical/WPF3DTutorial.htm all the way up to the cube demo. I am wondering if there is a way to place text on the cube either as part of the texture or as 3D text attached to the cube. If someone could point me towards a tutorial or a code snippet that would be helpful. Thanks!
Update: I forgot to mention that the one thing that I am doing differently from the tutorial is that I am embedding the WPF ViewPort control inside of a WPF UserControl inside of an ElementHost inside of a Windows Form.
The tutorial shows how to use Material, with a SolidColorBrush. Besides SolidColorBrush there are some more kinds of Brushes can be used with the Material. For example You can use VisualBrush, in which you can use any kind of Visual, including DrawingVisual and even UIElement.
Notice that if you're going to render heavy scene with a lot of texts you might encounter performance issues. UIElement performs very bad in 3D scene, so I would prefer using DrawingVisual instead. If that's still not good enough, you can rasterize your DrawingVisual using RenderTargetBitmap and then use ImageBrush instead of the VisualBrush (that's good only if the text is static - if you would like to use animations you must use the VisualBrush without rasterization).

Stretch a texture in XNA 4.0?

I can't figure anyway to do this, I don't want to scale it with .Draw, I want to just change the width.
The best way is using .Draw particularly if you are scaling a lot, especially as your object should handle its own drawing capabilities.
You can render the texture using a render target at the size you want, and then saving the render target texture.
Searching for a quick code example came up with the following which is saying the same thing:
How to resize and save a Texture2D in XNA?

Rendering DirectX 3D graphics onto an Image directly, using C#

The project I'm working on requires the ability to transform any of the 4 corners of an image. As GDI+ unfortunately doesn't have this capability, we're resorting into using DirectX's 3D graphics.
While I have a square mesh with a texture showing successfully on-screen, I need to be able to generate an image from this rendering, with the background set to transparent. Is there a way to efficiently achieve this?
Preferably, I'd like to do this without using a Control for initializing a device. Alternatively, I don't mind the option of creating a custom, invisible Control that will generates an image for me.
Edit:
Actually, I just realized a transparent background is strictly not necessary, but it would help the performance of our project a bit.
Anyway, I've had some luck doing something like this, but it is excessively slow. Perhaps there's a better method?
// Create a surface to render an image to
Surface mSurface = mDevice.GetRenderTarget(0);
// Render the visualization
mDevice.Clear(ClearFlags.Target, Color.Transparent, 1.0f, 0);
mDevice.BeginScene();
/* Do some amazing stuff */
// Exit rendering
mDevice.EndScene();
mDevice.Present();
// Render the bitmap images
GraphicsStream mGraphics = SurfaceLoader.SaveToStream(
ImageFileFormat.Bmp, mSurface);
Image mImage = new Bitmap(mGraphics, false);
Well if you use D3D for doing the final rendering to screen then you can easily do the things you are talking about using render-to-texture.

Categories

Resources