Perspective for Silverlight : dynamic 3D scenes

Perspective for Silverlight : dynamic 3D scenes

The Perspective library provides a framework that allows to build 3D scenes using predefined geometric models . In this tutorial , I described the construction of static scenes using XAML. I will present here the construction of dynamic scene by code.

A Perspective 3D scene consists of a Scene object that defines a lighting and a point of view, and that contains 3D models. The scene is presented visually in a Perspective Workshop3DX control.

So our goal is to define a Scene object and dynamically generate its content, ie 3D models.

Scene object definition

The Scene object can be defined using XAML or can be instantiated by the code.

In XAML, we define the Scene element in the Workshop3DX element. Optionally, we specify the characteristics of the point of view through a PerspectiveCamera object assigned to the Camera property:

<p:Workshop3DX 
    Name="workshop3DX"
    Grid.Row="1">
    <p:Scene>
        <p:Scene.Camera>
            <p:PerspectiveCamera 
                Position="10 2 10"
                LookTarget="0 1 0"
                FieldOfView="25"/>
        </p:Scene.Camera>
    </p:Scene>
</p:Workshop3DX>

The alternative is to define the Scene object in C # (this code assumes that the Workshop3DX control preexists):

private void CreateScene(Wpf.Controls.Workshop3DX workshop3DX)
{
    var camera = new PerspectiveCamera();
    camera.Position = new Vector3(10.0f, 2.0f, 10.0f);
    camera.LookTarget = new Vector3(0.0f, 1.0f, 0.0f);
    camera.FieldOfView = 25.0f;
    var scene = new Scene();
    scene.Camera = camera;
    workshop3DX.Scene = scene;
    workshop3DX.InvalidateProjection();
}

In the latter case, it is necessary to call the InvalidateProjection method of the object Workshop3DX, to adjust the rendering of the scene to the control dimensions.

Dynamic creation of 3D models

Once defined our scene object, we can add content using the AddModel method. When the different models have been added, it is necessary to call the Initialize method. Here is an example of C# code to instantiate an XyzAxis model:

private void AddAxisToScene(Wpf.Controls.Workshop3DX workshop3DX)
{
    var axis = new XyzAxis();
    axis.Length = 3.0f;
    workshop3DX.Scene.AddModel(axis);
    workshop3DX.Scene.Initialize();
}

The visual rendering is done in a specific thread, so it is necessary to use the Scene.AddModel method, which is thread-safe, instead of the Scene.Models.Add alternative, not thread-safe.

XyzAxis model

The creation of a more evolved model, as the sphere below, implements the notions of texture, material and transformation:

private void AddSphericalToScene(
    Wpf.Controls.Workshop3DX workshop3DX, 
    float scaleFactor,
    float r, float g, float b)
{
    var spherical = GetSpherical(scaleFactor, r, g, b);
    workshop3DX.Scene.AddModel(spherical);
    workshop3DX.Scene.Initialize();
}
private Spherical GetSpherical(float scaleFactor,
    float r, float g, float b)
{
    var spherical = new Spherical();
    spherical.ParallelCount = 80;
    spherical.Texture = new ColorTexture(r, g, b, 1.0f);
    spherical.Material = GetMaterial();
    spherical.Transform = GetScalingAndRandomTranslation(scaleFactor);
    return spherical;
}

Spherical model

The texture is defined here by a ColorTexture object that specifies the model color from RGB values.

The GetMaterial private method returns a ModelMaterial object specifying the appearance of the model material (reflection, gloss, etc.).

private ModelMaterial GetMaterial()
{
    return new ModelMaterial()
    {
        Diffuseness = 1.0f,
        Specularness = 1.0f,
        Shininess = 0.8f
    };
}

Transformations are defined by the private method below, which includes scaling and translation:

private ModelTransformGroup GetScalingAndRandomTranslation(float scaleFactor)
{
    var transformGroup = new ModelTransformGroup();
    var scaling = new Scaling(scaleFactor, scaleFactor, scaleFactor);
    transformGroup.Children.Add(scaling);
    var translation = new Translation();
    translation.OffsetX = GetRandomOffset();
    translation.OffsetY = GetRandomOffset();
    translation.OffsetZ = GetRandomOffset();
    transformGroup.Children.Add(translation);
    return transformGroup;
}

The GetRandomOffset private function defines a random coordinate.

The complete code for these examples is available in the DynamicSceneDemo.xaml page of the Perspective.Demo3D.sl5 project.

Here is the rendering obtained by the successive creation of various models with different parameters (scale factors, color) selected by the user:

Dynamic scene

About this article

Author : Olivier Dewit.

History :

  • October 24, 2012 : 1st publication.