Confused about Normals
Monday, August 28th, 2006For some reason, the Normals property on a MeshGeometry3D is per vertex. Who ever heard of a point having a normal? It’s weird. Just thought I’d point that out.
For some reason, the Normals property on a MeshGeometry3D is per vertex. Who ever heard of a point having a normal? It’s weird. Just thought I’d point that out.
Just a quick pointer to some useful code I found myself needing:
This is really cool. It also seems to be inhumanly fast. It’s a pretty blatant advert for a commercial clustering and knowledge extraction engine, but it’s still really neat.
It’s good to know I’m not completely barking mad. Well, not about source control, anyway. There’s a post here that I just spotted on del.icio.us that pretty much confirms my suspicions.
I’ve long been a proponent of subversion as a revision control mechanism. It’s got me out of more scrapes than I can count, and I push it as one of the technical foundations of any project I get involved with, mostly because I just haven’t found anything better. Well, except maybe darcs, but that doesn’t have the utterly wonderful TortoiseSVN shell extension for Windows, which is one of the very first things to get installed whenever I start work on a new workstation.
Cool stuff. Don’t know where I’d be without it.
There’s a great essay up here. Should be required reading.
The post is here.
I’ll be documenting here a set of terms in LightWave lingo along with their equivalents in WPF/XAML. I’ll also be making notes of any pertinent differences in approach between the two environments particularly pertaining to each specific concept. The notes here will specifically be limited to what’s acheivable in XAML without any code behind to pull off any fancy tricks.
Some of these notes will be obvious, others less so.
This does not claim to be authoritative – it’s all based on my personal observations, so if I’m wrong, please let me know!
These are the closest equivalent terms for the general geometry/surface wrappers in each environment. A GeometryModel3D brings together the actual vertex geometry (MeshGeometry3D) with a surface definition (MaterialGroup).
The same functionality that Parenting gives in LightWave can be achieved by grouping a Child’s Model3D data in the Parent’s Model3D.Children property. This has the effect of applying all transformations the Parent receives to the Child.
Ok, so you’ll almost certainly find a use for the MatrixCamera class too, as soon as you depart from LightWave’s simple camera settings, but ProjectionCamera is the ancestor class of PerspectiveCamera and OrthographicCamera, which will cover 97% of the uses you’ll need. LightWave’s camera is defined to look up its own Z axis, and this is most easily modeled with a LookDirection of 0,0,-1 in the xaml. Cameras in WPF also have a Transform property, so they are animatable in exactly the same way as Model3Ds.
As far as I can tell, there is simply no way to declaratively make Model3Ds, lights or the camera rotate in place driven by another object. There’s scope here for subclassing GeometryModel3D and adding a Target DependencyProperty, if one feels so inclined… Maybe one of these days I’ll get round to it
There’s a slight kink to this. LightWave’s UV map coordinates are specified per image in the surface, so in principle there can be as many UV map sets for an object as there are texture layers. A MeshGeometry3D only has a single TextureCoordinates property, and it doesn’t support any projection types. This means that in order to have any hope of matching appearance between LightWave and WPF, all images on an object must share the same projection type and parameters.
These are directly equivalent.
A Distant Light is almost the same as a DirectionalLight. They differ in that a Distant Light can have a Target. A DirectionalLight cannot.
LightWave’s lighting has a global ambient colour and intensity setting. The closest equivalent to these in XAML is the AmbientLight type. AmbientLights only have a Color property, but you can have more than one in a given Model3D tree.
The Spot Light and SpotLight are almost identical. The only difference is that LightWave’s outer cone angle is measured from the center to the edge, whereas WPF’s SpotLight’s OuterConeAngle property is measured from side to side (that is, the OuterConeAngle value is double LightWave’s value).
The colour channel in LightWave is primarily represented by the DiffuseMaterial in WPF. However, there are wrinkles in this…
In LightWave, transparency goes from 0% (fully opaque) to 100% (fully transparent). The sense is reversed in WPF – Opacity values go from 0.0 (fully transparent) to 1.0 (fully opaque).
In LightWave, the transparency channel is applied as a scalar intensity level to a surface. In WPF, there concept of a “transparency channel” doesn’t really exist. There’s no such thing as an OpacityMaterial, for example. There are two options if you want the effect of image-based transparency. The first is to apply your transparency map to the alpha channel of the colour image you are using for the DiffuseMaterial. The immediate advantage of this is that it’s simple. As long as you’ve only got a single colour image map, and you don’t mind altering the source image, it’s probably easiest to do this.
The alternative is a little more convoluted. It’s easiest to show the code first, then explain what it’s doing.
<VisualBrush>
<VisualBrush.Visual>
<Image HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0"
Source="#filename#">
<Image.OpacityMask>
<ImageBrush ImageSource="#mask_filename#" />
</Image.OpacityMask>
</Image>
</VisualBrush.Visual>
</Visual>
What we have here completely replaces the ImageBrush that would otherwise have filled the DiffuseMaterial.Brush property of the MaterialGroup. What this does is to create a generic Image control, and, taking advantage of the fact that all UIElements can have an OpacityMask added, we apply our transparency mask image to that control. Then we place that control inside a VisualBrush, which allows it to be used as a texture.
There is, however, a catch. OpacityMasks, for some unknown reason (and I don't know of any other system that works this way) use the opacity of the opacity mask's image for its value, not the intensity. With that in mind, the only technique I've found to use the same transparency image file in both LightWave and WPF involves copying the image, inverting it, and applying it to itself as an alpha mask, then switching off the alpha channel in LightWave. Clunky, but it works.
EmissiveMaterial is the closest match for LightWave's luminosity. However, they don't quite work the same way. A higher luminosity value in LightWave makes the observed surface colour tend towards the full surface colour value. EmissiveMaterials are entirely independent of any DiffuseMaterials that happen to live in the same MaterialGroup, and are coloured rather than scalar. I'll post an update shortly about how to get matching behaviour between the two.
The SpecularMaterial behaves in a very similar fashion to the Specular channel in LightWave, with the intensity of the SpecularMaterial's brush providing a close analogue to the specular channel value.
Glossiness is approximately SpecularPower. I haven't confirmed a mathematical relationship, but from visual tests it looks to me like the glossiness range 0% -> 100% maps to a SpecularPower range of 17 -> 255. Also, it doesn't appear to be possible to apply an image map to this property.
So, I’m trying to map a video texture onto a Xaml surface. So far, so easy. Except I want to apply the diffuse data to the emissive channel, because that’s closer to the way LightWave works. This is fine with static textures, but there’s a problem with videos. I generate as much as possible in a ResourceDictionary, and the relevant Xaml looks a little like this:
<VisualBrush x:Key="media_element" Opacity="1.0">
<VisualBrush.Visual>
<MediaElement Source="#filename#" />
</VisualBrush.Visual>
</VisualBrush>
<DiffuseMaterial Brush="{StaticResource media_element"} />
<EmissiveMaterial Brush="{StaticResource media_element"} />
The problem is that even when I specify that the DiffuseMaterial and EmissiveMaterial brushes point to the same element, they get their own players which don’t start in sync, so you get ghosting and funky audio ringing. I can’t see an obvious way around this… Anyone?
I’ve promised myself a place to keep all those little code tid-bits, bits of news that interest me, bits of news that might interest others, and general Online Stuff for quite a while now. So here it is.
A few months ago, I switched all of my online client development to Ruby, mainly because it’s a damn cool language. Why, then, a WordPress blog? Mainly because the server load is much, much lower than with a Rails blog (and I don’t know of any sufficiently mature alternatives), and setup is drop-dead simple. Which I like. I can live with PHP running things in the background, as long as I don’t actually have to touch the godforsaken language myself.
I am a coder of sorts, trained as an engineer, who loves getting into the technical bowels of a problem. I am a compulsive magpie in certain areas – image processing, natural language processing, 3D graphics, microcontrollers and BEAM robotics to name but a few. I rarely have enough time to pursue any of these to any sort of depth other than to keep abreast of what’s going on in the field.
I also don’t have enough time for gaming in any meaningful sense, which is a shame.
I live in London, and love it here.
A quick round-up of posts and pages I’ve spotted that mention or link to Shaxam:
There may be others I’ve missed, but those are the ones I’ve been told about…