GSI

Of course I couldn't mention a technique of possible real-time cell-shading yesterday without actually trying it out. No, I didn't attempt to derive from BitmapEffect. (I'd love to take a crack at BitmapEffect but I simply cannot justify the expenditure of time.)

Instead, I tried the RenderTargetBitmap approach. Here's a rough outline:

  • Lay out your Page or Window normally but instead of defining a Viewport3D element, use a Border instead. The Border is perhaps the simplest FrameworkElement derivative that has a Background property. Give the Background property an object of type ImageBrush.
  • Whatever you would have put into your Viewport3D put into a Viewport3DVisual instead. Set the Viewport property of the Viewport3DVisual to the actual size of the Border element. You'll need a handler for the SizeChanged event of the Border to keep this Viewport property updated when the Border size changes.
  • In that same SizeChanged event handler for the Border, create an object of type RenderTargetBitmap the same size as the Border and the Viewport3DVisual. You'll be recreating this bitmap whenever the size of the Border changes.
  • Insteall event handlers for anything else (such as scrollbars) that affect the 3D scene defined within the Viewport3DVisual.
  • Whenever anything happens that affects the appearance of the Viewport3DVisual perform the following actions:
    • Clear the RenderTargetBitmap by calling the Clear method.
    • Render the Viewport3DVisual on the bitmap by calling the Render method.
    • Dump the pixel bits of the RenderTargetBitmap into an array by calling CopyPixels.
    • Do whatever processing you want on the pixel bits. (For cell-shading, I just AND-ed each 32-bit ARGB pixel with 0xFFC0C0C0.)
    • Create a new bitmap based on the altered pixel bits by calling BitmapSource.Create.
    • Set that new bitmap to the ImageSource property of the ImageBrush object set to the Background property of the Border.

Here's the RealTimeCellShading source code. Sorry I can't give you an XBAP, but apparently Clear and CopyPixels are prohibited methods for partial trust. (But Render and BitmapSource.Create are mysteriously OK. Hey — I don't make up the XBAP rules!)

I've used an AmbientLight at 1/4 white and DirectionalLight of 3/4 white with a direction of (2, –3 –1). I've provided a pair of scrollbars to rotate the camera relative to the teapot, and a pair of sliders to rotate the teapot relative to the camera and light sources. Here's a view with the teapot slightly rotated:

Posted by gsi
: