This blog post shows a simple application in which we create a custom 3D panel that hosts some images in an ItemsControl. That panel displays a Viewport3D in its adorner layer and manages the relationship between the ItemsControl’s 2D visuals and their corresponding 3D visuals. Once all that is in place, we see how to animate the items in 3D space to create some very snazzy effects.
Every once in a while life throws you a bone. I woke up on this fine Sunday morning to discover that my good buddy, Sacha Barber, was looking for some help to fix a very strange bug. I did not know quite what his app was supposed to do, but he was displaying some images in a custom 3D panel and the images were not showing up when added from the code-behind.
I never did quite figure out how to fix that bug. However, while looking it over, my imagination fired up and I started creating a new project that was inspired by Sacha’s work. I decided to host an ItemsControl’s items in a custom panel (by setting its ItemsPanel property) and then display a Viewport3D in the panel’s adorner layer to achieve 3D visualizations of a 2D list of elements! Luckily, Sacha was cool with me writing a blog post about this exciting topic before he publishes his larger project. Thanks Sacha!!
In a nutshell, here is an ItemsControl full of images without using my custom 3D panel:
Now here is the same ItemsControl using my 3D panel :
What you cannot see in the screenshot above is that the images move to the back or front of the list along an animated path. The demo app moves the items at a regular interval, so it looks very cool. 😀
Here is the XAML for the ItemsControl in the demo app’s Window:
The main point of interest here is the fact that the ItemsPanel property is set to a template that generates an instance of my Panel3D class. That panel hosts a Viewport3D in its adorner layer, enabling it to render a 3D scene “on top of itself,” so to speak. Panel3D configures the Viewport3D in its constructor:
Panel3DAdorner simply hosts a Viewport3D within a DockPanel, whose Background is set to White. Having an opaque parent element enables it to effectively hide the panel underneath it, so that all you see is the 3D scene. Here is the XAML used to configure the Viewport3D:
The trick behind all of this is how we map a 2D visual, provided by the ItemsControl, to a 3D visual displayed by a Viewport3D in the adorner layer. That logic exists in Panel3D’s OnVisualChildrenChanged method override, as seen below:
When that method needs a 3D model built for a 2D element, it calls the Build3DModel method. The technique used here (which I took from Sacha’s code) is to paint a DiffuseMaterial with a VisualBrush whose Visual property references the 2D object in the panel. The GeometryModel3D contained by the ModelVisual3D then displays that DiffuseMaterial. You can see that method below:
I won’t get into how the animations work because it is quite a bit of not-so-interesting code. The basic idea is that when the Panel3D is asked to move its items it animates the TranslateTransform3D and Opacity of each 3D object in the scene. The logic uses a little trick to figure out where to move each item and what opacity level it should have, but I leave that code as a challenge for the reader to decrypt. The code related to moving the items can be found in the MoveItems method of Panel3D, if you’re interested.
Download the Visual Studio 2008 source code here: ImageViewer3D (Source Code) NOTE: Please be sure to rename the file extension from .DOC to .ZIP and then decompress the file. This is a necessary workaround for a limitation imposed by WordPress.
Great stuff… I love this 😀
Thanks for sharing this dude
Glad my original code inspires this blog. I think we both got something out of it, for example I got the Adorner layer fromm you, and you got this blog entry.
Thanks for your help
This may be the coolest integration of 3D with 2D that I’ve seen yet in WPF! Yes, even cooler than the Viewport2DVisual3D hack (er… I mean… “solution”). Major Kudos to you and Sacha for thinking outside the box. 😀
Sacha, your initial idea of creating a 3D panel was awesome! I just took that in my own direction and ran with it. Kudos to you!!
Thanks, Dr. WPF! I think this core idea can be expanded to open up a whole new way of doing data visualiation in WPF. Imagine if I replaced the ItemsControl with a ListBox and added selection capabilities in the 3D scene… I’ll be working on that in my free time! 😀
Haha…like it. Hope you get the 3D listbox working that will be cool.
Like I say I think we both benifited from this. Your idea is not what I wanted to do, and still isnt what I was after, so thats cool. 2 good ideas for the price of one.
And like I also said, I really like the Adorner idea, I didnt think of that….So I am happy too.
Thanks for your help champ.
Bring on the 3d listbox, you should have a look at the new 3d Elements
They may make your life a lot easier.
Thanks Sacha. 🙂
[…] WPF Disciples in 3D 31 03 2008 Welcome to the blog of the WPF Disciples group! This is the first post to our group’s blog. Recently, Josh Smith posted on his blog about an application that displays the items of an ItemsControl in a 3D panel. You can check it out here. […]
3d huh, if only there was some practical application for it… ; p
Haha. What a pipedream, Jonah. 🙂
[…] Animating Images in a 3D ItemsControl – Creating a custom 3D panel Understanding Routed Commands – This one blew my mind a little bit. It’s still a good read even if you don’t know what the f- you’re doing, like me. […]
[…] Animated 2D Elements in a 3D ItemsControl A few posts back I showed how to apply a custom 3D panel to an ItemsControl, so that its items render in a Viewport3D contained in the panel’s adorner layer. In this […]
Nice one Josh. One question though – is the lady in the pictures one of the WPF posse?:D If so, count me in.
😉 we wish!
Cool..looks similar to ElementFlow: http://blog.pixelingene.com/?p=145
Thank you for your website 😉
I made with photoshop backgrounds for myspace or youtube and even more
Hope you had a good day and thank you again!