Perspective pour Silverlight : scènes 3D dynamiques

Perspective pour Silverlight : scènes 3D dynamiques

La bibliothèque Perspective offre un framework qui permet de construire des scènes 3D au moyen de modèles géométriques prédéfinis . Dans ce tutoriel , j'ai décrit la construction statique de scènes au moyen de XAML. Je vais présenter ici la construction dynamique de scène par le code.

Une scène 3D Perspective est constituée d'un objet Scene qui définit un éclairage et un point de vue, et qui contient des modèles 3D. La scène est présentée visuellement dans un contrôle Perspective Workshop3DX.

Notre but est donc de définir un objet Scene et de générer dynamiquement son contenu, c'est à dire des modèles 3D.

Définition de l'objet Scene

L'objet Scene peut être défini en XAML ou bien être instancié par le code.

En XAML, on définit l'élément Scene au sein de l'élément Workshop3DX. Optionnellement, on précise les caractéristiques du point de vue au moyen d'un objet PerspectiveCamera assigné à la propriété Camera :

<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>

L'alternative consiste à définir l'objet Scene en C# (ce code suppose que le contrôle Workshop3DX préexiste) :

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();
}

Dans ce dernier cas, il est nécessaire d'appeler la méthode InvalidateProjection de l'objet Workshop3DX, pour ajuster le rendu de la scène aux dimensions du contrôle.

Création dynamique de modèles 3D

Une fois notre objet Scene défini, on peut lui ajouter du contenu au moyen de la méthode AddModel. Quand les différents modèles ont été ajoutés, il est nécessaire d'appeler la méthode Initialize. Voici par exemple le code C# d'instanciation d'un modèle XyzAxis :

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

Le rendu visuel étant réalisé dans un thread spécifique, il est indispensable d'utiliser la méthode Scene.AddModel, qui est thread-safe, au lieu de son alternative Scene.Models.Add, non thread-safe.

Modèle XyzAxis

La création d'un modèle plus évolué, comme la sphère ci-dessous, met en oeuvre les notions de texture, de matière et de 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;
}

Modèle Spherical

La texture est ici définie au moyen d'un objet ColorTexture, qui spécifie la couleur du modèle à partir de valeurs RGB.

La méthode privée GetMaterial renvoie un objet ModelMaterial spécifiant l'apparence de la matière du modèle (réflexion, brillance, etc.) :

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

Les transformations sont définies par la méthode privée ci-dessous, qui regroupe une mise à l'échelle (Scaling) et une 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;
}

La fonction privée GetRandomOffset définit une coordonnée aléatoire.

Le code complet de ces exemples est disponible dans la page DynamicSceneDemo.xaml du projet Perspective.Demo3D.sl5.

Voici le rendu obtenu par la création successive de modèles variés avec différents paramètres (facteurs d'échelle, couleur) choisis par l'utilisateur :

Scène dynamique

A propos de cet article

Auteur : Olivier Dewit

Historique :

  • 23 octobre 2012 : première publication.