How to wire up 3DViewport in MVVM - wpf

I have built a Model3DGroup in code behind and it works OK, but now I want to move my Model3DGroup to a ModelView in an MVVM Pattern. The Model3DGroup is now set up as a property in the ModelView.
So my question is: How do I change the code below to bind the Model3DGroup to the Viewport3D control?
<Viewport3D Name="MainViewport" ClipToBounds="True" >
<Viewport3D.Camera>
<PerspectiveCamera
FarPlaneDistance="100"
LookDirection="-11,-10,-9"
UpDirection="0,1,0"
NearPlaneDistance="1"
Position="11,10,9"
FieldOfView="70" />
</Viewport3D.Camera>
<ModelUIElement3D ></ModelUIElement3D>
<ModelVisual3D>>
<ModelVisual3D.Content>
<DirectionalLight
Color="White"
Direction="-2,-3,-1" />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
Thanks for your help!

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 ModelVisuals3D not visible when inside Canvas

If I put viewport3D inside Canvas my viewport3D is not visible anymore. If I remove Canvas then Viewport3D is visible again. What I'm doing wrong?
<Canvas Width="900" Height="524">
<Viewport3D Name="mainViewport" ClipToBounds="True" HitTestVisible="False">
<Viewport3D.Camera>
<PerspectiveCamera
FarPlaneDistance="3500"
LookDirection="0,0,1"
UpDirection="0,1,0"
NearPlaneDistance="1"
Position="0,0,0"
FieldOfView="66" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="White" />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Canvas>
I think the ViewPort3D will end up in the upper left corner of the Canvas with a Width and Height of 0 since Canvas never stretches its Children. Try to add Canvas.Left and Canvas.Top at the positioning of your choise and then add Width and Height for your Viewport3D. If you want your Viewport3D to always fill the available space then Canvas is the wrong way to go.
<Canvas Width="900" Height="524">
<Viewport3D Canvas.Left="100"
Canvas.Top="100"
Width="200"
Height="200"
Name="mainViewport"
ClipToBounds="True"
IsHitTestVisible="False">
<Viewport3D.Camera>
<PerspectiveCamera
FarPlaneDistance="3500"
LookDirection="0,0,1"
UpDirection="0,1,0"
NearPlaneDistance="1"
Position="0,0,0"
FieldOfView="66" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="White" />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Canvas>

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.

Image shear in 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/

Resources