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>
Related
We use vector icons exported from Expression Design in our application, but I just noticed that all empty space in the icons gets trimmed away when they are displayed inside a stretched Image. Since the whole point of having vector icons is to allow them to stretch and scale nicely, this seems very strange.
Here is an example. Both the red and the blue star are designed in a 32 pixels wide document, but the blue star is much smaller. Setting the stretch property to Uniform suddenly makes the two icons the same size.
Is it possible to solve this and keep the whitespace around the icons? I guess a possible workaround would be to add a transparent background rectangle that covers the whole icon area, but this seems like a bad solution to me.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="GeneralTest.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Window.Resources>
<DrawingImage x:Key="small_blue_star">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Blue" Geometry="F1 M 20.4989,22C 20.4634,22.0177 16.2771,19.0022 16.2416,19.0022C 16.2061,19.0022 12.0021,22.0177 11.9844,22C 11.9489,21.9823 13.4921,17.0332 13.4744,16.9977C 13.4744,16.9623 9.4655,14.0354 9.48323,13.9999C 9.48323,13.9644 14.45,14.0177 14.4855,13.9999C 14.5032,13.9822 16.2061,8.99765 16.2416,8.99765C 16.2771,8.99765 17.9623,13.9822 17.98,13.9999C 18.0155,14.0177 22.9823,13.9644 23,13.9999C 23,14.0354 18.9911,16.9623 18.9911,16.9977C 18.9734,17.0332 20.5166,21.9823 20.4989,22 Z "/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="big_red_star">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Red" Geometry="F1 M 26.0781,32C 25.9941,32.0436 16.0823,24.6277 15.9983,24.6277C 15.9143,24.6277 5.96055,32.0436 5.91855,32C 5.83455,31.9564 9.48848,19.7856 9.44648,19.6983C 9.44648,19.6111 -0.0453207,12.4133 -0.00332647,12.326C -0.00332647,12.2388 11.7564,12.3697 11.8404,12.326C 11.8824,12.2824 15.9143,0.0243702 15.9983,0.0243702C 16.0823,0.0243702 20.0723,12.2824 20.1142,12.326C 20.1982,12.3697 31.958,12.2388 32,12.326C 32,12.4133 22.5082,19.6111 22.5082,19.6983C 22.4662,19.7856 26.1201,31.9564 26.0781,32 Z "/>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Window.Resources>
<StackPanel x:Name="LayoutRoot">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Stretch=None" Width="100"/>
<Image Source="{StaticResource big_red_star}" Width="32" Stretch="None"/>
<Image Source="{StaticResource small_blue_star}" Width="32" Stretch="None"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Stretch=Uniform" Width="100"/>
<Image Source="{StaticResource big_red_star}" Width="32" Stretch="Uniform" />
<Image Source="{StaticResource small_blue_star}" Width="32" Stretch="Uniform"/>
</StackPanel>
</StackPanel>
</Window>
I'm using the chart control from the WPF Toolkit. How can I set the interval of the X axis?
I have the following XAML code:
<Grid Height="800">
<chartingToolkit:Chart Name="lineChart" Title="Pressure over Time"
VerticalAlignment="Top" Margin="20,50,20,0" Height="500">
<chartingToolkit:Chart.Axes>
<chartingToolkit:LinearAxis Title="Pressure" Orientation="Y" Interval="100" />
<chartingToolkit:LinearAxis Title="Time" Orientation="X" Interval="100" />
</chartingToolkit:Chart.Axes>
<chartingToolkit:LineSeries DependentValuePath="Value" IndependentValuePath="Key" ItemsSource="{Binding}" Name="Test"
IsSelectionEnabled="True" ClipToBounds="False">
</chartingToolkit:LineSeries>
</chartingToolkit:Chart>
<Button Width="100" Height="24" Margin="20,556,1058,220" Content="More" Name="Button1" />
</Grid>
The Y Axis works fine, it shows the interval of 100 but the X axis puts itself on the top (please see the added image) and the interval is the exact amounts of points. Why doesnt it listen to the Interval="100" property in the xaml? And why doesn't it place itself on the bottom?
For the location of the linearAxis, you can set the Location property to "Bottom"
in code:
<chartingToolkit:LinearAxis Title="Time" Orientation="X" Interval="100"
Location="Bottom" />
For the interval problem, i don't know...
<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.
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/
I'm wondering if anyone knows if it's possible in XAML to have a ListBox whose DataTemplate defines the ListBoxItem as a 3d element. Something along the lines of:
<ListBox x:Name="lst3D" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Viewport3D>
<Viewport2DVisual3D>
<Viewport2DVisual3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Angle="40" Axis="0, 1, 0" />
</RotateTransform3D.Rotation>
</RotateTransform3D>
</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="AliceBlue"/>
</Viewport2DVisual3D.Material>
<Label>Hello, 3D</Label> // we'd like to databind controls like this one
</Viewport2DVisual3D>
</Viewport3D>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBoxItem />
<ListBoxItem />
<ListBoxItem />
</ListBox>
Anyone seen this sort of thing done/have any advice?
Greatly appreciated,
bv
Replace the button with a content control such as,
<ContentControl Content="{Binding}" />
It also looks like the Viewpord3D doesn't request layout space so I needed to wrap it in a <Grid Height="100" Width="100">...</Grid> to see anything.
There's a couple of ways to do this.
You can change the DataTemplate to a ControlTemplate, and have it apply to all the items in the ListBox. But you cannot bind it to a specific data type.
The other option is move the DataTemplate to a resources section, and set the DataType to the type of the item you wish to display. Then you can use binding to bind to a property of the item etc.