Robotic Pandas

On abstractions for building next generation user interfaces

Announcing Bling 3.1!

Posted by mcdirmid on 27/10/2009

I’d like to announce a new version of Bling (http://bling.codeplex.com/) with maturing experimental support for retained and programmable 3D graphics. On the one hand, we have immediate-mode programmable graphics in Direct3D, which is flexible and fast but is more difficult to program. On the other hand, we have retained mode graphics in WPF 3D, which is easier to program but is less flexible and not as fast as straight Direct3D. Bling is a side project that experiments with something in between the two: the ease of programming that a retained graphics model provides with the flexibility and performance that comes with the ability to express custom pixel and vertex shaders.  Bling is built on top of Direct3D via the WindowsAPI Code pack, the DLR, and WPF.

Long description/example for those that are interested:

In Bling, 3D programmers are expressed by the programmer in pure C# code rather than HLSL code—at run-time the C#-encoded shaders are dynamically translated into HLSL code that is then compiled into DirectX 10 shaders. Shader bodies can directly refer to dependency properties, which are translated into uniform slots (aka global parameters) that are maintained via efficient dynamically generated CLR code (via the DLR). A simple complete example that uses a camera but no lighting:

CameraZ = new LabelSliderBl(this) { LabelName = "Z", Minimum = -40d, Maximum = +10d, Value = -4d, };
RotateX = new LabelSliderBl(this) { LabelName = "RotateX", Minimum = 0d, Maximum = 2d, Value = .9d, };
RotateY = new LabelSliderBl(this) { LabelName = "RotateY", Minimum = 0d, Maximum = 2d, Value = .9d, };
CubeTopology Cube = new CubeTopology();
Point3DBl WorldCenter = new Point3DBl(0, 0, 0);
Point3DBl CameraPosition = WorldCenter + new Point3DBl(0, 0, CameraZ.Value);
PerspectiveCameraCl Camera = new PerspectiveCameraCl() { Position = CameraPosition, };
ColorBl[] FaceColors = new ColorBl[] {
 Colors.Red, Colors.LightGreen,
 Colors.Blue, Colors.Yellow,
 Colors.Purple, Colors.Salmon,
};
Device.Render(Cube.Count, 16, (IntBl n, IntBl m, IVertex vertex) => {
 QuaternionBl qx = new QuaternionBl(new Point3DBl(1, 0, 0), RotateX.Value.PI());
 QuaternionBl qy = new QuaternionBl(new Point3DBl(0, 1, 0), RotateY.Value.PI());
 PointBl mxy = new PointBl(m % 4, m / 4);
 mxy = (mxy / 4d) - (.5 + .25) / 2d;
 vertex.Position =
(Camera * mxy.InsertZ(0).Translate() * .1.Bl().XXX().Scale() * (qx * qy).Matrix).Transform(Cube[n]);
 vertex.Color = FaceColors.Table(n / 4);
}, Cube.IndexBuffer);

The example defines 3 sliders (Z, RotateX, RotateY) with Slider-like Value dependency properties, these properties are then referred to in the Device.Render call to define the position of each vertex in a cube (defined through a utility cube topology class), where Z drives the perspective camera’s Z position while RotateX and RotateY are used to define rotations around the X and Y axis respectively. The cube is instanced 16 times, where n is the vertex ID and m is the instance ID. As with other shader-based programming models, all the logic for rendering is specified directly in the shader; e.g., the effects of the camera must be multiplied into the position computation.

clip_image001 clip_image002

This approach has full support for WPF dependency property capabilities, including WPF-based animation. Partitioning shader computations between pixel and vertex shaders is also inferred, with the principle that computation occurs in the vertex shader  as possible unless the programmer specifies otherwise. For example, consider the following code with a spotlight where all lighting computations are done in the vertex shader:

var Slider = new LabelSliderBl(this) {
 Minimum = -.1, Maximum = +.1, Value = 0, LabelName = "Light",
};
LightBl light = new SpotLightBl() {
 Direction = (new Point3DBl(Slider.Value, Slider.Value, +1)).Normalize,
 Color = Colors.White,
 Position = new Point3DBl(0, 0, -2.5),
 InnerConeAngle = 2.ToDegrees(),
 OuterConeAngle = 4.ToDegrees(),
};
MaterialCl diffuse = new DiffuseMaterialCl() {
Factor = .5,
Ambient = { Factor = .5 }
};
Device.Render(Cube.Count, DIM * DIM, (IntBl n, IntBl m, IVertex vertex) => {
Point3DBl WorldPos;
… /* ellided position computations */
 Vertex.Color = diffuse.ApplyLights(light + new AmbientLightBl() { Color = Colors.White }).
 ApplyAt(WorldPos, normal, CameraPosition).ForColor(clr);
}, Cube.IndexBuffer);

Result:

clip_image003

For better quality, we can force the lighting computation down into the pixel shader by specifying that world positions are computed on a per-pixel basis:

Device.Render(Cube.Count, DIM * DIM, (IntBl n, IntBl m, IVertex vertex) => {
Point3DBl WorldPos;
… /* ellided position computations */
 Vertex.Color = diffuse.ApplyLights(light + new AmbientLightBl() { Color = Colors.White }).
 ApplyAt(WorldPos.PerPixel(), normal, CameraPosition).ForColor(clr);
}, Cube.IndexBuffer);
The result is an improvement in quality if you look closely:

clip_image004

Other nice features:

· An explicit signature mode where uniforms, vertex, pixel, and geometry shaders are specified directly as annotated C# interfaces. This mode gives the user more control without requirement too much boiler plate, and is also the only way we can currently express DX10 geometry shading.

· Render target textures, ability to specify multiple render out passes, e.g., for simulating heat diffusion:

· Camera, light, and material model based on WPF 3D, with enhancements (e.g., a glass material).

· Meta-programming of shader trees to do things like automatically compute the derivative of an expression or automatically compute the upper bound of vertices that could be produced by a geometry shader.

· Lots of graphic utility classes to ease the expression of shaders and hide the math; e.g., one line of code to normal map a texture onto a parametric surface.

· DX10/WPF airspace issues addressed by overlay window.

Caveats:

· Right now Bling is only meant for prototypes and experiments, and not meant for production use; e.g., no DX resource management has been implemented. Bling is an effective way of rapidly exploring design ideas, which are then produced using a more established/involved technology (e.g., Direct3D).

· No XP support (DX10), textures won’t work on pre-SP3 Vista.

· Even though Bling’s retained model is based on WPF dependency properties, there is no support for anything like XAML.

· No way to host WPF content in DX10.

A download of Bling 3.1 is available on Codeplex.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: