Introducing Thriple: A Library of 3D WPF Components

March 8, 2009

I recently published a new project on CodePlex called Thriple.  It contains 3D components that you can easily add to your WPF user interfaces.  As of version 1.0, Thriple contains my old Panel3D layout panel, and my new ContentControl3D.  I have put a lot of time and effort into making ContentControl3D a highly reusable, customizable control.  I’m very happy with how it turned out, but be sure to read the Known Issues section on Thriple’s Release page.

The source code download also contains sample applications that show the components in action.  If you want to check it out, here’s the link: http://thriple.codeplex.com/

kick it on DotNetKicks.com


Introducing ContentControl3D

February 23, 2009

A couple years ago, Ian Griffiths blogged about a way to create flippable list items in WPF.  His approach involves using a VisualBrush to display the 2D content in 3D space, because he implemented it before Viewport2DVisual3D was introduced in .NET 3.5.  Also, his approach was not very easy to reuse in many applications because the functionality was not placed into a custom control.  Tonight, I decided to remedy this by making use of Viewport2DVisual3D in a reusable control.

The code associated with this post is a working prototype.  I intend on turning this into something more complete, but want to share it with the world as soon as possible, hoping to get some feedback and feature requests early on.

I created a control that derives ContentControl, called ContentControl3D.  It allows you to assign the BackContent property to specify what should be shown after you first flip the control over.  The Content property, inherited from ContentControl, specifies what to display on the front side of the surface.  You can also assign the BackContentTemplate property a DataTemplate, if BackContent is set to a data object (instead of a visual element).

Here is a screenshot of the demo application when it first loads up:

front
After clicking the “Flip Over” button, the UI performs an animated rotation, leaving you with a view of the back side of the surface.  This is shown below…

back
Naturally, you can put whatever content you want on the front and back sides.

Here is the XAML which configures the ContentControl3D in the demo window:

xaml
If you would like to check this control out, you can download the source code here: ContentControl3D Source Code.  NOTE: Be sure to change the file extension from .DOC to .ZIP and then decompress the file.

Your feedback is welcome.  Thanks!


Updated Panel3D code and demos now available

May 20, 2008

I fixed Panel3D so that its child elements can be transparent.  The updated source code and demo applications are now available for download from the CodeProject article:

http://www.codeproject.com/KB/WPF/panel3d.aspx


Panel3D now supports transparency

May 10, 2008

Not too long ago I created a WPF panel that lays out its child elements in 3D space, called Panel3D. When playing around with it, I never could figure out a way to make the 3D models in the panel support transparency, such that you could see models lower in the z-order “through” models higher in the z-order. The models higher in the z-order (i.e. those appearing closer to the viewer) were always opaque, thus covering up models behind them.

Someone left a comment on that article, asking how to create semi-transparent items in Panel3D. I didn’t know the answer, but luckily someone else did. It turns out that I was adding the 3D models to the Viewport3D’s Children collection in the wrong order. Panel3D was putting the front-most model at the beginning of the Children collection (technically, the scene’s light source is the very first child). The index of a model in the Children collection matched its visible index, meaning that the element furthest away from the viewer was the last child in the Viewport3D. This was completely wrong!

It turns out that transparency of 3D models in a Viewport3D is a little more tricky than working with transparency of 2D elements living in a 2D world. For transparency to work correctly in a Viewport3D, you must add the models into the Children collection in the opposite order than which we see them (relative to the scene’s camera). If you want to learn more about this issue, go to this blog post, which explains the issue quite well. Unfortunately, the utility method offered in that post does not work in Panel3D.

I modified Panel3D so that it arranges the models in the correct order. The updated source code is not yet available, since I want to give it some time to marinate in my head before I revise the CodeProject article. I did, however, update the WPF Disciples Blog Viewer 3D (with audio) application so that it takes advantage of this new feature.

Download the app here: WPF Disciples Blog Viewer 3D (with audio!)

NOTE: Be sure to change the file extension from .DOC to .ZIP and then decompress it.

Here is a “before” picture, of what the app used to look like (click to view full size image):

Here is the “after” picture, showing how the transparency looks:

I also added two new dependency properties to Panel3D.

AllowTransparency must be set to true if you want the models to be “truly” transparent. If you leave it to false, the old behavior is honored, where the items become more “dim” when their opacity is lowered. The new WPF Disciples Blog Viewer 3D app, seen above, sets this to true, which is why you can see through the items.

AutoAdjustOpacity can be set to false if you do not want Panel3D to automatically set the opacity of each element displayed in the scene. The new WPF Disciples Blog Viewer 3D app, seen above, sets this to false, which is why the items do not seem to fade away as they move into the distance.

I will release the new source code and update the CodeProject article soon…I promise! 😀


WPF Disciples 3D Blogroll…with Audio!

April 10, 2008

Last night my brother introduced me to SoundSnap.com, and I decided to add some audio clips to the WPF Disciples blogroll viewer app. This is just too much fun! 🙂

The app now has two tracks running in the background: the sound of the ocean and some nice calm music. When you move items in the Panel3D, it plays a subtle sound that makes it feel like something physical is happening. Also, when you open a blogger’s bio or blog, it plays a sound that represents a Web browser being opened. I spent a while picking out the right sounds, and adjusting the volume levels so that they are not tacky. Hopefully my tastes are good!

The one interesting part about how this works is the way that the sound plays when you move items in the panel. Here is the way I achieved that in XAML:

That snippet takes advantage of the fact that Panel3D has an IsItemsMoving dependency property that is set to true when you call MoveItems() and is set to false when the call completes later on. For this trick to work, the MediaElement’s DataContext must be set to the Panel3D instance so that it can bind to the panel correctly.

If my audio files were .WAV files, instead of .MP3, I could have used the SoundPlayerAction instead of this tricky approach.

Here is a video showing this app in action, in case you do not have Visual Studio 2008 or .NET Framework 3.5 installed:

Download the source code here: WPF Disciples 3D Blogroll Viewer with Audio (source code)

Download the executable here: WPF Disciples 3D Blogroll Viewer with Audio (binaries)

NOTE: Be sure to change the file extension from .DOC to .ZIP and then decompress the file. This is a workaround for a limitation imposed by WordPress.


Article about Panel3D

April 7, 2008

I just published an article to CodeProject showing my new Panel3D class.  The article is accompanied by a fairly interesting demo application that makes it easy to find appealing configurations for the panel’s 3D scene.  If you are interested, here is the link:

http://www.codeproject.com/KB/WPF/panel3d.aspx


Dr. WPF introduces Conceptual Children

April 7, 2008

Dr. WPF is amazingly brilliant. He figured out a way to create a panel whose children are neither visual or logical children, but simply “conceptual” children. This allows for many great things, including the ability to host the child elements in 3D space. His excellent article about the topic, with source code, can be found here.

I have been working closely with the good Doctor over the past week. His conceptual panel work has been the foundation of my new developments in displaying the items of a 2D ListBox as interactive, animated 3D objects. I will be writing about this exciting topic soon, but for now, just to whet your appetite…


Interactive Animated 2D Elements in a 3D ItemsControl

April 1, 2008
EDIT: After posting this entry, I published an article on CodeProject that shows a more robust and complete solution than the one shown here. You can view that article here.

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 post, I take that example a step further and show how to make those 2D elements respond to user input while in 3D space. The demo application is a 3D blogroll for members of the WPF Disciples group. It looks like this:

WPF Disciples 3D Blogroll (Screenshot)

(click on the image to see it at full size)

Each item in the list represents a blogger from WPF Disciples who has a bio on the group’s blog. If you click on the person’s name, a Web browser opens to that person’s bio. If you click on the blogger’s picture, it opens a browser to that person’s blog. Click on the buttons below to navigate between bloggers. Holding a navigation button down will continuously scroll through the items.

I tried to use a Viewport2DVisual3D in my original 3D ItemsControl project,so that the user could interact with the list’s items. However, there was a problem. In order to a host a 2D element in a Viewport2DVisual3D it must be parented to it, by setting the Visual property to the 2D element. Since my Panel3D is being used as an ItemsControl’s ItemsPanel, it cannot add or remove child elements. WPF enforces that rule at run time, by throwing an exception after you try to remove an element from the Panel’s Children collection. A child element of an items panel cannot be parented to another element, but Viewport2DVisual3D must be the visual parent of a 2D element in order to host it in 3D space.

The panel has children that it cannot remove but it must somehow render them in 3D space. The solution I originally used was to create a 3D mesh painted with a VisualBrush that references the panel’s child element. That technique prevented the 2D elements from responding to user input, since they were not really in the 3D scene. It just looked like they were in the 3D scene.

After much experimentation and discussion with other WPF Disciples, I finally found a way around this barrier. I figured out a way to dynamically generate a ContentPresenter such that it renders the content exactly how a ContentPresenter generated by the ItemsControl renders it. Here is that magic method:

WPF Disciples 3D Blogroll (CreateContentPresenter)

I had to jump through some hoops to make the ContentPresenter use the correct DataTemplate for its ContentTemplate property. What is even stranger is the fact that if it uses a typed DataTemplate, it must be declared in XAML with the explicit notation for the TypeExtension. For example, you must configure the typed DataTemplate with DataType=”{x:Type TypeName}” instead of the more convenient DataType=”TypeName“. Smells like a bug to me…

Here is the method that creates a Viewport2DVisual3D and calls the method seen above to create a 2D element:

WPF Disciples 3D Blogroll (Build 3D Model)

You can download this project’s source code here: WPF Disciples 3D Blogroll (Source Code) NOTE: Be sure to change the file extension from .DOC to .ZIP and then decompress the file.


Animating Images in a 3D ItemsControl

March 30, 2008

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:

ImageViewer3D (Before)

Now here is the same ItemsControl using my 3D panel :

ImageViewer3D (After)

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:

ImageViewer3D (ItemsControl using Panel3D)

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:

ImageViewer3D (Panel3D 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:

ImageViewer3D (Viewport3D Scene XAML)

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:

ImageViewer3D (The Bridge Between 2D and 3D)

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:

ImageViewer3D (Panel3D Model Creation)

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.