<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">WPF3D Team Blog</title><subtitle type="html" /><id>http://blogs.msdn.com/wpf3d/atom.xml</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/default.aspx" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/wpf3d/atom.xml" /><generator uri="http://communityserver.org" version="2.1.61025.2">Community Server</generator><updated>2007-09-07T21:02:00Z</updated><entry><title>What's New in Graphics for 4.0 Beta 2</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2009/10/20/what-s-new-in-graphics-for-4-0-beta-2.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2009/10/20/what-s-new-in-graphics-for-4-0-beta-2.aspx</id><published>2009-10-21T01:26:24Z</published><updated>2009-10-21T01:26:24Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Performance" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Performance/default.aspx" /><category term="4.0 Beta 2" scheme="http://blogs.msdn.com/wpf3d/archive/tags/4.0+Beta+2/default.aspx" /></entry><entry><title>WPF3D Lighting and Shading</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2009/06/29/wpf3d-lighting-and-shading.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2009/06/29/wpf3d-lighting-and-shading.aspx</id><published>2009-06-30T04:54:00Z</published><updated>2009-06-30T04:54:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="Materials" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Materials/default.aspx" /><category term="Lighting" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Lighting/default.aspx" /><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Shading" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Shading/default.aspx" /></entry><entry><title>What’s New in Graphics for 4.0 Beta 1</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2009/06/24/what-s-new-in-graphics-for-4-0-beta-1.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2009/06/24/what-s-new-in-graphics-for-4-0-beta-1.aspx</id><published>2009-06-25T03:48:00Z</published><updated>2009-06-25T03:48:00Z</updated><content type="html">&lt;p&gt;.NET 4.0 Beta 1 was released a few weeks ago and there’s a lot to it that you can read about elsewhere so I thought I would just stick to what’s changed for WPF graphics. These are the biggest things of note:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.media.cleartypehint(VS.100).aspx"&gt;RenderOptions.ClearTypeHint&lt;/a&gt;: If WPF renders text into a potentially transparent surface (e.g. a layered window like a menu or popup) we use grayscale anti-aliasing instead of ClearType because if the transparent surface is blended with another transparent surface, the ClearType will get messed up. Now with ClearTypeHint you can tell us to use ClearType and we’ll trust you that things aren’t transparent. &lt;/li&gt;    &lt;li&gt;The BitmapEffect classes are now no-ops. They are still there so your apps will compile but don’t expect them to do anything. &lt;/li&gt;    &lt;li&gt;The default &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.media.bitmapscalingmode.aspx"&gt;RenderOptions.BitmapScalingMode&lt;/a&gt; (Unspecified) is now Linear instead of Fant. If you still want Fant, you can re-enable it. &lt;/li&gt;    &lt;li&gt;Pixel Shader 2.0 is now required for hardware acceleration. Yes, if your card was &lt;a href="http://msdn.microsoft.com/en-us/library/ms742196.aspx"&gt;Tier 1&lt;/a&gt; but did not have PS 2.0 it is now Tier 0. &lt;/li&gt;    &lt;li&gt;The memory leak that was easy to hit with software 3D has been fixed. &lt;a href="http://blogs.msdn.com/wpf3d/archive/2009/06/08/3-5-sp1-software-3d-leak-fix-available.aspx"&gt;I already mentioned this&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;A common VisualBrush.Visual disconnect crash has been fixed. It’s in the same KB article as the memory leak. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;That’s not much but that’s because we’ve been saving things for Beta 2. Stay tuned!&lt;/p&gt;  &lt;p&gt;-- Jordan&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9802640" width="1" height="1"&gt;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="4.0 Beta 1" scheme="http://blogs.msdn.com/wpf3d/archive/tags/4.0+Beta+1/default.aspx" /></entry><entry><title>Transparent DiffuseMaterials and Depth Sorting</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2009/06/18/transparent-diffusematerials-and-depth-sorting.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2009/06/18/transparent-diffusematerials-and-depth-sorting.aspx</id><published>2009-06-19T04:28:00Z</published><updated>2009-06-19T04:28:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="Materials" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Materials/default.aspx" /><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Performance" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Performance/default.aspx" /></entry><entry><title>3.5 SP1 Software 3D Leak Fix Available</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2009/06/08/3-5-sp1-software-3d-leak-fix-available.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2009/06/08/3-5-sp1-software-3d-leak-fix-available.aspx</id><published>2009-06-09T01:34:00Z</published><updated>2009-06-09T01:34:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Performance" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Performance/default.aspx" /><category term="3.5 SP1" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3.5+SP1/default.aspx" /><category term="4.0 Beta 1" scheme="http://blogs.msdn.com/wpf3d/archive/tags/4.0+Beta+1/default.aspx" /></entry><entry><title>3D Hit Testing</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2009/05/18/3d-hit-testing.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2009/05/18/3d-hit-testing.aspx</id><published>2009-05-19T04:22:00Z</published><updated>2009-05-19T04:22:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Performance" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Performance/default.aspx" /><category term="Hit Testing" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Hit+Testing/default.aspx" /></entry><entry><title>Transforming Bounds</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2009/05/13/transforming-bounds.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2009/05/13/transforming-bounds.aspx</id><published>2009-05-14T01:25:00Z</published><updated>2009-05-14T01:25:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Visual3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Visual3D/default.aspx" /></entry><entry><title>D3DImage and Software Rendering</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2009/01/13/d3dimage-and-software-rendering.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2009/01/13/d3dimage-and-software-rendering.aspx</id><published>2009-01-14T05:17:00Z</published><updated>2009-01-14T05:17:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="3.5 SP1" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3.5+SP1/default.aspx" /><category term="D3DImage" scheme="http://blogs.msdn.com/wpf3d/archive/tags/D3DImage/default.aspx" /></entry><entry><title>.NET 3.5 SP1 Graphics @ Channel 9</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2008/05/13/net-3-5-sp1-graphics-channel-9.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2008/05/13/net-3-5-sp1-graphics-channel-9.aspx</id><published>2008-05-14T02:50:00Z</published><updated>2008-05-14T02:50:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="3.5" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3.5/default.aspx" /><category term="3.5 SP1" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3.5+SP1/default.aspx" /></entry><entry><title>Blender to XAML Exporter Updated</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2008/01/28/blender-to-xaml-exporter-updated.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2008/01/28/blender-to-xaml-exporter-updated.aspx</id><published>2008-01-28T22:56:00Z</published><updated>2008-01-28T22:56:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Tools" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Tools/default.aspx" /></entry><entry><title>.NET 3.5 has been released!</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2007/11/20/net-3-5-has-been-released.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2007/11/20/net-3-5-has-been-released.aspx</id><published>2007-11-21T01:42:00Z</published><updated>2007-11-21T01:42:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="3.5" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3.5/default.aspx" /></entry><entry><title>Augmented Reality with WPF3D</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2007/10/15/augmented-reality-with-wpf3d.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2007/10/15/augmented-reality-with-wpf3d.aspx</id><published>2007-10-16T02:57:00Z</published><updated>2007-10-16T02:57:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Apps" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Apps/default.aspx" /></entry><entry><title>Blender Exporter on CodePlex - Looking for volunteers...</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2007/09/30/blender-exporter-on-codeplex-looking-for-volunteers.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2007/09/30/blender-exporter-on-codeplex-looking-for-volunteers.aspx</id><published>2007-09-30T22:59:00Z</published><updated>2007-09-30T22:59:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Tools" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Tools/default.aspx" /></entry><entry><title>Petzold.Media3D</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2007/09/07/petzold-media3d.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2007/09/07/petzold-media3d.aspx</id><published>2007-09-08T07:16:00Z</published><updated>2007-09-08T07:16:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Books" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Books/default.aspx" /><category term="Geometry" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Geometry/default.aspx" /><category term="Apps" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Apps/default.aspx" /></entry><entry><title>Cel Shading</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/wpf3d/archive/2007/09/07/cell-shading.aspx" /><id>http://blogs.msdn.com/wpf3d/archive/2007/09/07/cell-shading.aspx</id><published>2007-09-08T07:02:00Z</published><updated>2007-09-08T07:02:00Z</updated><content type="html">&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;</content><author><name>wpf3d</name><uri>http://blogs.msdn.com/members/wpf3d.aspx</uri></author><category term="Materials" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Materials/default.aspx" /><category term="Lighting" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Lighting/default.aspx" /><category term="3D" scheme="http://blogs.msdn.com/wpf3d/archive/tags/3D/default.aspx" /><category term="WPF" scheme="http://blogs.msdn.com/wpf3d/archive/tags/WPF/default.aspx" /><category term="Shading" scheme="http://blogs.msdn.com/wpf3d/archive/tags/Shading/default.aspx" /></entry></feed>