<?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 : Materials</title><link>http://blogs.msdn.com/wpf3d/archive/tags/Materials/default.aspx</link><description>Tags: Materials</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><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>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>Material Behavior</title><link>http://blogs.msdn.com/wpf3d/archive/2007/03/08/material-behavior.aspx</link><pubDate>Fri, 09 Mar 2007 03:37:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1841409</guid><dc:creator>wpf3d</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/1841409.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=1841409</wfw:commentRss><description>&lt;P&gt;What Material you choose will impact your GeometryModel3D in three ways:&lt;BR&gt;
&lt;OL&gt;
&lt;LI&gt;Lighting model 
&lt;LI&gt;Depth write 
&lt;LI&gt;Blend with the back buffer &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;The first one is straightforward since it's right in the name of the Material plus it's documented. The last two aren't obvious at all and this is probably the first you've heard of them.&lt;/P&gt;
&lt;CENTER&gt;
&lt;TABLE class="" width="50%"&gt;
&lt;TBODY&gt;
&lt;TR frame="below"&gt;
&lt;TD class=""&gt;&lt;B&gt;Type&lt;/B&gt;&lt;/TD&gt;
&lt;TD class=""&gt;&lt;B&gt;Depth Write&lt;/B&gt;&lt;/TD&gt;
&lt;TD class=""&gt;&lt;B&gt;Blend&lt;/B&gt;&lt;/TD&gt;
&lt;TR&gt;
&lt;TD class=""&gt;DiffuseMaterial&lt;/TD&gt;
&lt;TD class=""&gt;Yes&lt;/TD&gt;
&lt;TD class=""&gt;SrcOver: S&lt;SUB&gt;α&lt;/SUB&gt;S+(1-S&lt;SUB&gt;α&lt;/SUB&gt;)D 
&lt;TR&gt;
&lt;TD class=""&gt;"AmbientMaterial"&lt;/TD&gt;
&lt;TD class=""&gt;Yes&lt;/TD&gt;
&lt;TD class=""&gt;SrcOver: S&lt;SUB&gt;α&lt;/SUB&gt;S+(1-S&lt;SUB&gt;α&lt;/SUB&gt;)D 
&lt;TR&gt;
&lt;TD class=""&gt;EmissiveMaterial&lt;/TD&gt;
&lt;TD class=""&gt;No&lt;/TD&gt;
&lt;TD class=""&gt;Additive: S&lt;SUB&gt;α&lt;/SUB&gt;S+D 
&lt;TR&gt;
&lt;TD class=""&gt;SpecularMaterial&lt;/TD&gt;
&lt;TD class=""&gt;No&lt;/TD&gt;
&lt;TD class=""&gt;Additive: S&lt;SUB&gt;α&lt;/SUB&gt;S+D &lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/CENTER&gt;
&lt;P&gt;&lt;STRONG&gt;Depth write and the depth buffer&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;If you haven't heard of the depth buffer (a.k.a. the z buffer) before, it's essentially how the card keeps track of&amp;nbsp;the distance&amp;nbsp;to an object&amp;nbsp;from the camera per pixel. When a polygon is being rasterized at a pixel that has already been written to, do you keep the old value or take the new value? For opaque objects, you typically want the one closest to the camera to win because you won't be able to see the occluded one. This is what we tell the card to do&amp;nbsp;(for you D3D programmers out there, we use D3DCMP_LESSEQUAL).&lt;/P&gt;
&lt;P&gt;For example, say you draw a triangle with a DiffuseMaterial. If you then draw another triangle directly behind, it will be ignored in the area of overlap because the first triangle is in front of it. But if a polygon doesn't write to the depth buffer, then it's like the card doesn't know it's there. Say you draw a triangle with an EmissiveMaterial. If you then draw an overlapping triangle it doesn't matter if it's behind or in front -- the new triangle overwrites the old one because the card has no "record" of the old one.&lt;STRONG&gt;&amp;nbsp;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Can you think of why the depth buffer might cause problems with transparent objects in a dynamic scene? That's a topic for another post :)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Blend&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;In the equation&amp;nbsp;above, S means source (the GeometryModel3D you're drawing) and D means destination (what you've drawn to the back buffer already). From the equations you can make a few observations like a fully opaque DiffuseMaterial will never let you see what was previously written or even opaque additive Materials will&amp;nbsp;appear transparent because they don't block out what is already there.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Why are there different behaviors?&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;The behaviors came out of how we think most people use Materials. Just about every Model3D will contain a DiffuseMaterial and will want to write to the depth buffer. If you then want your Model3D to glow or shine, you throw in an EmissiveMaterial or SpecularMaterial. Since you already wrote the depth, you don't need to do it again in the emissive and specular passes. Furthermore, you don't want emissive and specular to subtract away from the diffuse layer you just put down. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Extra Tips&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;"AmbientMaterial" is in quotes because it doesn't exist but you can make a Material that only responds to ambient light. See my earlier &lt;A 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 post&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;If you'd like one of the additive&amp;nbsp;Materials to write depth, you can do so by putting them&amp;nbsp;in a MaterialGroup along with a transparent black DiffuseMaterial. That way the DiffuseMaterial doesn't affect&amp;nbsp;the color but does affect the depth buffer. You can put this "depth pass"&amp;nbsp;DiffuseMaterial before&amp;nbsp;or after the other&amp;nbsp;Materials but you will get different results between the two if you have any overlapping front faces (or back faces if we're talking about BackMaterial).&amp;nbsp;&lt;/P&gt;
&lt;P&gt;-- Jordan&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1841409" 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></item><item><title>Interacting with 2D on 3D in WPF</title><link>http://blogs.msdn.com/wpf3d/archive/2006/12/12/interacting-with-2d-on-3d-in-wpf.aspx</link><pubDate>Wed, 13 Dec 2006 06:19:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1270819</guid><dc:creator>wpf3d</dc:creator><slash:comments>32</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/1270819.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=1270819</wfw:commentRss><description>&lt;P&gt;Interacting with 2D placed on 3D is now possible in v1 of the Windows Presentation Foundation!&lt;/P&gt;
&lt;P&gt;In between shipping Vista and planning the next version of WPF, we realized that with a clever implementation it was possible to provide this feature today on v1 bits, and I’m happy to report that as of now, the binaries (and source code to them) needed to do this are available for download (&lt;A class="" href="http://www.codeplex.com/3DTools/Release/ProjectReleases.aspx?ReleaseId=577" mce_href="http://www.codeplex.com/3DTools/Release/ProjectReleases.aspx?ReleaseId=577"&gt;here&lt;/A&gt;).&lt;/P&gt;
&lt;P&gt;The download also contains two sample applications - InteractiveViewport3DSample and Channel9Demo - which illustrate how to use the code.&amp;nbsp; So if you just want to dive right in to 2D on 3D, that's a good place to start.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The rest of this post will describe how to use this feature as a developer, as well as how it’s implemented behind the scenes.&amp;nbsp; If you want the video version though, which includes a cool demo of an app we made with the 2D on 3D code (photo shown below – source here &lt;A href="http://www.codeplex.com/3DTools/Release/ProjectReleases.aspx?ReleaseId=2058"&gt;http://www.codeplex.com/3DTools/Release/ProjectReleases.aspx?ReleaseId=2058&lt;/A&gt;), check it out on Channel9&amp;nbsp;(&lt;A class="" href="http://channel9.msdn.com/Showpost.aspx?postid=266036" mce_href="http://channel9.msdn.com/Showpost.aspx?postid=266036"&gt;here&lt;/A&gt;).&lt;/P&gt;
&lt;P&gt;&lt;IMG title="Flickr Application" style="WIDTH: 628px; HEIGHT: 402px" height=402 alt="Flickr Application" src="http://blogs.msdn.com/photos/wpf3d/images/1270944/original.aspx" width=628 mce_src="http://blogs.msdn.com/photos/wpf3d/images/1270944/original.aspx"&gt;&lt;BR&gt;&lt;/P&gt;
&lt;H3&gt;How do you use it?&lt;/H3&gt;
&lt;P&gt;There are two main classes needed to add 2D on 3D to you app: Interactive3DDecorator and InteractiveVisual3D.&amp;nbsp; The Interactive3DDecorator handles the majority of the work that allows the 2D on 3D interaction to happen.&amp;nbsp; To use it, you simply place it around the Viewport3D that you intend to make interactive.&amp;nbsp; So in XAML, you have:&lt;/P&gt;&lt;FONT face="Courier New" size=2&gt;
&lt;P&gt;&amp;lt;local:Interactive3DDecorator&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Viewport3D&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; …&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/Viewport3D&amp;gt;&lt;BR&gt;&amp;lt;/local:Interactive3DDecorator&amp;gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;Then, to actually add interactive 2D on 3D objects in to your scene, you use the InteractiveVisual3D class.&amp;nbsp; InteractiveVisual3D is a subclass of ModelVisual3D and provides the following dependency properties which set up the interactive 2D on 3D:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Geometry&amp;nbsp; - The Geometry3D that is to become the content of the InteractiveVisual3D .&lt;/LI&gt;
&lt;LI&gt;Visual – The 2D you want to interact with on the 3D geometry.&lt;/LI&gt;
&lt;LI&gt;Material – A user specified material to use on the 3D object.&amp;nbsp; By default, a DiffuseMaterial is used.&lt;/LI&gt;
&lt;LI&gt;IsBackVisible – Indicates whether the material used for the front face should also be mirrored on the back face.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;The first two properties, Geometry and Visual, are the primary ones needed.&amp;nbsp; They allow the geometry that should be used to bet set, as well as the Visual that should appear on that geometry.&amp;nbsp; For example, the below XAML code demonstrates how to create an InteractiveVisual3D.&lt;/P&gt;&lt;FONT face="Courier New" size=2&gt;
&lt;P&gt;&amp;lt;local:InteractiveVisual3D Geometry="{StaticResource PlaneMesh}"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;local:InteractiveVisual3D.Visual&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;StackPanel&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Label Content="Sample UI" /&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Button Content="Close Window"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;TextBox /&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/StackPanel&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/local:InteractiveVisual3D.Visual&amp;gt;&lt;BR&gt;&amp;lt;/local:InteractiveVisual3D&amp;gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;The other properties allow for fine tuning of the object’s appearance.&amp;nbsp; The Material property allows a user to create their own material for the object.&amp;nbsp; To do so, a user can create a material as always, and then specify using the IsInteractiveMaterial attached property which material is intended to be “interactive” (i.e. the VisualBrush created using the passed in Visual is set as the Brush for that material). Note, this attached property must be set to true on at least one material – otherwise an exception will be thrown.&amp;nbsp; If you ever want to disable interaction, you can set “IsHitTestVisible” on the Visual to be false.&amp;nbsp; As an example of setting a custom material, the following code sets the material to be composed of a DiffuseMaterial, which will contain the visual brush, and a SpecularMaterial.&lt;/P&gt;&lt;FONT face="Courier New" size=2&gt;
&lt;P&gt;&amp;lt;local:InteractiveVisual3D.Material&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;MaterialGroup&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;DiffuseMaterial local:InteractiveVisual3D.IsInteractiveMaterial="True"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;SpecularMaterial Brush="Red" /&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/MaterialGroup&amp;gt;&lt;BR&gt;&amp;lt;/local:InteractiveVisual3D.Material&amp;gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;Finally, IsBackVisible sets the material used on the front face to also be used on the back face.&amp;nbsp; Currently, the Interactive3DDecorator does not distinguish between front and back faces, so this allows for there to be interaction with the back face as well.&lt;/P&gt;
&lt;H3&gt;&lt;STRONG&gt;How does it work?&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P&gt;At a very high level, the interaction with 2D on 3D is achieved by really interacting with a hidden version of that 2D content in 2D.&amp;nbsp; The 2D is positioned such that the point in 3D the mouse is over is the exact same point as the mouse is over on the hidden 2D version.&amp;nbsp; Then, when the user clicks, etc… they are interacting with exactly the same location.&amp;nbsp; If you want to see this for yourself, you can set the “Debug” property on Interactive3DDecorator to true, which makes the hidden layer partially visible. &lt;/P&gt;
&lt;P&gt;The Interactive3DDecorator then consists of two elements: the 3D content that is displayed within it and a hidden layer that is used to position and display the 2D content that is being interacted with.&amp;nbsp; Depending on what 2D content on 3D is being interacted with, the hidden layer changes to hold that 2D content.&amp;nbsp; The images below give a visual representation of what is going on.&amp;nbsp; The first photo is just of the 2D content we wish to place on 3D.&amp;nbsp; The second is that 2D content on 3D.&amp;nbsp; And finally, the third image shows how the 2D on 3D interaction takes place.&amp;nbsp; When the mouse moves over the “B” in the button, the hidden layer (shown to be only partially transparent for this example) is moved such that the mouse is over the same point in the hidden layer as it is in the 3D scene.&lt;/P&gt;
&lt;P&gt;&lt;IMG title=ex1 style="WIDTH: 247px; HEIGHT: 254px" height=254 alt=ex1 src="http://blogs.msdn.com/photos/wpf3d/images/1270951/original.aspx" width=247 mce_src="http://blogs.msdn.com/photos/wpf3d/images/1270951/original.aspx"&gt;&lt;IMG title=ex2 style="WIDTH: 279px; HEIGHT: 254px" height=254 alt=ex2 src="http://blogs.msdn.com/photos/wpf3d/images/1270952/original.aspx" width=279 mce_src="http://blogs.msdn.com/photos/wpf3d/images/1270952/original.aspx"&gt;&lt;IMG title=ex3 style="WIDTH: 279px; HEIGHT: 254px" height=254 alt=ex3 src="http://blogs.msdn.com/photos/wpf3d/images/1271170/original.aspx" width=279 mce_src="http://blogs.msdn.com/photos/wpf3d/images/1271170/original.aspx"&gt;&lt;BR&gt;&amp;nbsp; &lt;BR&gt;To figure out where to position the hidden layer works as follows.&amp;nbsp; When the mouse moves in the 3D scene, a ray is shot in to the 3D scene to see if it intersects any object.&amp;nbsp; If it hit an object, and it is an InteractiveVisual3D, we can use the return parameters from the intersection to compute the texture coordinate that was hit.&amp;nbsp; Then from these, we can map from the (u,v) value of the texture coordinate, on to an x,y point on the 2D visual, which is the point we need to place under the mouse.&amp;nbsp; More specifically, the code assumes texture coordinates are all in the range (0,0) to (1,1) – i.e. upper left to lower right of the image (for those planning to use this, this is important to know, since your texture coordinates need to be within this range to enable interaction with the 2D content).&amp;nbsp; Then the point on the 2D object that was hit is simply (u * Width, v * Height). &lt;/P&gt;
&lt;P&gt;One of the great things about this method then is that the only event that needs to be tracked is when the mouse moves.&amp;nbsp; There’s no need for catching and forwarding on every type of event: the hidden layer takes care of all of this work.&amp;nbsp;&amp;nbsp; &lt;BR&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Positioning With Capture&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;There’s one very interesting “gotcha” though: what happens when one of the 2D objects grabs capture and then you move off the 3D mesh it is on?&amp;nbsp; For example, you select some text, and then move the mouse above that selected text, or click and hold on a button, and then move away from it.&amp;nbsp; Correct hidden content positioning becomes more complicated in this case.&amp;nbsp; The problem becomes difficult for many reasons.&amp;nbsp; In the normal 2D situation, both the mouse position and the 2D content exist in the same plane.&amp;nbsp; The transformation that is applied to the 2D content can be used to transform the mouse position to the content’s local coordinate system.&amp;nbsp; However in 3D, due to the projection of 3D on to a 2D plane, the mouse’s position actually corresponds to a line in 3D space.&amp;nbsp; In addition, the element with capture could also be mapped to any arbitrary geometry.&amp;nbsp; When the mouse is over the 3D object, hit testing tells us where it is relative to the 2D visual.&amp;nbsp; When it is off the 3D object, due to the above issues, there is no longer a straight forward answer to this question: the 2D point corresponds to a 3D line and the 2D content could be on arbitrary 3D geometry.&amp;nbsp; Also, because the element has capture, it wants to receive all events.&amp;nbsp; Before, we only needed to be sure that the mouse was over the correct object at all times.&amp;nbsp; Now we need to position the hidden visual such that it is in the proper position relative to the object that has capture.&lt;/P&gt;
&lt;P&gt;To solve this issue, the code takes the following approach:&amp;nbsp; The overall idea is to reduce the 3D problem back to 2D.&amp;nbsp; In the normal 2D case, the transformations applied to the content can be used to convert the mouse position to the content’s local coordinate system.&amp;nbsp; This transformed position then lets the content know where the mouse is relative to it.&amp;nbsp; In 3D, due to the many orientations of the geometry and texture coordinate layouts, it’s difficult to say where a 3D point is in the relative coordinate system of the 2D content on 3D.&amp;nbsp; To approximate this, the outline of the 2D content on 3D, after it has been projected to screen space, is computed, and then the mouse is positioned based on this projection.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;For example, take the 3 images below.&amp;nbsp; The first is the 2D content on 3D.&amp;nbsp; In the second image, text is selected, and the mouse is moved to a point off the object.&amp;nbsp; The third image is the outline of the text box (the object that has capture).&amp;nbsp; This outline is then used to position the hidden visual.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;IMG title=ex4 style="WIDTH: 178px; HEIGHT: 180px" height=180 alt=ex4 src="http://blogs.msdn.com/photos/wpf3d/images/1270976/original.aspx" width=178 mce_src="http://blogs.msdn.com/photos/wpf3d/images/1270976/original.aspx"&gt;&lt;IMG title=ex5 style="WIDTH: 178px; HEIGHT: 180px" height=180 alt=ex5 src="http://blogs.msdn.com/photos/wpf3d/images/1271169/original.aspx" width=178 mce_src="http://blogs.msdn.com/photos/wpf3d/images/1271169/original.aspx"&gt;&lt;IMG title=ex6 style="WIDTH: 177px; HEIGHT: 179px" height=179 alt=ex6 src="http://blogs.msdn.com/photos/wpf3d/images/1270994/original.aspx" width=177 mce_src="http://blogs.msdn.com/photos/wpf3d/images/1270994/original.aspx"&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;BR&gt;After the outline is available, The closest point on this outline to the mouse position is computed, and then this point on the outline is considered what was “hit” and it is placed under the moue position (hence, highlighting up to the “T” in the middle image below).&amp;nbsp; Since we place the mouse by the closest edge point, the interaction tends to behave as it would in 2D, since we position the hidden content based on what the mouse is closest to on the 2D content on 3D.&amp;nbsp; By placing it at the closest edge point, we are explicitly stating about where we expect the mouse to be relative to the 2D on 3D element’s orientation.&lt;/P&gt;
&lt;P&gt;This method helps provide an intuitive response to the interaction, since the interaction happens with the closest point on the object with capture to the mouse.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Enjoy using it!&amp;nbsp; We’ve had a lot of fun building this, and can’t wait to see what kind of incredible applications will be built with it!&lt;/P&gt;
&lt;P&gt;-Kurt&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1270819" 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/3DTools/default.aspx">3DTools</category></item><item><title>Material Color Knobs</title><link>http://blogs.msdn.com/wpf3d/archive/2006/12/08/material-color-knobs.aspx</link><pubDate>Fri, 08 Dec 2006 23:40:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1237335</guid><dc:creator>wpf3d</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/wpf3d/comments/1237335.aspx</comments><wfw:commentRss>http://blogs.msdn.com/wpf3d/commentrss.aspx?PostID=1237335</wfw:commentRss><description>&lt;P&gt;We affectionately refer to DiffuseMaterial.Color, DiffuseMaterial.AmbientColor, SpecularMaterial.Color, and EmissiveMaterial.Color as the "color knobs." The color knobs are probably the least understood WPF3D feature because they were one of the last (if not the last) features we added and most of the things you can do with them are not obvious. Hopefully this article will give you insight into how the properties work and help you write better XAML exporters.&lt;/P&gt;
&lt;P&gt;The full lighting equation used by WPF&amp;nbsp;is definitely something we need to cover later, but essentially the final color for a single Material is going to be: Color * lighting result * Brush. DiffuseMaterial includes both ambient and diffuse lighting so it has two color properties making the&amp;nbsp;equation:&amp;nbsp;(AmbientColor * ambient lighting result + Color * diffuse lighting result) * Brush. From this equation, you can see that you can't just set Color and be done -- you also need a Brush. By default, all of the Color properties are white giving them no effect on the final appearance.&lt;/P&gt;
&lt;P&gt;Now let's look at a few ways to use these properties.&lt;STRONG&gt;&amp;nbsp;&lt;/STRONG&gt;(By the way, if I refer to a color channel going from 0.0 -&amp;gt; 1.0 it's the same as 0 -&amp;gt; 255 if you're using bytes)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Color Knobs as a Filter&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Let's say a&amp;nbsp;GeometryModel3D with a DiffuseMaterial is being hit by a light containing red. If you set&amp;nbsp;the red channel of the color knob&amp;nbsp;to 0, the mesh won't reflect any red light. If you set it to 1, it'll reflect all of the red light the Brush reflects. By changing the value between 0 and&amp;nbsp;1 you can "dial in" how much you want to reflect back. This is&amp;nbsp;how we started calling them "knobs."&lt;/P&gt;
&lt;P&gt;The color knobs are full colors so they do have alpha. Setting the alpha value does what you would expect (e.g. alpha of 0.5 makes it half transparent). There is one exception to things and, surprise, it's DiffuseMaterial. Only DiffuseMaterial.Color.A affects the transparency of the Model. Turning down DiffuseMaterial.AmbientColor.A does make the ambient&amp;nbsp;component transparent and increase the impact of the diffuse component, but it does not affect Model transparency.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;AmbientMaterial&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;DiffuseMaterial, SpecularMaterial, EmissiveMaterial... where's AmbientMaterial? We don't have it. What do you if you want a Model to respond to only ambient light? Before color knobs, it couldn't be done. With color knobs, create a DiffuseMaterial, set Color to (0,0,0,0), and all diffuse contribution will be wiped out leaving you with just ambient!&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Fully Illuminated Solid Colors&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Say you wanted to make a Model look green. You have two good options: a white brush with a green color knob &lt;EM&gt;or&lt;/EM&gt; a green brush with a white (the default value) color knob. Is there a difference between the two?&amp;nbsp;It depends on how much light is hitting the Model. If the amount of light hitting isn't greater than 1.0 in each channel, then they're equivalent. If not, here's what happens:&lt;/P&gt;
&lt;CENTER&gt;
&lt;P&gt;&lt;IMG title="green knob, white brush" style="WIDTH: 227px; HEIGHT: 228px" height=228 alt="green knob, white brush" src="http://blogs.msdn.com/photos/wpf3d/images/1237189/original.aspx" width=227 mce_src="http://blogs.msdn.com/photos/wpf3d/images/1237189/original.aspx"&gt;&lt;IMG title="white knob, green brush" style="WIDTH: 229px; HEIGHT: 230px" height=230 alt="white knob, green brush" src="http://blogs.msdn.com/photos/wpf3d/images/1237210/original.aspx" width=229 mce_src="http://blogs.msdn.com/photos/wpf3d/images/1237210/original.aspx"&gt;&lt;/P&gt;&lt;/CENTER&gt;
&lt;P&gt;Both pictures are of a sphere mesh with a DiffuseMaterial and two full power point lights shining on it. On the left, the the Color is set to #ff006000 and the Brush is set to white. On the right, the Color is set to white and the Brush is a #ff006000 SolidColorBrush. Why is the one on the left so vibrant and the one on the right so lackluster?&lt;/P&gt;
&lt;P&gt;In the graphics pipeline, lighting is calculated in the vertex processing stage and textures are sampled later on in pixel processing. In WPF, all Brushes applied to 3D are done as textures -- even SolidColorBrushes. Unfortunately, the graphics card clamps colors coming out of the vertex stage to 1 so no matter how many hundreds of lights you have you will never be able to exceed the color of the SolidColorBrush. As you can see in the image on the right, the big solid color splotch in the middle has a value of #ff006000, the color of the SCB. The color knob value is incorporated &lt;EM&gt;during vertex processing&lt;/EM&gt; so it is multiplied by the unclamped lighting result. For those of you used to per-vertex colors in other APIs, you can think of the color knob as a single vertex color for&amp;nbsp;the entire mesh. This explanation is tricky and requires some knowledge of graphics hardware but hopefully it made some sense :)&lt;/P&gt;
&lt;P&gt;In general, you may end up wanting to use the color knobs for all of your solid color needs*. &lt;/P&gt;
&lt;P&gt;-- Jordan&lt;/P&gt;
&lt;P&gt;* There is one minor perf issue to take note of if you don't have a Tier 2&amp;nbsp;graphics card:&amp;nbsp;If you have a MaterialGroup with more than one DiffuseMaterial or more than one SpecularMaterial and those duplicate Materials have different&amp;nbsp;color knob values, you will incur a performance penalty. For example, a MaterialGroup with two DiffuseMaterials one with Color (.5, .5,&amp;nbsp;.5) and one with Color&amp;nbsp;(1, 1, 1).&amp;nbsp;Fortunately, this doesn't happen too often.&amp;nbsp;See &lt;A href="http://msdn2.microsoft.com/en-us/library/ms742196.aspx"&gt;this MSDN article&lt;/A&gt; for information about tiering.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1237335" 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></item></channel></rss>