<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>WPF3D Team Blog : 3D</title><link>http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx</link><description>Tags: 3D</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>What's New in Graphics for 4.0 Beta 2</title><link>http://blogs.msdn.com/wpf3d/archive/2009/10/20/what-s-new-in-graphics-for-4-0-beta-2.aspx</link><pubDate>Wed, 21 Oct 2009 01:26:24 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9910288</guid><dc:creator>wpf3d</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/9910288.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=9910288</wfw:commentRss><description>&lt;p&gt;Last beta &lt;a href="http://blogs.msdn.com/wpf3d/archive/2009/06/24/what-s-new-in-graphics-for-4-0-beta-1.aspx"&gt;I mentioned&lt;/a&gt; we were saving the best for Beta 2 so thank you for waiting :)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;New Features&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The PixelShader class now accepts Pixel Shader 3.0 shaders when your hardware supports them. &lt;strong&gt;Important&lt;/strong&gt;: There is no software rendering for PS 3.0. For example, you won't see PS 3.0 Effects over Remote Desktop, when printing, in RenderTargetBitmap, etc...&lt;/li&gt;    &lt;li&gt;You can now tell us to cache the render output of an element tree in memory using what we've been calling the &amp;quot;cached composition&amp;quot; feature. The APIs for this feature are &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.uielement.cachemode(VS.100).aspx"&gt;UIElement.CacheMode&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.media.bitmapcachebrush(VS.100).aspx"&gt;BitmapCacheBrush&lt;/a&gt;. Think of this as hardware RenderTargetBitmap but without the BitmapSource APIs. Cached composition is more efficient than VisualBrush and allows you to specify a scale to render at if you know you'll be zooming. We'll have to write about this more later. &lt;/li&gt;    &lt;li&gt;Brand new text rendering and layout. One of the biggest complaints about WPF has been small text &amp;quot;clarity&amp;quot; so we added &amp;quot;Display&amp;quot; mode text rendering which snaps to the pixel grid and looks just like the GDI rendering the rest of Windows uses. Rendering of East Asian fonts that have embedded bitmaps has also improved. &lt;a href="http://blogs.msdn.com/text/archive/2009/08/24/wpf-4-0-text-stack-improvements.aspx"&gt;All of the details&lt;/a&gt; are over at the WPF Text blog. You should be able to notice a big difference over Beta 1 in Visual Studio 2010.&lt;/li&gt;    &lt;li&gt;My team didn't do this, but it helps us out quite a bit. WPF layout can position elements on sub-pixel boundaries which causes blurry bitmaps or seams. There have been specific workarounds for these things but no general fix. Now you can set &lt;a href="http://blogs.msdn.com/text/archive/2009/08/27/layout-rounding.aspx"&gt;layout rounding&lt;/a&gt; on the element tree root and walk away.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;Some Notable Bug Fixes&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;We've fixed most of our D3D9D.dll issues. If you're on XP SP3 &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=b66e14b8-8505-4b17-bf80-edb2df5abad4&amp;amp;displaylang=en#issues"&gt;you'll still hit a problem&lt;/a&gt; that's out of our control. To workaround that or any other issue, you can copy d3d9d.dll to the exe folder, rename it to d3d9.dll, and check the &amp;quot;break on error&amp;quot; box in the control panel as usual but &lt;strong&gt;do not&lt;/strong&gt; enable d3d9d.dll globally. Or you can use the checked D3D9.dll as mentioned in the release notes I just linked to. &lt;/li&gt;    &lt;li&gt;Fixed all known D3DImage device lost and timing bugs. If you find more, let us know ASAP. &lt;/li&gt;    &lt;li&gt;ColorContext should finally work in all scenarios! It can still throw exceptions when the embedded ColorContext is bad. I believe we shipped Beta 2 with some backwards compat exception issues that have been fixed for final release. &lt;/li&gt;    &lt;li&gt;WriteableBitmap was not respecting dirty rect size. If your dirty region is small compared to the size of the entire WriteableBitmap, you will see CPU improvement.&lt;/li&gt;    &lt;li&gt;&lt;em&gt;Minor&lt;/em&gt; 3D performance improvements. We reduced the amount of DrawPrimitive() calls for large indexed meshes and slightly improved CPU usage for large Model3D counts.&lt;/li&gt;    &lt;li&gt;We reduced the amount of GC.Collect(2) calls caused by bitmap allocations &lt;/li&gt;    &lt;li&gt;The render thread no longer dies when you create &amp;quot;32 / number of monitors&amp;quot; WPF AppDomains.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;strong&gt;A Notable Bug&lt;/strong&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Remember how &lt;a href="http://blogs.msdn.com/wpf3d/archive/2009/06/24/what-s-new-in-graphics-for-4-0-beta-1.aspx"&gt;I said&lt;/a&gt; we disabled hardware rendering if you didn't have PS 2.0? Well, that wasn't true. We thought we did but there was a bug and it's in Beta 2 as well. It'll be true for the final release.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It's also worth mentioning that &lt;a href="http://blogs.msdn.com/jgoldb/archive/2009/10/19/what-s-new-in-net-framework-4-client-profile-beta-2.aspx"&gt;.NET Framework 4.0 setup size has shrunk dramatically&lt;/a&gt;. The full x86 installer is down to ~38MB and the new &amp;quot;client&amp;quot; installer down to ~31MB. Full 3.5 SP1 is 231MB!&lt;/p&gt;  &lt;p&gt;-- Jordan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9910288" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/4.0+Beta+2/default.aspx">4.0 Beta 2</category></item><item><title>WPF3D Lighting and Shading</title><link>http://blogs.msdn.com/wpf3d/archive/2009/06/29/wpf3d-lighting-and-shading.aspx</link><pubDate>Tue, 30 Jun 2009 04:54:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9809090</guid><dc:creator>wpf3d</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/9809090.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=9809090</wfw:commentRss><description>&lt;p&gt;We use the standard fixed-function &lt;a href="http://en.wikipedia.org/wiki/Blinn-Phong_shading_model"&gt;Blinn-Phong model&lt;/a&gt;. You can read up on all of the equations &lt;a href="http://msdn.microsoft.com/en-us/library/bb147178(VS.85).aspx"&gt;here&lt;/a&gt; at MSDN.&lt;/p&gt;  &lt;p&gt;If you have a Tier 2 card, we actually do our lighting in a vertex shader. If you don’t have a Tier 2 card, we do the lighting on the CPU. Why not just use D3D9’s fixed-function APIs you might ask? We wanted to be able to blend a texture (SpecularMaterial.Brush) only with the specular component and it turns out the D3D9 fixed-function APIs can’t do that.&lt;/p&gt;  &lt;p&gt;An important thing to know is all Material Brushes are treated as textures even though they might not be implemented as such (e.g. SolidColorBrush). This means if the amount of light hitting a vertex is more than 1.0, it will be capped at 1.0 before being blended with the texture. This is an unfortunate behavior of the fixed function pipeline. I discussed this more in the &lt;a href="http://blogs.msdn.com/wpf3d/archive/2006/12/08/material-color-knobs.aspx"&gt;color knobs post&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;There is one thing that may be unique to out lighting model. Since we are a retained system, we factor in a Light’s transform to all of its properties. We approximate the scale being applied to the light by taking the cube root of the absolute value of the determinant of the upper 3x3 part of the Light’s transform. For a uniform scale this will be the actual scale but for non-uniform it’s good enough (the real solution is too costly for something uncommon). Internally, this number is factored into the range and attenuation values so things make sense. For example, if the Light undergoes a uniform scale of 2.0, we’ll multiple its range by 2.0.&lt;/p&gt;  &lt;p&gt;-- Jordan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9809090" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Materials/default.aspx">Materials</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Lighting/default.aspx">Lighting</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Shading/default.aspx">Shading</category></item><item><title>Transparent DiffuseMaterials and Depth Sorting</title><link>http://blogs.msdn.com/wpf3d/archive/2009/06/18/transparent-diffusematerials-and-depth-sorting.aspx</link><pubDate>Fri, 19 Jun 2009 04:28:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9778262</guid><dc:creator>wpf3d</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/9778262.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=9778262</wfw:commentRss><description>&lt;p&gt;I &lt;a href="http://blogs.msdn.com/wpf3d/archive/2007/03/08/material-behavior.aspx"&gt;hinted at this a long time ago&lt;/a&gt; and then forgot to follow up, whoops! &lt;/p&gt;  &lt;p&gt;As the old post says, DiffuseMaterial writes to the depth buffer. This means if you draw one diffuse model and then draw another diffuse model behind it, the card knows not to draw the second one on top of the first because the first is closer. The depth buffer only knows about position and has no concept of transparency so if the first model is transparent, you won’t see the second model behind it because the depth buffer rejected it as being behind the first.&lt;/p&gt;  &lt;p&gt;What does this mean? This means you have to sort your transparent DiffuseMaterials from back to front. If your scene is dynamic, you’ll have to do this any time the relationship between the transparent models and the camera changes. Peter gives an example of how to do this &lt;a href="http://blogs.msdn.com/pantal/archive/2007/07/23/sorting-for-wpf-3d-transparency.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;-- Jordan&lt;/p&gt;  &lt;p&gt;P.S. If you have a lot of overlapping models (a.k.a overdraw) you can sort your opaque models from front to back. This will prevent all of the obstructed models from being rasterized and will improve performance if rasterization is the bottleneck. If you have both opaque and transparent models, first draw the opaque ones then the transparent ones.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9778262" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Materials/default.aspx">Materials</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Performance/default.aspx">Performance</category></item><item><title>3.5 SP1 Software 3D Leak Fix Available</title><link>http://blogs.msdn.com/wpf3d/archive/2009/06/08/3-5-sp1-software-3d-leak-fix-available.aspx</link><pubDate>Tue, 09 Jun 2009 01:34:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9710503</guid><dc:creator>wpf3d</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/9710503.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=9710503</wfw:commentRss><description>&lt;p&gt;In 3.5 SP1 it was really easy to leak memory when doing software 3D rendering involving a VisualBrush or DrawingBrush. We got this complaint many times online and in person. Unfortunately, there is no work around. It’s described in “Issue 2” from &lt;a href="http://support.microsoft.com/kb/967634/"&gt;this new Knowledge Base article&lt;/a&gt;. The fix should also be in 4.0 Beta 1. &lt;/p&gt;  &lt;p&gt;-- Jordan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9710503" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3.5+SP1/default.aspx">3.5 SP1</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/4.0+Beta+1/default.aspx">4.0 Beta 1</category></item><item><title>3D Hit Testing</title><link>http://blogs.msdn.com/wpf3d/archive/2009/05/18/3d-hit-testing.aspx</link><pubDate>Tue, 19 May 2009 04:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9626597</guid><dc:creator>wpf3d</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/9626597.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=9626597</wfw:commentRss><description>&lt;p&gt;How to do 3D hit testing has come up a bit recently in the forums but essentially it isn’t any different than 2D hit testing which is described on MSDN &lt;a href="http://msdn.microsoft.com/en-us/library/ms752097.aspx"&gt;here&lt;/a&gt;. You can either start with a 2D point on the Viewport3D or a 3D point on a Visual3D. &lt;/p&gt;  &lt;p&gt;Starting at the Viewport3D level is straightforward. Suppose you have a mouse down handler and you want it to hit test into 3D:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public void &lt;/span&gt;MouseHitTest(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;MouseButtonEventArgs &lt;/span&gt;args)
{
    &lt;span style="color: #2b91af"&gt;Point &lt;/span&gt;mousePos = args.GetPosition(viewport3d);
    &lt;span style="color: #2b91af"&gt;PointHitTestParameters &lt;/span&gt;hitParams = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PointHitTestParameters&lt;/span&gt;(mousePos);
    &lt;span style="color: #2b91af"&gt;VisualTreeHelper&lt;/span&gt;.HitTest(viewport3d, &lt;span style="color: blue"&gt;null&lt;/span&gt;, ResultCallback, hitParams);
}&lt;/pre&gt;

&lt;p&gt;Visual3D is slightly trickier because a point is no longer sufficient in 3D space. You also need to specify a direction. An origin point plus a direction is known as a &lt;em&gt;ray&lt;/em&gt;. It will look something like this:&lt;/p&gt;

&lt;pre class="code"&gt;    &lt;span style="color: #2b91af"&gt;RayHitTestParameters &lt;/span&gt;hitParams = 
        &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RayHitTestParameters&lt;/span&gt;(
            &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Point3D&lt;/span&gt;(0, 0, 0),
            &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Vector3D&lt;/span&gt;(1, 0, 0)
            );
    &lt;span style="color: #2b91af"&gt;VisualTreeHelper&lt;/span&gt;.HitTest(visual3d, &lt;span style="color: blue"&gt;null&lt;/span&gt;, ResultCallback, hitParams);&lt;/pre&gt;

&lt;p&gt;The only difference is the HitTestParameters.&lt;/p&gt;

&lt;p&gt;The second argument to HitTest is a filter which allows you to control which parts of the tree get tested. Skipping part of the tree is a perf win of course, but generally you’ll want to hit test everything and this is covered well in the MSDN article so I won’t do it here.&lt;/p&gt;

&lt;p&gt;The third argument, the result callback, is where the action happens. We’ve hit something and we’ve decided to tell you about it. It could be 3D or it could be 2D. It’s up to you to decide what you’re looking for and when/if you want to stop. &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HitTestResultBehavior &lt;/span&gt;ResultCallback(&lt;span style="color: #2b91af"&gt;HitTestResult &lt;/span&gt;result)
{
    &lt;span style="color: green"&gt;// Did we hit 3D?
    &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RayHitTestResult &lt;/span&gt;rayResult = result &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RayHitTestResult&lt;/span&gt;; 
    &lt;span style="color: blue"&gt;if &lt;/span&gt;(rayResult != &lt;span style="color: blue"&gt;null&lt;/span&gt;) 
    { 
        &lt;span style="color: green"&gt;// Did we hit a MeshGeometry3D?
        &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RayMeshGeometry3DHitTestResult &lt;/span&gt;rayMeshResult = 
            rayResult &lt;span style="color: blue"&gt;as &lt;/span&gt;&lt;span style="color: #2b91af"&gt;RayMeshGeometry3DHitTestResult&lt;/span&gt;;
                                                                                          
        &lt;span style="color: blue"&gt;if &lt;/span&gt;(rayMeshResult != &lt;span style="color: blue"&gt;null&lt;/span&gt;) 
        { 
            &lt;span style="color: green"&gt;// Yes we did!
        &lt;/span&gt;} 
    } 
    
    &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #2b91af"&gt;HitTestResultBehavior&lt;/span&gt;.Continue; 
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;RayMeshGeometry3DHitTestResult has MeshHit, PointHit, and DistanceToRayOrigin properties which tell you pretty much everything you want to know. It also has the triangle indices and weights (a.k.a. &lt;em&gt;barycentric coordinates&lt;/em&gt;) so you can do things like figure out the texture coordinate of the point hit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance Tip&lt;/strong&gt;: As you mouse over 3D we do hit testing behind your back because there could be interactive 2D on the 3D or a 2D layer underneath the 3D (empty Viewport3D space is considered transparent for hit testing purposes). If you know you don’t need either of those, disable hit testing on the Viewport3D by setting its IsHitTestVisible property to false. This is an old tip but a good one :)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sneaky Performance Tip&lt;/strong&gt;: Can’t disable hit testing and it’s still eating up a bunch of CPU? Override HitTestCore() and, while the mouse is moving, only &lt;em&gt;really&lt;/em&gt; issue the hit test every two or three (or more!) requests. This will introduce lag of course but that may be acceptable to your application.&lt;/p&gt;

&lt;p&gt;-- Jordan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9626597" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Hit+Testing/default.aspx">Hit Testing</category></item><item><title>Transforming Bounds</title><link>http://blogs.msdn.com/wpf3d/archive/2009/05/13/transforming-bounds.aspx</link><pubDate>Thu, 14 May 2009 01:25:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9611784</guid><dc:creator>wpf3d</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/9611784.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=9611784</wfw:commentRss><description>&lt;p&gt;Many haven’t realized this, but we added the ability to transform between 2D and 3D Visuals back in 3.5. This is handy if you need to draw 2D content around your 3D object or if you want to know the 2D position of a 3D point without doing a hit test. The methods are:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb763860.aspx"&gt;GeneralTransform3DTo2D Visual3D.TransformToAncestor(Visual ancestor)&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb763975.aspx"&gt;GeneralTransform2DTo3D Visual.TransformToAncestor(Visual3D ancestor)&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;(Note that Visual and Visual3D already had TransformToFoo methods to move up and down their own trees.)&lt;/p&gt;  &lt;p&gt;General transforms have a Transform method that operates on points and a TransformBounds method operates on rects for convenience. General transforms aren’t guaranteed to succeed so you need to be careful with them. &lt;/p&gt;  &lt;p&gt;I wrote a little 3D XAML scene that animates a torus in a Canvas and then added this code to place a blue rectangle around the torus:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;void &lt;/span&gt;CompositionTarget_Rendering(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;EventArgs &lt;/span&gt;e)
{
    &lt;span style="color: #2b91af"&gt;GeneralTransform3DTo2D &lt;/span&gt;gt = visual3d.TransformToAncestor(viewport3d);
    &lt;span style="color: green"&gt;// If null, the transform isn't possible at all
    &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(gt != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color: #2b91af"&gt;Rect &lt;/span&gt;bounds = gt.TransformBounds(&lt;span style="color: #2b91af"&gt;VisualTreeHelper&lt;/span&gt;.GetDescendantBounds(visual3d));
        &lt;span style="color: green"&gt;// If empty, visual3d's specific bounds couldn't be transformed
        &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(!bounds.IsEmpty)
        {
            rect.Width = bounds.Width;
            rect.Height = bounds.Height;
            &lt;span style="color: #2b91af"&gt;Canvas&lt;/span&gt;.SetLeft(rect, bounds.Left);
            &lt;span style="color: #2b91af"&gt;Canvas&lt;/span&gt;.SetTop(rect, bounds.Top);
        }
    }
}&lt;/pre&gt;

&lt;p&gt;And the result looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/TransformingBounds_D8F6/torusBounds_2.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="torusBounds" border="0" alt="torusBounds" src="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/TransformingBounds_D8F6/torusBounds_thumb.png" width="240" height="196" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The bounds you’ll get won’t necessarily be very tight, but they will always be inclusive.&lt;/p&gt;

&lt;p&gt;You’ll notice that there isn’t a Visual.TransformToDescendant(Visual3D descendant) and that’s because when going from 2D to 3D you get an infinite number of points along a ray. This is when you need to resort to hit testing and pick the specific point you want.&lt;/p&gt;

&lt;p&gt;-- Jordan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9611784" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Visual3D/default.aspx">Visual3D</category></item><item><title>D3DImage and Software Rendering</title><link>http://blogs.msdn.com/wpf3d/archive/2009/01/13/d3dimage-and-software-rendering.aspx</link><pubDate>Wed, 14 Jan 2009 05:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9317841</guid><dc:creator>wpf3d</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/9317841.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=9317841</wfw:commentRss><description>&lt;p&gt;If the WPF render thread is doing software rendering, &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.interop.d3dimage.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.windows.interop.d3dimage.aspx"&gt;D3DImage &lt;/a&gt;will not show up. I don't think we specifically called this out in the documentation so it can come as a surprise when you first encounter it. Off the top of my head, here are times when the render thread is in software:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.media.rendercapability.tier.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.windows.media.rendercapability.tier.aspx"&gt;RenderCapability.Tier&lt;/a&gt; == 0&lt;/li&gt;&lt;li&gt;You set &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.interop.hwndtarget.rendermode.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.windows.interop.hwndtarget.rendermode.aspx"&gt;HwndTarget.RenderMode&lt;/a&gt; = SoftwareOnly&lt;/li&gt;&lt;li&gt;A video card driver &lt;a href="http://msdn.microsoft.com/en-us/library/ms742196.aspx#other_resources" mce_href="http://msdn.microsoft.com/en-us/library/ms742196.aspx#other_resources"&gt;before November 2004&lt;/a&gt; (date subject to change in the future)&lt;br&gt;&lt;/li&gt;&lt;li&gt;Remote desktop&lt;/li&gt;&lt;li&gt;The window size is larger than the max texture size of the video card (rare)&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;All of these cases should be covered by simply checking #1 except for #2. You might be surprised by #4, but in 3.5 SP1 we had to change how remoting works. &lt;/p&gt;&lt;p&gt;You're probably thinking that I left out &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.rendertargetbitmap.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.rendertargetbitmap.aspx"&gt;RenderTargetBitmap&lt;/a&gt; and printing since they both use software rendering, but they happen on the UI thread! D3DImage will show up because they call &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.interop.d3dimage.copybackbuffer.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.windows.interop.d3dimage.copybackbuffer.aspx"&gt;CopyBackBuffer()&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;-- Jordan&lt;/p&gt;&lt;p&gt;P.S. Don't forget to read the &lt;a href="http://msdn.microsoft.com/en-us/library/cc656910.aspx" mce_href="http://msdn.microsoft.com/en-us/library/cc656910.aspx"&gt;perf notes&lt;/a&gt; when using D3DImage &lt;br&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9317841" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3.5+SP1/default.aspx">3.5 SP1</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/D3DImage/default.aspx">D3DImage</category></item><item><title>.NET 3.5 SP1 Graphics @ Channel 9</title><link>http://blogs.msdn.com/wpf3d/archive/2008/05/13/net-3-5-sp1-graphics-channel-9.aspx</link><pubDate>Wed, 14 May 2008 02:50:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8502219</guid><dc:creator>wpf3d</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/8502219.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=8502219</wfw:commentRss><description>&lt;P&gt;Sorry for the lack of updates, but we've been pretty busy. On what, you may ask? Our PM, David Teitlebaum, just &lt;A class="" href="http://channel9.msdn.com/Showpost.aspx?postid=403854" mce_href="http://channel9.msdn.com/Showpost.aspx?postid=403854"&gt;did a video on Channel 9&lt;/A&gt; showing off the new features. He starts by covering interactive 2D on 3D and improved layered window support, both of which were in 3.5, and he finishes with the customizable ImageEffects, the much improved WriteableBitmap, BitmapScalingMode.NearestNeighbor, and D3DImage.&lt;/P&gt;
&lt;P&gt;-- Jordan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8502219" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3.5/default.aspx">3.5</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3.5+SP1/default.aspx">3.5 SP1</category></item><item><title>Blender to XAML Exporter Updated</title><link>http://blogs.msdn.com/wpf3d/archive/2008/01/28/blender-to-xaml-exporter-updated.aspx</link><pubDate>Mon, 28 Jan 2008 22:56:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7292169</guid><dc:creator>wpf3d</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/7292169.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=7292169</wfw:commentRss><description>&lt;P&gt;&lt;A class="" href="http://www.therhogue.com/" mce_href="http://www.therhogue.com/"&gt;Robert Hogue&lt;/A&gt; has updated the Python script with a bunch of new features. See &lt;A class="" href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2749196&amp;amp;SiteID=1&amp;amp;mode=1" mce_href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2749196&amp;amp;SiteID=1&amp;amp;mode=1"&gt;this forum post&lt;/A&gt; for the instructions, tutorials, and demos!&lt;/P&gt;
&lt;P&gt;-- Jordan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7292169" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Tools/default.aspx">Tools</category></item><item><title>.NET 3.5 has been released!</title><link>http://blogs.msdn.com/wpf3d/archive/2007/11/20/net-3-5-has-been-released.aspx</link><pubDate>Wed, 21 Nov 2007 01:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6445866</guid><dc:creator>wpf3d</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/6445866.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=6445866</wfw:commentRss><description>&lt;P&gt;Yesterday, .NET Framework 3.5 and Visual Studio 2008 went live on MSDN. You can see what's new in both &lt;A class="" href="http://windowsclient.net/vstudio2008.aspx" mce_href="http://windowsclient.net/vstudio2008.aspx"&gt;here&lt;/A&gt;&amp;nbsp;and download them &lt;A class="" href="http://windowsclient.net/edownloads.aspx" mce_href="http://windowsclient.net/edownloads.aspx"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Since this is a graphics blog, here are the graphics-specific changes of note in 3.5:&lt;/P&gt;&lt;STRONG&gt;New Graphics Features&lt;/STRONG&gt; 
&lt;UL&gt;
&lt;LI&gt;UIElement3D 
&lt;LI&gt;Interactive 2D on 3D: Viewport2DVisual3D 
&lt;LI&gt;Transformation services on Visual3D 
&lt;LI&gt;BitmapSource.DecodeFailed event 
&lt;LI&gt;HwndTarget.RenderMode to enable software rendering per window 
&lt;LI&gt;BitmapImage.UriCachePolicy and BitmapDecoder.Create(..., RequestCachePolicy) to control web request caching&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Notable Graphics&amp;nbsp;Performance Improvements&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Less animation jitter&lt;/LI&gt;
&lt;LI&gt;RenderTargetBitmap memory leaks plugged&lt;/LI&gt;
&lt;LI&gt;Big layered window improvements when combined with &lt;A class="" href="http://support.microsoft.com/kb/938660" mce_href="http://support.microsoft.com/kb/938660"&gt;this&lt;/A&gt; on Vista or &lt;A class="" href="http://support.microsoft.com/kb/937106/" mce_href="http://support.microsoft.com/kb/937106/"&gt;this&lt;/A&gt; on XP&lt;/LI&gt;
&lt;LI&gt;MeshGeometry3D hit testing up to 50% faster in common scenarios&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;Notable Graphics&amp;nbsp;Bug Fixes&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Numerous layered window problems resolved&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Most of these changes will appear in 3.0 SP1 as well.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;-- Jordan&lt;/P&gt;&lt;/STRONG&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6445866" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3.5/default.aspx">3.5</category></item><item><title>Augmented Reality with WPF3D</title><link>http://blogs.msdn.com/wpf3d/archive/2007/10/15/augmented-reality-with-wpf3d.aspx</link><pubDate>Tue, 16 Oct 2007 02:57:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5465641</guid><dc:creator>wpf3d</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/5465641.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=5465641</wfw:commentRss><description>&lt;P&gt;&lt;A class="" href="http://en.wikipedia.org/wiki/Augmented_reality" mce_href="http://en.wikipedia.org/wiki/Augmented_reality"&gt;Augmented Reality&lt;/A&gt; is the process of taking real world data, typically video, and enhancing it with computer graphics. &lt;A class="" href="http://www.brains-n-brawn.com/default.aspx?vDir=wpfaugreal" mce_href="http://www.brains-n-brawn.com/default.aspx?vDir=wpfaugreal"&gt;Casey&lt;/A&gt; used WPF3D along with an AR toolkit and DirectShow to get some great results. &lt;A class="" href="http://www.youtube.com/watch?v=vPaXR24FP5g" mce_href="http://www.youtube.com/watch?v=vPaXR24FP5g"&gt;Check out the sweet video&lt;/A&gt;! &lt;/P&gt;
&lt;P&gt;-- Jordan&lt;/P&gt;
&lt;P&gt;P.S. We finally got around to putting some links on the side.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5465641" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Apps/default.aspx">Apps</category></item><item><title>Blender Exporter on CodePlex - Looking for volunteers...</title><link>http://blogs.msdn.com/wpf3d/archive/2007/09/30/blender-exporter-on-codeplex-looking-for-volunteers.aspx</link><pubDate>Sun, 30 Sep 2007 22:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5213659</guid><dc:creator>wpf3d</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/5213659.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=5213659</wfw:commentRss><description>&lt;P&gt;In July I promised to track down the Blender exporter that was lost during the GotDotNet phase out.&amp;nbsp; The last version of the export script is now hosted on CodePlex (&lt;A class="" href="http://codeplex.com/xamlexporter" mce_href="http://codeplex.com/xamlexporter"&gt;here&lt;/A&gt;).&amp;nbsp; I am embarrassed that it has taken me this long to do this, and even more so that the script is not up to date for the latest version of Blender.&lt;/P&gt;
&lt;P&gt;This has forced me to admit that it's time to&amp;nbsp;give someone else the opportunity to&amp;nbsp;take ownership of this project.&amp;nbsp; If you're interested, &lt;A class="" href="https://www.codeplex.com/UserAccount/ContactUser.aspx?ContactUser=Daniel" mce_href="https://www.codeplex.com/UserAccount/ContactUser.aspx?ContactUser=Daniel"&gt;contact me&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;- Daniel&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5213659" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Tools/default.aspx">Tools</category></item><item><title>Petzold.Media3D</title><link>http://blogs.msdn.com/wpf3d/archive/2007/09/07/petzold-media3d.aspx</link><pubDate>Sat, 08 Sep 2007 07:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4822276</guid><dc:creator>wpf3d</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/4822276.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=4822276</wfw:commentRss><description>&lt;P&gt;Charles Petzold has &lt;A class="" href="http://www.charlespetzold.com/3D/" mce_href="http://www.charlespetzold.com/3D/"&gt;posted his WPF3D library on the web.&lt;/A&gt;&amp;nbsp;It includes sphere, cube, cylinder, torus, line, and teapot mesh generation.&lt;/P&gt;
&lt;P&gt;Buying his book&amp;nbsp;&lt;EM&gt;3D Programming for Windows&lt;/EM&gt; grants you royalty-free use of the library so be sure to check it out!&lt;/P&gt;
&lt;P&gt;-- Jordan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4822276" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Books/default.aspx">Books</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Geometry/default.aspx">Geometry</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Apps/default.aspx">Apps</category></item><item><title>Cel Shading</title><link>http://blogs.msdn.com/wpf3d/archive/2007/09/07/cell-shading.aspx</link><pubDate>Sat, 08 Sep 2007 07:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4821848</guid><dc:creator>wpf3d</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/4821848.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=4821848</wfw:commentRss><description>&lt;P&gt;Charles Petzold has been experimenting with cel shading on &lt;A href="http://www.charlespetzold.com/blog/blog.xml" mce_href="http://www.charlespetzold.com/blog/blog.xml"&gt;his blog&lt;/A&gt; at the request of &lt;A href="http://chriscavanagh.wordpress.com/" mce_href="http://chriscavanagh.wordpress.com/"&gt;Chris Cavanagh&lt;/A&gt; (whom has updated his &lt;A href="http://chriscavanagh.wordpress.com/2007/05/26/minor-xbap-update/" mce_href="http://chriscavanagh.wordpress.com/2007/05/26/minor-xbap-update/"&gt;3D physics XBAP&lt;/A&gt; btw). Though we do use shaders internally, WPF3D's API is fixed function so you have to dig out the ol' fixed function playbook to achieve fancier effects. The plays usually boil down to abusing textures :)&lt;/P&gt;
&lt;P&gt;First, make a small, one dimensional texture containing the colors you want. Here are a couple of examples I've zoomed in on and highlighted the pixels to make things clearer. Why I'm using grayscale will make sense in a minute:&lt;/P&gt;
&lt;P align=center&gt;&lt;A href="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/big_strip_2.png" mce_href="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/big_strip_2.png"&gt;&lt;IMG id=id style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=16 alt=big_strip src="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/big_strip_thumb.png" width=156 border=0 mce_src="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/big_strip_thumb.png"&gt;&lt;/A&gt; &lt;BR&gt;&lt;A href="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/big_strip2_2.png" mce_href="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/big_strip2_2.png"&gt;&lt;IMG id=id style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=16 alt=big_strip2 src="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/big_strip2_thumb.png" width=156 border=0 mce_src="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/big_strip2_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P align=left&gt;Next, we need a function that maps to [0, 1] and takes into account the light position relative to a vertex. How about the cosine of the angle to the light? Turns out we can compute that fairly quickly because it's equal to the dot product of the normal and the vector to the light divided by their lengths. &lt;/P&gt;&lt;PRE class=code&gt;    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Int32Collection&lt;/SPAN&gt; idxs = mesh.TriangleIndices;
    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Point3DCollection&lt;/SPAN&gt; pts = mesh.Positions;
    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Vector3DCollection&lt;/SPAN&gt; nrms = mesh.Normals;
    &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;PointCollection&lt;/SPAN&gt; txs = mesh.TextureCoordinates;
    mesh.TextureCoordinates = &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;null&lt;/SPAN&gt;;
    &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;for&lt;/SPAN&gt; (&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;int&lt;/SPAN&gt; i = 0, count = idxs.Count; i &amp;lt; count; ++i)
    { 
        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;int&lt;/SPAN&gt; idx = idxs[i]; 
        &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Vector3D&lt;/SPAN&gt; toLight = lightPos - pts[idx]; 
        toLight.Normalize(); 

        &lt;SPAN style="COLOR: rgb(0,128,0)"&gt;// The normals are pre-normalized, no need to do it again &lt;/SPAN&gt; 
        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;double&lt;/SPAN&gt; dp = &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Vector3D&lt;/SPAN&gt;.DotProduct(toLight, nrms[idx]); 
        
        &lt;SPAN style="COLOR: rgb(0,128,0)"&gt;// A negative dot product means the vertex is facing away &lt;/SPAN&gt; 
        &lt;SPAN style="COLOR: rgb(0,128,0)"&gt;// from the light so let's set that to the darkest color &lt;/SPAN&gt; 
        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;if&lt;/SPAN&gt; (dp &amp;lt; 0) 
        { 
            dp = 0; 
        } 
        
        txs[idx] = &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Point&lt;/SPAN&gt;(dp, 0); 
    } 
    mesh.TextureCoordinates = txs;&lt;/PRE&gt;
&lt;P&gt;Naturally, you're going to need to redo this calculation any time the relationship between the light and the mesh changes so it needs to be fast. This is why I go through all of that collection nonsense (&lt;A href="http://blogs.msdn.com/timothyc/archive/2006/08/31/734308.aspx" mce_href="http://blogs.msdn.com/timothyc/archive/2006/08/31/734308.aspx"&gt;read this&lt;/A&gt;).&lt;/P&gt;
&lt;P&gt;So why did I use a grayscale texture? If I baked the color in, I'd have to make a new texture any time I wanted to change the color. Instead, I can use the &lt;A class="" href="http://blogs.msdn.com/wpf3d/archive/2006/12/08/material-color-knobs.aspx" mce_href="http://blogs.msdn.com/wpf3d/archive/2006/12/08/material-color-knobs.aspx"&gt;color knobs&lt;/A&gt; to set the color and use the grayscale texture like a mask. In these photos, I have a single AmbientLight with a DiffuseMaterial with AmbientColor="green" and Brush equal to the one dimensional texture. I don't actually have a real point light in the scene which helps performance.&lt;/P&gt;
&lt;P align=center&gt;&lt;IMG src="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/cellpot_6.png"&gt; &lt;IMG src="http://blogs.msdn.com/blogfiles/wpf3d/WindowsLiveWriter/CellShading_1204C/celltorus_4.png"&gt;&lt;/P&gt;
&lt;P&gt;Being that it's per-vertex, more vertices means a higher quality image and you're going to see some popping when it's animated. The teapot doesn't have too many vertices so the spout and black line on the body don't look great. On the highly tesselated torus, those issues are gone but it's still hard to get a clean, crisp edge because of the linear interpolation of the texture.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;-- Jordan&lt;/P&gt;
&lt;P&gt;P.S. If you use a texture with two colors and instead dot the normal with the direction to the camera, you'll get silhouette edges but they could look really bad because of the per-vertex nature again.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4821848" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Materials/default.aspx">Materials</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Lighting/default.aspx">Lighting</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Shading/default.aspx">Shading</category></item><item><title>Subclassing UIElement3D</title><link>http://blogs.msdn.com/wpf3d/archive/2007/09/05/subclassing-uielement3d.aspx</link><pubDate>Thu, 06 Sep 2007 04:20:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4775055</guid><dc:creator>wpf3d</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/4775055.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=4775055</wfw:commentRss><description>&lt;P&gt;Subclassing from UIElement3D to create your own elements that respond to input, focus and eventing is simple to do in 3.5.&amp;nbsp; In this example we'll create a Sphere class which derives from UIElement3D and will show off some new features in the process.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Deriving from UIElement3D&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The first step is to derive from UIElement3D:&lt;/P&gt;&lt;PRE class=code&gt;    &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt; : &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;UIElement3D
&lt;/SPAN&gt;    {&lt;/PRE&gt;&lt;PRE class=code&gt;    }&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;Even though UIElement3D is declared abstract, there aren't any abstract methods you need to override.&amp;nbsp; The above will compile -&amp;nbsp;it just won't do anything interesting.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Rendering a Sphere&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Although the above lets us derive from UIElement3D, we still don't have anything rendering to look like a sphere.&amp;nbsp; Before going in to how to render the sphere, first we're going to want to create a couple of dependency properties to control how the sphere looks.&amp;nbsp; These will be PhiDiv and ThetaDiv, to represent the number of slices to make in the horizontal and vertical directions respectively, as well as Radius, to represent the radius of the sphere.&amp;nbsp; The code for these is below:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: rgb(128,128,128)"&gt;        ///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,128,128)"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; The number of vertical slices to make on the sphere
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,128,128)"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;readonly&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyProperty&lt;/SPAN&gt; ThetaDivProperty =
            &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyProperty&lt;/SPAN&gt;.Register(&lt;SPAN style="COLOR: rgb(163,21,21)"&gt;"ThetaDiv"&lt;/SPAN&gt;,
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;int&lt;/SPAN&gt;),
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt;),
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;PropertyMetadata&lt;/SPAN&gt;(15, ThetaDivPropertyChanged));

        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;void&lt;/SPAN&gt; ThetaDivPropertyChanged(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyObject&lt;/SPAN&gt; d, &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyPropertyChangedEventArgs&lt;/SPAN&gt; e)
        {
            &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt; s = (&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt;)d;
            s.InvalidateModel();
        }

        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;int&lt;/SPAN&gt; ThetaDiv
        {
            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;get
&lt;/SPAN&gt;            {
                &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;return&lt;/SPAN&gt; (&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;int&lt;/SPAN&gt;)GetValue(ThetaDivProperty);
            }

            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;set
&lt;/SPAN&gt;            {
                SetValue(ThetaDivProperty, &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;value&lt;/SPAN&gt;);
            }
        }

        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,128,128)"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; The number of horizontal slices to make on the sphere
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,128,128)"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;readonly&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyProperty&lt;/SPAN&gt; PhiDivProperty =
            &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyProperty&lt;/SPAN&gt;.Register(&lt;SPAN style="COLOR: rgb(163,21,21)"&gt;"PhiDiv"&lt;/SPAN&gt;,
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;int&lt;/SPAN&gt;),
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt;),
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;PropertyMetadata&lt;/SPAN&gt;(15, PhiDivPropertyChanged));

        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;void&lt;/SPAN&gt; PhiDivPropertyChanged(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyObject&lt;/SPAN&gt; d, &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyPropertyChangedEventArgs&lt;/SPAN&gt; e)
        {
            &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt; s = (&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt;)d;
            s.InvalidateModel();
        }

        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;int&lt;/SPAN&gt; PhiDiv
        {
            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;get
&lt;/SPAN&gt;            {
                &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;return&lt;/SPAN&gt; (&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;int&lt;/SPAN&gt;)GetValue(PhiDivProperty);
            }

            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;set
&lt;/SPAN&gt;            {
                SetValue(PhiDivProperty, &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;value&lt;/SPAN&gt;);
            }
        }

        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,128,128)"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; The radius of the sphere
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,128,128)"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;readonly&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyProperty&lt;/SPAN&gt; RadiusProperty =
            &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyProperty&lt;/SPAN&gt;.Register(&lt;SPAN style="COLOR: rgb(163,21,21)"&gt;"Radius"&lt;/SPAN&gt;,
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;double&lt;/SPAN&gt;),
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt;),
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;PropertyMetadata&lt;/SPAN&gt;(1.0, RadiusPropertyChanged));

        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;void&lt;/SPAN&gt; RadiusPropertyChanged(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyObject&lt;/SPAN&gt; d, &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyPropertyChangedEventArgs&lt;/SPAN&gt; e)
        {
            &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt; s = (&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt;)d;
            s.InvalidateModel();
        }

        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;double&lt;/SPAN&gt; Radius
        {
            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;get
&lt;/SPAN&gt;            {
                &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;return&lt;/SPAN&gt; (&lt;SPAN style="COLOR: rgb(0,0,255)"&gt;double&lt;/SPAN&gt;)GetValue(RadiusProperty);
            }

            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;set
&lt;/SPAN&gt;            {
                SetValue(RadiusProperty, &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;value&lt;/SPAN&gt;);
            }
        }&lt;/PRE&gt;
&lt;P&gt;&lt;STRONG&gt;InvalidateModel, OnUpdateModel and &lt;STRONG&gt;Visual3DModel&lt;/STRONG&gt;&lt;/STRONG&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;The above should look like standard C# WPF code to create a few dependency properties, but the one new method that should look unfamiliar is the InvalidateModel call made whenever any of the above dependency properties changes.&amp;nbsp;InvalidateModel is similar to the InvalidateVisual method that exists for the 2D UIElement.&amp;nbsp; Calling InvalidateModel indicates that the 3D model representing the UIElement3D has changed and should be updated.&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;In&amp;nbsp;response to InvalidateModel, OnUpdateModel will be called to update the 3D model that represents the object. In this way, you can&amp;nbsp;make multiple changes to properties that affect the visual appearance of the UIElement3D and only make one final change to the model, rather than having to regenerate it each time a change is made.&amp;nbsp; For instance, say changes are made to ThetaDiv, PhiDiv, and Radius above.&amp;nbsp;&amp;nbsp;Rather than having to regenerate the model each time, InvalidateModel can be called each time a property changes, and then all of the changes can be dealt with when OnUpdateModel is called. Of course,&amp;nbsp;the model can also be changed in other places, but this provides one standard option to make the change.&lt;/P&gt;
&lt;P&gt;The last thing that hasn't been discussed is how to actually change the model.&amp;nbsp;In 3.5, Visual3D now exposes a protected CLR property Visual3DModel which represents the 3D model for the object.&amp;nbsp; This is the 3D equivalent to the render data of a 2D Visual.&amp;nbsp; To set what the visual representation for the Visual3D&amp;nbsp;is&amp;nbsp;then, it's necessary to set this property.&amp;nbsp; For instance, ModelUIElement3D's&amp;nbsp;Model property takes care of setting this. There is one subtle point about setting this property.&amp;nbsp; Just like render data, setting this property won't set up the links necessary for things such as data bindings to work.&amp;nbsp; To make this happen, you'll also want to have a dependency property for the&amp;nbsp;model itself.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The code for InvalidateModel is shown below, as well as the Model dependency property:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE class=code&gt;        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;protected&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;override&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;void&lt;/SPAN&gt; OnUpdateModel()
        {
            &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;GeometryModel3D&lt;/SPAN&gt; model = &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;GeometryModel3D&lt;/SPAN&gt;();

            model.Geometry = Tessellate(ThetaDiv, PhiDiv, Radius);
            model.Material = &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DiffuseMaterial&lt;/SPAN&gt;(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Brushes&lt;/SPAN&gt;.Blue);

            Model = model;
        }

        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,128,128)"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; The Model property for the sphere
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(128,128,128)"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(0,128,0)"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: rgb(128,128,128)"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;readonly&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyProperty&lt;/SPAN&gt; ModelProperty =
            &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyProperty&lt;/SPAN&gt;.Register(&lt;SPAN style="COLOR: rgb(163,21,21)"&gt;"Model"&lt;/SPAN&gt;,
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Model3D&lt;/SPAN&gt;),
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;typeof&lt;/SPAN&gt;(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt;),
                                        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;PropertyMetadata&lt;/SPAN&gt;(ModelPropertyChanged));

        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;void&lt;/SPAN&gt; ModelPropertyChanged(&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyObject&lt;/SPAN&gt; d, &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;DependencyPropertyChangedEventArgs&lt;/SPAN&gt; e)
        {
            &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt; s = (&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Sphere&lt;/SPAN&gt;)d;
            s.Visual3DModel = (&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Model3D&lt;/SPAN&gt;)e.NewValue;
        }

        &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Model3D&lt;/SPAN&gt; Model
        {
            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;get
&lt;/SPAN&gt;            {
                &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;return&lt;/SPAN&gt; (&lt;SPAN style="COLOR: rgb(43,145,175)"&gt;Model3D&lt;/SPAN&gt;)GetValue(ModelProperty);
            }

            &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;set
&lt;/SPAN&gt;            {
                SetValue(ModelProperty, &lt;SPAN style="COLOR: rgb(0,0,255)"&gt;value&lt;/SPAN&gt;);
            }
        }&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;Attached to this post you'll find a simple example app which has the full code to the above Sphere class.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4775055" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/wpf3d/attachment/4775055.ashx" length="60911" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/Geometry/default.aspx">Geometry</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/UIElement3D/default.aspx">UIElement3D</category><category domain="http://blogs.msdn.com/wpf3d/archive/tags/3.5/default.aspx">3.5</category></item></channel></rss>