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>
Related
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.
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!
I have a XAML file of some view where a complex 3D model is defined. The problem is that the part defining the model is quite big, it has over 0.5 MB and it's really hard to browse through the file. Is there a way I can move e.g the Model3DGroup into another file and then include it in my main XAML file? I use a SketchUp to XAML converter which creates files with <Model3DGroup xmlns="..." xmlns:x="..."> as their roots, so I'm almost sure it can be done in a convenient way.
My current XAML file looks like this:
<UserControl x:Class="BigAtom.Views.WorkspaceView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestProj"
mc:Ignorable="d"
d:DesignHeight="278" d:DesignWidth="274">
<Grid x:Name="RootVisual" Background="Beige" ClipToBounds="True">
<Canvas Name="DrawingCanvas" Grid.Row="0" Grid.Column="0" Width="0" Height="0" RenderTransform="1,0,0,-1,0,0" Margin="10">
<Viewport3D Name="Object3D" Width="50" Height="50" Margin="-25,-25" ClipToBounds="False">
<Viewport3D.Camera>
<OrthographicCamera x:Name="CamMain" Position="0 60 100" LookDirection="0 -60 -100"></OrthographicCamera>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight x:Name="DirLightMain" Direction="-1,-1,-1"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D x:Name="MyModel">
<ModelVisual3D.Content>
<Model3DGroup>
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D Positions="-5.6166 10.4050 153.1136 [very long line]" TextureCoordinates="-5.616612 -10.405044 -3.582495 [very long line]" TriangleIndices="164 17 57 [very long line]"/>
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Color="White" Brush="#ffffff"/>
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Color="White" Brush="White"/>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Canvas>
</Grid>
</UserControl>
and I want to achieve something like this:
<UserControl x:Class="BigAtom.Views.WorkspaceView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestProj"
mc:Ignorable="d"
d:DesignHeight="278" d:DesignWidth="274">
<Grid x:Name="RootVisual" Background="Beige" ClipToBounds="True">
<Canvas Name="DrawingCanvas" Grid.Row="0" Grid.Column="0" Width="0" Height="0" RenderTransform="1,0,0,-1,0,0" Margin="10">
<Viewport3D Name="Object3D" Width="50" Height="50" Margin="-25,-25" ClipToBounds="False">
<Viewport3D.Camera>
<OrthographicCamera x:Name="CamMain" Position="0 60 100" LookDirection="0 -60 -100"></OrthographicCamera>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight x:Name="DirLightMain" Direction="-1,-1,-1"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<ModelVisual3D x:Name="MyModel">
<ModelVisual3D.Content>
<Model3DGroup --- some kind of reference to the file which keeps the 3D model --- />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Canvas>
</Grid>
</UserControl>
#edit
McGarnagle's answer is generally OK, but in my case I also have some DataTemplate defined in my UserControl.Resources. Because of this, I had to create such a structure:
<UserControl.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type local:SomeType}" x:Key="SomeTypeTemplate">
....
</DataTemplate>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Models.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
I imagine you should be able to use a resource dictionary for this. Add a file, say, "Models.xaml" with the definitions:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Model3DGroup x:Key="TheModelContent">
...
</Model3DGroup>
</ResourceDictionary>
Then reference the file in your UserControl, and refer to the models using the StaticResource keyword:
<UserControl>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Models.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- other resources here -->
</ResourceDictionary>
</UserControl.Resources>
...
<ModelVisual3D Content="{StaticResource TheModelContent}">
...
</UserControl>
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>
<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.