HisTech Up

Générer un package 3MF

Introduction

user

Christian Hissibini

I am a Tech enthusiast who loves to blend Dev & Design on Web and Mobile Platforms. I am also a Windows Platform Dev MVP


LATEST POSTS

What are the differences between Data Mining, Machine Learning and Deep Learning? 11th February, 2018

What are the challenges of using Artificial Intelligence? 15th January, 2018

Mobile Development

Générer un package 3MF

Posted on .

Qu’est-ce que 3MF?

3MF (3D Manufacturing Format) est un ensemble de conventions régissant la description en langage XML de l’apparence et de la structure de modèles3D à des fins de fabrication (impression 3D). Ce format définit une série de pièces (dont certaines sont requises et d’autres facultatives) et leurs relations, de façon à fournir toutes les informations nécessaires à un périphérique de fabrication 3D. Un jeu de données conforme au format 3MF peut être enregistré dans un fichier présentant l’extension.3mf.

Dans Windows10, la classe Printing3D3MFPackage de l’espace de noms Windows.Graphics.Printing3D est analogue à un fichier .3mf unique, tandis que d’autres classes sont mappées sur les différents éléments XML de ce fichier. Ce guide décrit la façon dont chacune des parties principales d’un document3MF peut être créée et définie par programmation, le mode d’utilisation de l’extension3MF Materials, ainsi que les procédures de conversion et d’enregistrement d’un objet Printing3D3MFPackage en fichier.3mf. Pour plus d’informations sur les normes3MF ou sur l’extension3MF Materials, voir la Spécification 3MF.

Classes principales de la structure 3MF

La classe Printing3D3MFPackage représente un document3MF complet, au cœur duquel se trouve la partie modèle, représentée par la classe Printing3DModel. Nous spécifierons la plupart des informations relatives au modèle3D considéré en définissant les propriétés de la classe Printing3DModel et les propriétés de leurs classes sous-jacentes.

C#
var localPackage = new Printing3D3MFPackage();
var model = new Printing3DModel();
// specify scaling units for model data
model.Unit = Printing3DModelUnit.Millimeter;

Métadonnées

La partie modèle d’un document3MF peut contenir des métadonnées sous la forme de paires de chaînes clé/valeur stockées dans la propriété Metadata. Il existe un certain nombre de noms de métadonnées prédéfinis, mais d’autres paires peuvent être ajoutées sous la forme d’une extension (décrite plus en détail dans la spécification3MF). Le destinataire du package (périphérique de fabrication3D) est chargé de déterminer si et comment les métadonnées doivent être traitées, mais il est conseillé d’inclure dans le package3MF le maximum d’informations de base:

C#
model.Metadata.Add("Title", "Cube");
model.Metadata.Add("Designer", "John Smith");
model.Metadata.Add("CreationDate", "1/1/2016");

Données de maillage

Dans le contexte de ce guide, un maillage est un corps de géométrie en 3dimensions construit à partir d’un seul ensemble de vertex (même s’il n’a pas besoin d’apparaître sous la forme d’un solide unique). Une partie maillage est représentée par la classe Printing3DMesh. Un objet de maillage valide doit contenir des informations sur l’emplacement de tous ses vertex et de toutes les faces triangulaires figurant entre certains ensembles de vertex.

La méthode suivante ajoute des vertex à un maillage et leur attribue des emplacements dans l’espace3D:

C#
private async Task GetVerticesAsync(Printing3DMesh mesh) {
    Printing3DBufferDescription description;

    description.Format = Printing3DBufferFormat.Printing3DDouble;

    // have 3 xyz values
    description.Stride = 3;

    // have 8 vertices in all in this mesh
    mesh.CreateVertexPositions(sizeof(double) * 3 * 8);
    mesh.VertexPositionsDescription = description;

    // set the locations (in 3D coordinate space) of each vertex
    using (var stream = mesh.GetVertexPositions().AsStream()) {
        double[] vertices =
        {
            0, 0, 0,
            10, 0, 0,
            0, 10, 0,
            10, 10, 0,
            0, 0, 10,
            10, 0, 10,
            0, 10, 10,
            10, 10, 10,
        };

        // convert vertex data to a byte array
        byte[] vertexData = vertices.SelectMany(v => BitConverter.GetBytes(v)).ToArray();

        // write the locations to each vertex
        await stream.WriteAsync(vertexData, 0, vertexData.Length);
    }
    // update vertex count: 8 vertices in the cube
    mesh.VertexCount = 8;
}

La méthode suivante définit tous les triangles qui doivent être dessinés entre ces sommets:

C#
private static async Task SetTriangleIndicesAsync(Printing3DMesh mesh) {

    Printing3DBufferDescription description;

    description.Format = Printing3DBufferFormat.Printing3DUInt;
    // 3 vertex indices
    description.Stride = 3;
    // 12 triangles in all in the cube
    mesh.IndexCount = 12;

    mesh.TriangleIndicesDescription = description;

    // allocate space for 12 triangles
    mesh.CreateTriangleIndices(sizeof(UInt32) * 3 * 12);

    // get a datastream of the triangle indices (should be blank at this point)
    var stream2 = mesh.GetTriangleIndices().AsStream();
    {
        // define a set of triangle indices: each row is one triangle. The values in each row
        // correspond to the index of the vertex. 
        UInt32[] indices =
        {
            1, 0, 2,
            1, 2, 3,
            0, 1, 5,
            0, 5, 4,
            1, 3, 7,
            1, 7, 5,
            2, 7, 3,
            2, 6, 7,
            0, 6, 2,
            0, 4, 6,
            6, 5, 7,
            4, 5, 6,
        };
        // convert index data to byte array
        var vertexData = indices.SelectMany(v => BitConverter.GetBytes(v)).ToArray();
        var len = vertexData.Length;
        // write index data to the triangle indices stream
        await stream2.WriteAsync(vertexData, 0, vertexData.Length);
    }

}

Note

Les index de tous les triangles doivent être définis dans le sens inverse des aiguilles d’une montre (quand on regarde le triangle à partir de l’extérieur de l’objet de maillage), afin que leurs vecteurs normaux à la face pointent sur l’extérieur.

Une fois qu’un objet Printing3DMesh contient des ensembles valides de sommets et de triangles, il doit être ajouté à la propriété Meshes du modèle. Tous les objets Printing3DMesh d’un package doivent être stockés sous la propriété Meshes de la classe Printing3DModel.

C#
// add the mesh to the model
model.Meshes.Add(mesh);

Créer des matériaux

Un modèle3D peut contenir des données concernant différents matériaux. Cette convention est destinée à tirer parti des périphériques de fabrication 3D qui peuvent utiliser plusieurs matériaux dans le cadre d’un même travail d’impression. Il existe également plusieurs types de groupe de matériaux, chacun d’eux pouvant prendre en charge un certain nombre de matériaux spécifiques. Chaque groupe de matériaux doit comporter un numéro d’identification de référence unique, et chaque matériau figurant dans un groupe doit également être doté d’un identifiant unique.

Les différents objets de maillage au sein d’un modèle peuvent alors référencer ces matériaux. En outre, les divers triangles de chaque maillage peuvent spécifier différents matériaux. Il est même possible de représenter plusieurs matériaux à l’intérieur d’un même triangle, en attribuant un matériau différent à chacun des vertex du triangle et en calculant le matériau de la face comme correspondant au gradient entre ces derniers.

Ce guide commence par expliquer comment créer différents types de matériaux au sein de leurs groupes respectifs et comment les stocker sous forme de ressources sur l’objet de modèle. Nous étudierons ensuite la procédure d’attribution de différents matériaux à des maillages et triangles spécifiques.

Matériaux de base

Le type de matériau par défaut est le type Matériau de base, qui comporte à la fois une valeur Matériau de couleur (décrite ci-après) et un attribut de nom destiné à spécifier le type de matériau à utiliser.

C#
// add material group
// all material indices need to start from 1: 0 is a reserved id
// create new base materialgroup with id = 1
var baseMaterialGroup = new Printing3DBaseMaterialGroup(1);

// create color objects
// 'A' should be 255 if alpha = 100%
var darkBlue = Windows.UI.Color.FromArgb(255, 20, 20, 90);
var orange = Windows.UI.Color.FromArgb(255, 250, 120, 45);
var teal = Windows.UI.Color.FromArgb(255, 1, 250, 200);

// create new ColorMaterials, assigning color objects
var colrMat = new Printing3DColorMaterial();
colrMat.Color = darkBlue;

var colrMat2 = new Printing3DColorMaterial();
colrMat2.Color = orange;

var colrMat3 = new Printing3DColorMaterial();
colrMat3.Color = teal;

// setup new materials using the ColorMaterial objects
// set desired material type in the Name property
var baseMaterial = new Printing3DBaseMaterial {
    Name = Printing3DBaseMaterial.Pla,
    Color = colrMat
};

var baseMaterial2 = new Printing3DBaseMaterial {
    Name = Printing3DBaseMaterial.Abs,
    Color = colrMat2
};

// add base materials to the basematerialgroup

// material group index 0
baseMaterialGroup.Bases.Add(baseMaterial);
// material group index 1
baseMaterialGroup.Bases.Add(baseMaterial2);

// add material group to the basegroups property of the model
model.Material.BaseGroups.Add(baseMaterialGroup);

Note

Le périphérique de fabrication3D détermine le mappage entre les matériaux physiques disponibles et les éléments de matériau virtuels stockés dans le fichier3MF. Le mappage des matériaux n’est pas nécessairement de type1:1. En effet, si une imprimante 3D n’utilise qu’un seul matériau, elle imprimera la totalité du modèle dans ce matériau, quels que soient les différents matériaux attribués à des objets ou faces spécifiques.

Matériaux de couleur

Les matériaux de couleur sont semblables aux matériaux de base, mais n’indiquent pas de nom. Ils ne fournissent donc aucune instruction sur le type de matériau à utiliser par le périphérique. Ils ne comportent que des données de couleur et laissent le périphérique choisir le type de matériau (le périphérique peut alors demander à l’utilisateur d’effectuer lui-même ce choix). Dans le code ci-dessous, les objets colrMat issus de la méthode précédente sont utilisés séparément.

C#
// add ColorMaterials to the Color Material Group (with id 2)
var colorGroup = new Printing3DColorMaterialGroup(2);

// add the previous ColorMaterial objects to this ColorMaterialGroup
colorGroup.Colors.Add(colrMat);
colorGroup.Colors.Add(colrMat2);
colorGroup.Colors.Add(colrMat3);

// add colorGroup to the ColorGroups property on the model
model.Material.ColorGroups.Add(colorGroup);

Matériaux composites

Les matériaux composites demandent simplement au périphérique de fabrication de combiner uniformément différents matériaux de base. Chaque groupe de matériaux composites doit référencer très précisément un groupe de matériaux de base à partir duquel les ingrédients seront dessinés. En outre, les matériaux de base au sein de ce groupe qui doivent être disponibles doivent être répertoriés dans une liste d’index de matériau, que chaque matériau composite référencera alors lors de la spécification des proportions (chaque matériau composite constitue simplement une proportion de matériaux de base).

C#
// CompositeGroups
// create new composite material group with id = 3
var compositeGroup = new Printing3DCompositeMaterialGroup(3);

// indices point to base materials in BaseMaterialGroup with id =1
compositeGroup.MaterialIndices.Add(0);
compositeGroup.MaterialIndices.Add(1);

// create new composite materials
var compMat = new Printing3DCompositeMaterial();
// fraction adds to 1.0
compMat.Values.Add(0.2); // .2 of first base material in BaseMaterialGroup 1
compMat.Values.Add(0.8); // .8 of second base material in BaseMaterialGroup 1

var compMat2 = new Printing3DCompositeMaterial();
// fraction adds to 1.0
compMat2.Values.Add(0.5);
compMat2.Values.Add(0.5);

var compMat3 = new Printing3DCompositeMaterial();
// fraction adds to 1.0
compMat3.Values.Add(0.8);
compMat3.Values.Add(0.2);

var compMat4 = new Printing3DCompositeMaterial();
// fraction adds to 1.0
compMat4.Values.Add(0.4);
compMat4.Values.Add(0.6);

// add composites to group
compositeGroup.Composites.Add(compMat);
compositeGroup.Composites.Add(compMat2);
compositeGroup.Composites.Add(compMat3);
compositeGroup.Composites.Add(compMat4);

// add group to model
model.Material.CompositeGroups.Add(compositeGroup);

Matériaux de coordonnées de texture

3MF prend en charge l’utilisation d’images 2D pour la coloration des surfaces de modèles 3D. De cette façon, le modèle peut véhiculer beaucoup plus de données de couleur par face triangulaire (plutôt qu’une seule valeur de couleur par vertex de triangle). À l’instar des matériaux de couleur, les matériaux de coordonnées de texture transmettent uniquement des données de couleur. Pour utiliser une texture2D, une ressource de texture doit d’abord être déclarée:

C#
// texture resource setup
Printing3DTextureResource texResource = new Printing3DTextureResource();
// name conveys the path within the 3MF document
texResource.Name = "/3D/Texture/msLogo.png";

// in this case, we reference texture data in the sample appx, convert it to 
// an IRandomAccessStream, and assign it as the TextureData
Uri texUri = new Uri("ms-appx:///Assets/msLogo.png");
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(texUri);
IRandomAccessStreamWithContentType iRandomAccessStreamWithContentType = await file.OpenReadAsync();
texResource.TextureData = iRandomAccessStreamWithContentType;
// add this testure resource to the 3MF Package
localPackage.Textures.Add(texResource);

// assign this texture resource to a Printing3DModelTexture
var modelTexture = new Printing3DModelTexture();
modelTexture.TextureResource = texResource;

Note

Les données de texture appartiennent au package3MF proprement dit, et non à la partie modèle du package.

Nous renseignons ensuite les matériaux Texture3Coord. Chacun d’eux référence une ressource de texture et spécifie un point spécifique sur l’image (en coordonnéesUV).

C#
// texture2Coord Group
// create new Texture2CoordMaterialGroup with id = 4
var tex2CoordGroup = new Printing3DTexture2CoordMaterialGroup(4);

// create texture materials:
// set up four tex2coordmaterial objects with four (u,v) pairs, 
// mapping to each corner of the image:

var tex2CoordMaterial = new Printing3DTexture2CoordMaterial();
tex2CoordMaterial.U = 0.0;
tex2CoordMaterial.V = 1.0;
tex2CoordGroup.Texture2Coords.Add(tex2CoordMaterial);

var tex2CoordMaterial2 = new Printing3DTexture2CoordMaterial();
tex2CoordMaterial2.U = 1.0;
tex2CoordMaterial2.V = 1.0;
tex2CoordGroup.Texture2Coords.Add(tex2CoordMaterial2);

var tex2CoordMaterial3 = new Printing3DTexture2CoordMaterial();
tex2CoordMaterial3.U = 0.0;
tex2CoordMaterial3.V = 0.0;
tex2CoordGroup.Texture2Coords.Add(tex2CoordMaterial3);

var tex2CoordMaterial4 = new Printing3DTexture2CoordMaterial();
tex2CoordMaterial4.U = 1.0;
tex2CoordMaterial4.V = 0.0;
tex2CoordGroup.Texture2Coords.Add(tex2CoordMaterial4);

// add our Printing3DModelTexture to the Texture property of the group
tex2CoordGroup.Texture = modelTexture;

// add metadata about the texture so that u,v values can be used
model.Metadata.Add("tex4", "/3D/Texture/msLogo.png");
// add group to groups on the model's material
model.Material.Texture2CoordGroups.Add(tex2CoordGroup);

Mapper des matériaux sur les faces

Afin de préciser les matériaux mappés sur les vertex de chaque triangle, nous devons effectuer quelques opérations supplémentaires sur l’objet de maillage de notre modèle (si un modèle contient plusieurs maillages, les matériaux doivent être attribués séparément à chacun d’eux). Comme indiqué précédemment, les matériaux sont attribués par vertex et par triangle. Le code ci-dessous vous indique la façon dont ces informations sont entrées et interprétées.

C#
private static async Task SetMaterialIndicesAsync(Printing3DMesh mesh) {
    // declare a description of the material indices
    Printing3DBufferDescription description;
    description.Format = Printing3DBufferFormat.Printing3DUInt;
    // 4 indices for material description per triangle
    description.Stride = 4;
    // 12 triangles total
    mesh.IndexCount = 12;
    mesh.TriangleMaterialIndicesDescription = description;

    // create space for storing this data
    mesh.CreateTriangleMaterialIndices(sizeof(UInt32) * 4 * 12);

    {
        // each row is a triangle face (in the order they were created)
        // first column is the id of the material group, last 3 columns show which material id (within that group)
        // maps to each triangle vertex (in the order they were listed when creating triangles)
        UInt32[] indices =
        {
            // base materials:
            // in  the BaseMaterialGroup (id=1), the BaseMaterial with id=0 will be applied to these triangle vertices
            1, 0, 0, 0, 
            1, 0, 0, 0,
            // color materials:
            // in the ColorMaterialGroup (id=2), the ColorMaterials with these ids will be applied to these triangle vertices
            2, 1, 1, 1,
            2, 1, 1, 1,
            2, 0, 0, 0,
            2, 0, 0, 0,
            2, 0, 1, 2,
            2, 1, 0, 2,
            // composite materials:
            // in the CompositeMaterialGroup (id=3), the CompositeMaterial with id=0 will be applied to these triangles
            3,0,0,0,
            3,0,0,0,
            // texture materials:
            // in the Texture2CoordMaterialGroup (id=4), each texture coordinate is mapped to the appropriate vertex on these
            // two adjacent triangle faces, so that the square face they create displays the original rectangular image
            4, 0, 3, 1,
            4, 2, 3, 0,
        };

        // get the current (unassigned) vertex data as a stream and write our new 'indices' data to it.
        var stream = mesh.GetTriangleMaterialIndices().AsStream();
        var vertexData = indices.SelectMany(v => BitConverter.GetBytes(v)).ToArray();
        var len = vertexData.Length;
        await stream.WriteAsync(vertexData, 0, vertexData.Length);
    }
}

Composants et builds

La structure des composants permet à l’utilisateur de placer plusieurs objets de maillage dans un modèle 3D imprimable. Un objet Printing3DComponent contient un maillage unique, ainsi qu’une liste de références à d’autres composants. Il s’agit en fait d’une liste d’objets Printing3DComponentWithMatrix. Chaque objet Printing3DComponentWithMatrix contient un élément Printing3DComponent et, plus important encore, une matrice de transformation qui s’applique au maillage et aux composants de cet élément Printing3DComponent.

Par exemple, un modèle de voiture peut être constitué d’un élément Printing3DComponent«Châssis» qui contient le maillage du châssis de la voiture. Le composant «Châssis» peut alors comporter des références à quatreobjets Printing3DComponentWithMatrix distincts, qui référencent tous le même élément Printing3DComponent avec le maillage «Roue» et contiennent quatrematrices de transformation (mappant les roues sur quatrepositions différentes du châssis de la voiture). Dans ce scénario, le maillage «Châssis» et le maillage «Roue» ne doivent être stockés qu’une seule fois, même si le produit final comporte cinq maillages au total.

Tous les objets Printing3DComponent doivent être directement référencés dans la propriété Components du modèle. Le composant à utiliser spécifiquement dans le travail d’impression est stocké dans la propriété Build.

C#
// create new component
Printing3DComponent component = new Printing3DComponent();

// assign mesh to the component's mesh
component.Mesh = mesh;

// add component to the model's list of all used components
// a model can have references to multiple components
model.Components.Add(component);

// create the transform matrix
var componentWithMatrix = new Printing3DComponentWithMatrix();
// assign component to this componentwithmatrix
componentWithMatrix.Component = component;

// create an identity matrix
var identityMatrix = Matrix4x4.Identity;

// use the identity matrix as the transform matrix (no transformation)
componentWithMatrix.Matrix = identityMatrix;

// add component to the build property.
model.Build.Components.Add(componentWithMatrix);

Enregistrer un package

Une fois que nous disposons d’un modèle dont nous avons défini les matériaux et les composants, nous pouvons l’enregistrer dans le package.

C#
// save the model to the package:
await localPackage.SaveModelToPackageAsync(model);
// get the model stream
var modelStream = localPackage.ModelPart;

// fix any textures in the model file
localPackage.ModelPart = await FixTextureContentType(modelStream);

Nous pouvons alors initialiser un travail d’impression dans l’application (voir Impression3D à partir de votre application), ou enregistrer cet objet Printing3D3MFPackage sous la forme d’un fichier.3mf.

La méthode suivante sélectionne un objet Printing3D3MFPackage finalisé et enregistre ses données dans un fichier.3mf.

C#
private async void SaveTo3mf(Printing3D3MFPackage localPackage) {

    // prompt the user to choose a location to save the file to
    FileSavePicker savePicker = new FileSavePicker();
    savePicker.DefaultFileExtension = ".3mf";
    savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
    savePicker.FileTypeChoices.Add("3MF File", new[] { ".3mf" });
    var storageFile = await savePicker.PickSaveFileAsync();
    if (storageFile == null) {
        return;
    }

    // save the 3MF Package to an IRandomAccessStream
    using (var stream = await localPackage.SaveAsync()) {
        // go to the beginning of the stream
        stream.Seek(0);

        // read from the file stream and write to a buffer
        using (var dataReader = new DataReader(stream)) {
            await dataReader.LoadAsync((uint)stream.Size);
            var buffer = dataReader.ReadBuffer((uint)stream.Size);

            // write from the buffer to the storagefile specified
            await FileIO.WriteBufferAsync(storageFile, buffer);
        }
    }
}



Ref
https://docs.microsoft.com/
profile

Christian Hissibini

I am a Tech enthusiast who loves to blend Dev & Design on Web and Mobile Platforms. I am also a Windows Platform Dev MVP

There are no comments.

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

View Comments (0) ...
Navigation