| WPF lights in Viewport3D |
| Section: WPF | Rating: Not rated yet! |
 | CodeGod submitted this resource The member's homepage is http://www.codegod.de Visit the profile here |
Attachment
Introduction
WPF offers some nice possibilities to display 3D graphics in a ViewPort3D-area. In this article the author explains how to use different kind of lights on a 3D-model: AmbientLight, DirectionalLight, PointLight and Spotlight.
Figure 1The concept
For illuminating objects in a 3D model you can use different kind of lights (Ambient-, Directional-, Point- and Spotlight)
AmbientLight
This type of light shines on every object in the scene no matter where it is located. The only parameter you can use for this light is the color.
DirectionalLight
This light shines in the direction you specify. The source of the light is defined by the camera's position.
PointLight
This is a light that shines like a lamp from a certain point in the model.
SpotLight
The Spotlight is a combination of a DirectionalLight and a PointLight with some special parameters: It has a point (source) in the model, it shines into the direction you specify and it has an InnerConeAngle- and an OuterConeAngle-property. The inner cone is a hard light, the outer cone is a fading light.
The way in which the light is reflected is determined by the material we apply for the objects. There is emissive material, specular material and diffuse material. The diffuse material doesn't reflect any light, the specular one reflects light so that the surface of the illuminated object appears glossy and the emissive material reflects the light that you defined with the color of your brush.
The Project
In our project we defined a pyramid as the 3D-object to be illuminated. Below the scene we defined 3 light-types which can be combined: AmbientLight, DirectionalLight and PointLight:
Figure 2When playing with the colors and enabled-states you will get the idea how the different lights in WPF work together.
XAML and Code
Here is the XAML for the viewport in which the pyramid is defined:
<Viewport3D Grid.Row="0">
<Viewport3D.Camera>
<PerspectiveCamera Position="-3,1,8" LookDirection="3,-1,-8"
UpDirection="0,1,0" FieldOfView="45"
NearPlaneDistance="0.15" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup x:Name="group3D">
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="0,1,0 1,-1,1 -1,-1,1 1,-1,1 -1,-1,-1"
Normals="0,1,0 -1,0,1 1,0,1 -1,0,-1 1,0,-1"
TriangleIndices="0,2,1 0,3,1 0,3,4 0,2,4" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial Brush="Aqua" />
</GeometryModel3D.Material>
<GeometryModel3D.BackMaterial>
<DiffuseMaterial Brush="LightBlue"/>
</GeometryModel3D.BackMaterial>
</GeometryModel3D>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
In this sample we used a diffuse matrial to keep it simple, but in the next tutorial we will cover the subject Materials in 3D graphics with WPF more deeply. Instead of using diffuse material here we could also define a MaterialGroup for Material and BackMaterial and combine emissive, diffuse and specular materials.
As you can see we have no lights defined. We will add this by code to the Model3DGroup group3D.
To set the colors of the lights and the enabled-states for it, we created this small UserControl:
<UserControl x:Class="WpfLights.LigthtParamControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="100" Width="300">
<StackPanel HorizontalAlignment="Left">
<CheckBox Margin="5,0,0,5" x:Name="cbEnabled" Content="Enabled"
Unchecked="cbEnabled_Unchecked" Checked="cbEnabled_Checked" />
<Grid Margin="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="80"/>
</Grid.RowDefinitions>
<StackPanel VerticalAlignment="Top" Grid.Column="0">
<Label Content="Red"/>
<Slider Margin="5" Minimum="0" Maximum="255"
x:Name="slRed" ValueChanged="slRed_ValueChanged" />
</StackPanel>
<StackPanel VerticalAlignment="Top" Grid.Column="1">
<Label Content="Green"/>
<Slider Margin="5" Minimum="0" Maximum="255"
x:Name="slGreen" ValueChanged="slGreen_ValueChanged" />
</StackPanel>
<StackPanel VerticalAlignment="Top" Grid.Column="2">
<Label Content="Blue"/>
<Slider Margin="5" Minimum="0" Maximum="255"
x:Name="slBlue" ValueChanged="slBlue_ValueChanged" />
</StackPanel>
</Grid>
</StackPanel>
</UserControl>
A LigthtParamControl has a property for the Model3DGroup and the Light. When changing values by maniplating the CheckBox or the silders, the light's and group's values are updated:
private Light _light;
private Model3DGroup _group;
private void cbEnabled_Unchecked(object sender,
RoutedEventArgs e)
{
SetEnabled( );
}
private void SetEnabled()
{
if (cbEnabled.IsChecked == true)
{
_group.Children.Add(_light);
}
else
{
_group.Children.Remove(_light);
}
}
private void slBlue_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
_light.Color = Color.FromRgb(_light.Color.R,
_light.Color.G, (byte)e.NewValue);
}
In the main window we have 3 TabItems on a TabControl, each of them holds a LightParamControl-instance. This is how the XAML for one TabItem looks like:
<TabItem>
<TabItem.Header>
<TextBlock Text="AmbientLight"/>
</TabItem.Header>
<local:LigthtParamControl x:Name="lightAmb" HorizontalAlignment="Left">
</local:LigthtParamControl>
</TabItem>
Using our LightParamControl, the initialization for the lights is very simple:
public WinMain()
{
InitializeComponent();
lightAmb.LightSource = new AmbientLight(Color.FromRgb(100, 100, 100));
lightAmb.Group = group3D;
lightAmb.Enabled = true;
lightDir.LightSource = new DirectionalLight(Color.FromRgb(255, 255, 255),
new Vector3D( 2,-1,-1 ));
lightDir.Group = group3D;
lightDir.Enabled = true;
lightPoint.LightSource = new PointLight(Color.FromRgb(255, 255, 255),
new Point3D(8, -5, -5));
lightPoint.Group = group3D;
lightPoint.Enabled = false;
}
There are some hard-coded paramaters in here, feel free to enhance the example as you like. The project for VS 2008 Beta2 is attach... have fun!