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.


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.