Thursday, April 3, 2008

Texturemapping in Silverlight 2beta1

Click here if you want to see the example and skip my development log :)

A while ago I was asked the following: "Can you make a 360 degree panorama viewer in Silverlight?"
Naively I answered: "I think so, I have the sourcecode for a texturemap routine in Flash, and that should be reusable in Silverlight"

Sounded easy enough, but unfortunately I was wrong.

My colleague Rob Houweling helped me get started in Silverlight and helped me out when I got Stuck in C# and I set off to work in Silverlight 1.1a

Now Flash does not support texturemapping, but you can fake this with some clever routines. Seb Lee-Delisle explains how this works visually

I have Flash sourcecode that does just that. This code unfortunately uses 2 matrix calculations, Matrix.invert and a concatenate function which simply arent supported in Silverlight.
(Hmm, I also just discovered that there's a newer version of this class which does not use these calculations, and could have saved me a lot of work.. ahwell, live and learn.. Anyway, it still uses 2 matrices though)

After porting the code and adding my own invert functions, I discovered that the matrix transformations in Silverlight had a big bug. When using the exact same matrix that Flash uses, Silverlight didn't draw the transformation correctly, It seemed that matrix accuracy was completely incorrect. Using Javascript and silverlight, you apparantly don't have this problem. See Kit3d. But Javascript is a lot slower than c# so that was not an option.

Did you ever notice that several people started working on 3d engines in c#, got as far as flat-shading and then development halted? I think this is because of this lame Matrix-problem..:)

Anyway, we decided to wait 2 weeks until the release of Silverlight 2.0.
Now the matrix worked properly and I continued work on the texture mapper.
Unfortunately I couldn't get the function to work with 2 matrices. All the output was simply wrong. So I decided to try again and see if I could write the same code with only 1 matrix (inverting + concatenating 2 matrices also results in 1 matrix, so this should work)

I found some code that did exactly that, but the code was next to unreadable and had a weird coordinate space that was unusable for me so I simplified the heck out of it and modified it to suit my needs.
That worked!

I now had the correct output.

I could split up my texture in triangles, and plot them back to the screen, as long as I didn't rotate anything.
Which is not quite right.

This had to do with the way Silverlight draws out transformed bitmaps, it uses the topmost and leftmost pixel coordinate to start. Flash uses the first pixel you draw in your shape.

Luckily this was solveable by checking for this location and changing the texture's offset.

After this was done, creating a panorama viewer (a 3d cube with an observer in the middle) was quite easy.

Online Example
So Ladies and Gentlemen, without further ado I now present:

The (to our knowledge) first 3d texturemapper in Silverlight using C#

Panorama viewer in Silverlight 2.0

You need Silverlight 2beta1 get it here

I've also put up the sourcecode here.
(Mind you, the code is quite messy and not optimised.)

Please let me know what you think.

And to all 3d-engine coders out there, go on, add texturemapping!
(and fix my code, because its probably crap ;)

One problem still remains as you can see in the panorama viewer. Silverlight insists on anti-aliasing. This Cannot be switched off. So we're stuck with ugly white-ish lines around every triangle we draw.

I've tried fixing this by making the triangles overlap slightly, but havent pulled it off quite right, it distorts the rendered image, so I gave up that attempt.

Microsoft, please fix this, it's annoying.