Image shear in WPF - wpf

I am trying to shear an Image in WPF (C#) using pure XAML. I have used transformations such as skew, scale and matrix but I am not getting the result as I want. Following is the code I am using
<Image Source="G:\Demo\virtualization\virtualization\img3.bmp" Stretch="Fill" Height="70" Width="240" Margin="0,170,-312,-29" >
<Image.RenderTransform>
<TransformGroup>
<MatrixTransform Matrix="1,.1,-4.2,1,0,0" />
<!--<ScaleTransform ScaleX=".2" ScaleY=".6"/>-->
</TransformGroup>
</Image.RenderTransform>
</Image>
With the above code, below is the similar effect that I am getting:
/----/
/ /
/ /
/----/
But I want following effect:
/---\
/ \
/ \
/---------\
Due to new user, I am not allowed to post Images right now...
Thanks
EDIT:
I have tried viewport3d to get this effect. Following is the code:
<Grid>
<Image Source="G:\Demo\virtualization\virtualization\2.jpg"/>
<Viewport3D Name="mainViewport" ClipToBounds="True" HorizontalAlignment="Stretch" Height="300">
<Viewport3D.Camera>
<PerspectiveCamera Position="0, 0, 20" />
</Viewport3D.Camera>
<Viewport2DVisual3D>
<Viewport2DVisual3D.Transform>
<MatrixTransform3D Matrix="1,0,0,0
0,1,0,0
0,0,1,0
0,0,0,1" />
</Viewport2DVisual3D.Transform>
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0"
TextureCoordinates="0,0 0,1 1,1 1,0" TriangleIndices="0 1 2 0 2 3"/>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" Brush="White"/>
</Viewport2DVisual3D.Material>
<Grid>
<Image Source="G:\Demo\virtualization\virtualization\img3.bmp"/>
</Grid>
</Viewport2DVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="#FFFFFFFF" Direction="0,-1,-1"/>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
I am using matrix transformation to get the effect.
However I am looking to alternate ways to get this effect May be rotating the camera of viewport.

You cannot achieve this kind of effect with linear transformation (mathematically impossible).
You could get this effect with WPF 3D.

You can achieve this effect with a custom pixel shader.
Download a copy of Shazzam (it's free) and check out the paperfold sample (shazzam-tool.com). While it's not exactly the shear effect you showed in your question, it is close.
Have you worked with shaders before? If you want to use a custom shader I have a prototype shear effect that I worked on a couple months ago. I can clean up the HLSL and post it here.
Edit
Shazzam contains a tutorial section and about 80 sample shaders. That's a good place to start. The hardest part about using custom shaders is that you have to learn a new language (HLSL).
There is a list of shader articles at http://blog.shazzam-tool.com/index.php/shader-articles/

Related

Rotate canvas along x axis in WPF

I have a 2D canvas that I want to rotate along the x-axis. I later want to animate movement of the object along the z-axis.
With CSS, rotating along the x-axis is straightforward:
transform: rotateX(30deg);, and so is translation over the z-axis.
Here is a demonstration of how I want to rotate the XAML canvas.
How can I achieve the same effect in XAML/WPF? I tried using a Viewport3D with a Viewport2DVisual3D as a starting point to apply the 3D transformation. However, the canvas does not even render once placed. I don't know if the material lighting or geometry needs to be adjusted. What's the best approach I should go for? Is there a tool I can use to simplify this work?
I tried using code from How to rotate 2D UIElement around a 3D axis (Y)?, and How to rotate 2D UIElement around a 3D axis (Y)?. I can't seem to get my code to work with a canvas.
EDIT:
I tried using the code at http://www.codeproject.com/Articles/34391/Rotating-WPF-Content-in-D-Space (section "ContentControl3D Internals") as a base for the starting point:
<Viewport2DVisual3D>
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D TriangleIndices="0,1,2 2,3,0" TextureCoordinates="0,1 1,1 1,0 0,0" Positions="-1,-1,0 1,-1,0 1,1,0 -1,1,0" />
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="180" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</Viewport2DVisual3D.Transform>
<Viewport2DVisual3D.Material>
<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" Brush="White" />
</Viewport2DVisual3D.Material>
<Viewport2DVisual3D.Visual>
<Border BorderBrush="Transparent" BorderThickness="1">
<Canvas>
<!-- ... -->
</Canvas>
</Border>
</Viewport2DVisual3D.Visual>
</Viewport2DVisual3D>
The canvas does not render. I did try using other wrappers as well from the other links I provided, and had no luck getting the visuals to render.
From this example page, Add a camera and some lighting (lighting optional):
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="0, 0, 4"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="#FFFFFFFF" Direction="0,0,-1"></DirectionalLight>
</ModelVisual3D.Content>
</ModelVisual3D>
<Viewport2DVisual3D>
...
</Viewport2DVisual3D>
The rotation angle 180 is really big, I think that is flipping your border all the way around backwards.

WPF MeshGeometry3D image scaling is blurry

Context: I am trying to render Minecraft characters in WPF to preview skins. These skins are extremely tiny, such as the skin for the head I am trying to get working is 8x8 pixels.
Currently when I slap on the texture onto the mesh, it will render fine but the scaling makes it extremely blurry. I need it to scale in such a way that it doesn't try and 'smooth out' the scaling as the pixels are meant to be crisp lines. I couldn't find any properties on the ImageBrush that could help me with this result. My XAML:
<ModelVisual3D>
<ModelVisual3D.Content>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-1,1,1 -1,-1,1 1,-1,1 1,1,1" TriangleIndices="0,1,2 0,2,3" TextureCoordinates="0,0 0,1 1,1 1,0"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush ImageSource="../Images/SteveHead.png" />
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
</GeometryModel3D>
</ModelVisual3D.Content>
</ModelVisual3D>
This is the texture for the head (it's really here, just tiny :p)
And the result I am getting with this XAML:
Any tips so I can scale this up with the 'pixels' intact?

Viewport3D performance on a simple mesh

I created a full-screen WPF Canvas, representing a time line. Only the visible part of the time line is composed, so (practically) no UI elements lie outside of the visible range.
I'm trying to add perspective to this time line using a Viewport3D. The result at the moment looks as follows:
You can scroll the time line left and right by dragging. Performance in the 2D version is great. However, once the canvas is placed inside a Viewport3D using Viewport2DVisual3D, performance drops drastically.
It's not like I'm rendering a complex mesh, where is this performance decrease coming from, and can I prevent it?
To give you an idea of how the 3D perspective was realized I'll add the XAML code here, unfortunately it doesn't work on its own.
<Grid Background="{StaticResource BackgroundBrush}">
<Viewport3D ClipToBounds="False">
<Viewport3D.Camera>
<PerspectiveCamera
Position="0 0 5"
LookDirection="0.4 0 -1"
UpDirection="0 1 0" />
</Viewport3D.Camera>
<ContainerUIElement3D>
<ModelUIElement3D>
<AmbientLight Color="White" />
</ModelUIElement3D>
</ContainerUIElement3D>
<Viewport2DVisual3D>
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D
TriangleIndices="0,1,2 2,3,0"
TextureCoordinates="0 0, 0 1, 1 1, 1 0">
<MeshGeometry3D.Positions>
<MultiBinding Converter="{StaticResource AspectRatioToPositions}">
<Binding ElementName="TimeLineContainer" Path="Width" />
<Binding ElementName="TimeLineContainer" Path="Height" />
</MultiBinding>
</MeshGeometry3D.Positions>
</MeshGeometry3D>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial
Viewport2DVisual3D.IsVisualHostMaterial="True"
Brush="White" />
</Viewport2DVisual3D.Material>
<Grid
x:Name="TimeLineContainer"
Width="1650" Height="600"
ClipToBounds="True"
Background="{StaticResource TimeLineBrush}"
Behaviors:MouseBehavior.LeftClickDragCommand="ActivityOverview:ActivityOverviewWindow.MouseDragged"
MouseWheel="OnMouseWheel"
MouseMove="OnMouseMoved">
<ActivityOverview:TimeLineControl x:Name="TimeLine" Focusable="True">
<ActivityOverview:TimeLineControl.CommandBindings>
<CommandBinding
Command="ActivityOverview:ActivityOverviewWindow.MouseDragged"
Executed="MoveTimeLine" />
</ActivityOverview:TimeLineControl.CommandBindings>
</ActivityOverview:TimeLineControl>
</Grid>
</Viewport2DVisual3D>
</Viewport3D>
</Grid>
When using Viewport2DVisual3D performance can be slow when you attempt to display content that is time-consuming to render. This seemed to be the case in my example.
For this reason, you can set the CacheMode of Viewport2DVisual3D.
<Viewport2DVisual3D>
<Viewport2DVisual3D.CacheMode>
<BitmapCache />
</Viewport2DVisual3D.CacheMode>
...
</Viewport2DVisual3D>
Starting from Windows Vista, anti-aliasing is enabled by default. Disabling this also helps in improving performance. It's weird this would have a big impact with such a simple mesh (two triangles), but on my PC, it does!
<Viewport3D ClipToBounds="False" RenderOptions.EdgeMode="Aliased">
Combining these two settings, I got great improvements.
Hi guys you can use <OrthographicCamera Position="0 0 5" LookDirection="0.4 0 -1" UpDirection="0 1 0" /> . Please check my code below
<Grid Background="{StaticResource BackgroundBrush}">
<Viewport3D ClipToBounds="False">
<Viewport3D.Camera>
<OrthographicCamera
Position="0 0 5"
LookDirection="0.4 0 -1"
UpDirection="0 1 0" />
</Viewport3D.Camera>
<ContainerUIElement3D>
<ModelUIElement3D>
<AmbientLight Color="White" />
</ModelUIElement3D>
</ContainerUIElement3D>
<Viewport2DVisual3D>
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D
TriangleIndices="0,1,2 2,3,0"
TextureCoordinates="0 0, 0 1, 1 1, 1 0">
<MeshGeometry3D.Positions>
<MultiBinding Converter="{StaticResource AspectRatioToPositions}">
<Binding ElementName="TimeLineContainer" Path="Width" />
<Binding ElementName="TimeLineContainer" Path="Height" />
</MultiBinding>
</MeshGeometry3D.Positions>
</MeshGeometry3D>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial
Viewport2DVisual3D.IsVisualHostMaterial="True"
Brush="White" />
</Viewport2DVisual3D.Material>
<Grid
x:Name="TimeLineContainer"
Width="1650" Height="600"
ClipToBounds="True"
Background="{StaticResource TimeLineBrush}"
Behaviors:MouseBehavior.LeftClickDragCommand="ActivityOverview:ActivityOverviewWindow.MouseDragged"
MouseWheel="OnMouseWheel"
MouseMove="OnMouseMoved">
<ActivityOverview:TimeLineControl x:Name="TimeLine" Focusable="True">
<ActivityOverview:TimeLineControl.CommandBindings>
<CommandBinding
Command="ActivityOverview:ActivityOverviewWindow.MouseDragged"
Executed="MoveTimeLine" />
</ActivityOverview:TimeLineControl.CommandBindings>
</ActivityOverview:TimeLineControl>
</Grid>
</Viewport2DVisual3D>
</Viewport3D>

Why can a control draw outside its bounding box?

Here's an example image of what I mean: example
The gray rectangle is the bounding box of a control that draws the blue lines and dots in it's OnRender(...) method. The red ovals mark places where it happens.
Why is that possible?
How can it be avoided?
Here's the perfect answer to my second question, at least when using a rectangular shaped control:
<object ClipToBounds="True" />
More details on the MSDN.
https://msdn.microsoft.com/en-us/library/ms750441(v=vs.100).aspx has detailed information about the architectural design of WPF to answer why it is possible.
To avoid it you want to use the clip property of your element.
<Rectangle Fill="Yellow" Height="100" Width="200" StrokeThickness="2" Stroke="Black">
<Rectangle.Clip>
<EllipseGeometry Center="200,100" RadiusX="50" RadiusY="50" />
</Rectangle.Clip>
</Rectangle>
Check out http://msdn.microsoft.com/en-us/library/cc189065%28v=VS.95%29.aspx for more details.

A question about WPF. Size in Viewport3D

<Window x:Class="Viewport2DVisual3DExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Button on 3D"
WindowStyle="None"
Background="{x:Null}"
Foreground="{x:Null}"
AllowsTransparency="True"
>
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera Position="0, 0, 4"/>
</Viewport3D.Camera>
<!-- Front -->
<Viewport2DVisual3D>
<!-- Give the plane a slight rotation -->
<Viewport2DVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="frontTransform" Angle="0" Axis="0, 1, 0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</Viewport2DVisual3D.Transform>
<!-- The Geometry, Material, and Visual for the Viewport2DVisual3D -->
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0"
TextureCoordinates="0,0 0,1 1,1 1,0" TriangleIndices="0 1 2 0 2 3"/>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" Brush="White"/>
</Viewport2DVisual3D.Material>
<!-- Here Here Here Here Here -->
<Image Source="i:\\tempa\\tm.png" Width="534" Height="458" />
</Viewport2DVisual3D>
<!-- Back -->
<Viewport2DVisual3D>
<!-- Give the plane a slight rotation -->
<Viewport2DVisual3D.Transform>
<RotateTransform3D >
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="backTransform" Angle="180" Axis="0, 1, 0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</Viewport2DVisual3D.Transform>
<!-- The Geometry, Material, and Visual for the Viewport2DVisual3D -->
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D Positions="-1,1,0 -1,-1,0 1,-1,0 1,1,0"
TextureCoordinates="0,0 0,1 1,1 1,0" TriangleIndices="0 1 2 0 2 3"/>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial Viewport2DVisual3D.IsVisualHostMaterial="True" Brush="White"/>
</Viewport2DVisual3D.Material>
<Button Name="btnBack">Back</Button>
</Viewport2DVisual3D>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="#FFFFFFFF" Direction="0,0,-1"/>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
I am trying to build a 2-Side window using Viewport3D. But then I had some trouble about size.
<!-- Here Here Here Here Here -->
<Image Source="i:\\tempa\\tm.png" Width="534" Height="458" />
I want this Image to be the exact same size as its source image.
Neither a specified value or "auto" would work.
How can I get what I want?
My 3d knowledge is limited and someone can probably answer this better, but in a 3d environment, the size of an object is dependent on a lot of things.. camera position,near/far plane, the size/location of the object, transforms applied to that object, viewport size, and probably other stuff I'm forgetting. The 3d engine takes all the stuff into account when rendering stuff. Setting the size of the image is just one piece of it.
Maybe try messing with the camera position or adding a scaletransform to the image.
What you are looking for is the projection matrix of the camera. That matrix transforms a 3D point into a 2D point. So by passing the 3D coordinates of the MeshGeometry3D you can find out the 2D coordinates and sizes.

Resources