Generieren eines 3MF-PaketsGenerate a 3MF package

Wichtige APIsImportant APIs

Dieses Handbuch beschreibt die Struktur des 3D Manufacturing Format-Dokuments und wie dieses mit der Windows.Graphics.Printing3D-API erstellt und bearbeitet werden kann.This guide describes the structure of the 3D Manufacturing Format document and how it can be created and manipulated with the Windows.Graphics.Printing3D API.

Was ist 3MF?What is 3MF?

Das 3D Manufacturing Format ist ein Satz von Konventionen für die Verwendung von XML, um die Darstellung und Struktur von 3D-Modellen zu beschreiben, die für die Fertigung eingesetzt werden (3D-Druck).The 3D Manufacturing Format is a set of conventions for using XML to describe the appearance and structure of 3D models for the purpose of manufacturing (3D printing). Es definiert einen Satz von Teilen (von denen einige erforderlich und andere optional sind) und ihre Beziehungen. Ziel dabei ist es, alle erforderlichen Informationen für ein 3D-Fertigungsgerät bereitzustellen.It defines a set of parts (some required and some optional) and their relationships, with the goal of providing all necessary information to a 3D manufacturing device. Ein Datensatz, der dem 3D Manufacturing Format entspricht, kann als Datei mit der Erweiterung „.3mf“ gespeichert werden.A data set that adheres to the 3D Manufacturing Format can be saved as a file with the .3mf extension.

In Windows 10 entspricht die Printing3D3MFPackage-Klasse im Windows.Graphics.Printing3D-Namespace einer einzelnen 3MF-Datei, und andere Klassen entsprechen den spezifischen XML-Elementen in der Datei.In Windows 10, the Printing3D3MFPackage class in the Windows.Graphics.Printing3D namespace is analogous to a single .3mf file, and other classes map to the particular XML elements in the file. In diesem Handbuch wird beschrieben, wie die einzelnen Hauptbestandteile eines 3MF-Dokuments erstellt und programmgesteuert festgelegt werden können, wie die 3MF Materials-Erweiterung genutzt werden kann und wie ein Printing3D3MFPackage-Objekt konvertiert und als 3MF-Datei gespeichert werden kann.This guide describes how each of the main parts of a 3MF document can be created and set programmatically, how the 3MF Materials Extension can be utilized, and how a Printing3D3MFPackage object can be converted and saved as a .3mf file. Weitere Informationen zu den Standards der 3MF- oder der 3MF Materials-Erweiterung finden Sie in der 3MF-Spezifikation.For more information on the standards of 3MF or the 3MF Materials Extension, see the 3MF Specification.

Hauptklassen in der 3MF-StrukturCore classes in the 3MF structure

Die Printing3D3MFPackage-Klasse stellt ein vollständiges 3MF-Dokument dar, und den Kern eines 3MF-Dokuments bildet der Modellbestandteil, der durch die Printing3DModel-Klasse dargestellt wird.The Printing3D3MFPackage class represents a complete 3MF document, and at the core of a 3MF document is its model part, represented by the Printing3DModel class. Der Großteil der Informationen, die zu einem 3D-Modell angegeben werden, werden gespeichert, indem die Eigenschaften der Printing3DModel-Klasse und die Eigenschaften der zugrunde liegenden Klassen festgelegt werden.Most of the information we wish to specify about a 3D model will be stored by setting the properties of the Printing3DModel class and the properties of their underlying classes.

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

MetadatenMetadata

Der Modellteil eines 3MF-Dokuments kann Metadaten in Form von Schlüssel-Wert-Paaren von Zeichenfolgen enthalten, die in der Metadata-Eigenschaft gespeichert sind.The model part of a 3MF document can hold metadata in the form of key/value pairs of strings stored in the Metadata property. Es gibt eine Reihe von vordefinierten Metadatennamen, aber es können weitere Paare als Teil einer Erweiterung hinzugefügt werden (dies wird in der 3MF-Spezifikation ausführlicher beschrieben).There are a number of predefined names of metadata, but other pairs can be added as part of an extension (described in more detail in the 3MF specification). Der Empfänger des Pakets (ein 3D-Fertigungsgerät) bestimmt, ob und wie Metadaten behandelt werden. Es empfiehlt sich jedoch, möglichst viele grundlegende Informationen im 3MF-Paket einzuschließen:It is up to the receiver of the package (a 3D manufacturing device) to determine whether and how to handle metadata, but it is good practice to include as much basic info as possible in the 3MF package:

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

GitterdatenMesh data

Im Kontext dieses Handbuchs bezeichnet ein Gitter einen Körper mit dreidimensionaler Geometrie, der anhand eines einzelnen Satzes von Scheitelpunkten erstellt wird (obwohl das Gitter nicht zwangsläufig als Festkörper angezeigt werden muss).In the context of this guide, a mesh is a body of 3-dimensional geometry constructed from a single set of vertices (though it does not have to appear as a single solid). Ein Gitterteil wird durch die Printing3DMesh-Klasse dargestellt.A mesh part is represented by the Printing3DMesh class. Ein gültiges Gitterobjekt muss Informationen über die Lage aller Scheitelpunkte sowie alle Dreiecksoberflächen enthalten, die zwischen bestimmten Scheitelpunktsätzen vorhanden sind.A valid mesh object must contain information about the location of all of its vertices as well as all the triangle faces that exist between certain sets of vertices.

Mit der folgenden Methode werden einem Gitter Scheitelpunkte hinzugefügt. Diesen Scheitelpunkten wird dann im 3D-Raum eine Lage zugewiesen:The following method adds vertices to a mesh and then gives them locations in 3D space:

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

Die nächste Methode definiert alle Dreiecke, die über diese Scheitelpunkte gezeichnet werden sollen:The next method defines all of the triangles to be drawn across these vertices:

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

}

Hinweis

Die Indizes aller Dreiecke müssen gegen den Uhrzeigersinn definiert werden (bei Sicht auf das Dreieck von außerhalb des Gitterobjekts), sodass ihre Oberflächennormalvektoren nach außen zeigen.All triangles must have their indices defined in counter-clockwise order (when viewing the triangle from outside of the mesh object), so that their face-normal vectors point outward.

Wenn ein Printing3DMesh-Objekt gültige Sätze von Scheitelpunkten und Dreiecken enthält, sollte es anschließend der Meshes-Eigenschaft des Modells hinzugefügt werden.When a Printing3DMesh object contains valid sets of vertices and triangles, it should then be added to the model's Meshes property. Alle Printing3DMesh-Objekte in einem Paket müssen unter der Meshes-Eigenschaft der Printing3DModel-Klasse gespeichert werden.All Printing3DMesh objects in a package must be stored under the Meshes property of the Printing3DModel class.

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

Erstellen von MaterialenCreate materials

Ein 3D-Modell kann Daten für mehrere Materialien enthalten.A 3D model can hold data for multiple materials. Diese Konvention ist für 3D-Fertigungsgeräte konzipiert, die mehrere Materialien für einen einzelnen Druckauftrag verwenden können.This convention is intended to take advantage of 3D manufacturing devices that can use multiple materials on a single print job. Es gibt auch mehrere Typen von Materialgruppen, die jeweils eine Reihe verschiedener einzelner Materialien unterstützen können.There are also multiple types of material gropus, each one capable of supporting a number of different individual materals. Jede Materialgruppe muss eine eindeutige Referenz-ID aufweisen, und jedes Material innerhalb einer Gruppe muss ebenfalls über eine eindeutige ID verfügen.Each material group must have a unique reference id number, and each material within that group must also have a unique id.

Die verschiedenen Gitterobjekte in einem Modell können dann auf diese Materialien verweisen.The different mesh objects within a model can then reference these materials. Darüber hinaus können einzelne Dreiecke in jedem Gitter unterschiedliche Materialien angeben.Furthermore, individual triangles on each mesh can specify different materials. Verschiedene Materialien können sogar innerhalb eines einzelnen Dreiecks dargestellt werden, wobei jedem Dreieckvertex ein anderes Material zugewiesen ist und das Oberflächenmaterial als der Verlauf dazwischen berechnet wird.Further still, different materials can even be represented within a single triangle, with each triangle vertex having a different material assigned to it and the face material calculated as the gradient between them.

In diesem Handbuch wird zunächst beschrieben, wie verschiedene Materialarten innerhalb ihrer jeweiligen Materialgruppen erstellt und als Ressourcen für das Modellobjekt gespeichert werden.This guide will first show how to create different kinds of materials within their respective material groups and store them as resources on the model object. Anschließend wird erläutert, wie verschiedene Materialien einzelnen Gittern und Dreiecken zugewiesen werden.Then, we will go about assigning different materials to individual meshes and individual triangles.

BasismaterialienBase materials

Der Standardmaterialtyp ist Base Material, der sowohl einen Color Material-Wert (nachfolgend beschrieben) als auch ein Namensattribut aufweist, mit dem der Typ des zu verwendenden Materials angegeben werden soll.The default material type is Base Material, which has both a Color Material value (described below) and a name attribute that is intended to specify the type of material to use.

// 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);

Hinweis

 Das 3D-Fertigungsgerät bestimmt, welche verfügbaren physischen Materialien den jeweiligen im 3MF gespeicherten virtuellen Materialelementen zugeordnet werden. The 3D manufacturing device will determine which available physical materials map to which virtual material elements stored in the 3MF. Die Materialzuordnung muss nicht 1:1 erfolgen: Wenn ein 3D-Drucker nur ein Material verwendet, wird das gesamte Modell in diesem Material gedruckt, unabhängig davon, welchen Objekten oder Oberflächen verschiedene Materialien zugeordnet wurden.Material mapping doesn't have to be 1:1: if a 3D printer only uses one material, it will print the whole model in that material, regardless of which objects or faces were assigned different materials.

FarbmaterialienColor materials

Farbmaterialien ähneln den Basismaterialien, enthalten jedoch keinen Namen.Color Materials are similar to Base Materials, but they do not contain a name. Somit enthalten sie keine Anweisungen, welche Materialart vom Gerät verwendet werden soll.Thus, they give no instructions as to what type of material should be used by the machine. Sie enthalten lediglich Farbdaten und überlassen dem Gerät die Auswahl des Materialtyps (das Gerät kann anschließend den Benutzer zur Auswahl auffordern).They hold only color data, and let the machine choose the material type (and the machine may then prompt the user to choose). Im folgenden Code werden die colrMat-Objekte aus der vorherigen Methode alleine verwendet.In the code below, the colrMat objects from the previous method are used on their own.

// 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);

Zusammengesetzte MaterialienComposite materials

Zusammengesetzte Materialien weisen das Fertigungsgerät an, eine einheitliche Mischung aus unterschiedlichen Basismaterialien zu verwenden.Composite Materials simply instruct the manufacturing device to use a uniform mixture of different Base Materials. Jede zusammengesetzte Materialgruppe muss auf genau eine Basismaterialgruppe verweisen, aus der die Bestandteile entnommen werden sollen.Each Composite Material Group must reference exactly one Base Material Group from which to draw ingredients. Zusätzlich müssen die Basismaterialien in dieser Gruppe, die verfügbar gemacht werden sollen, in einer Liste mit den Materialindizes aufgeführt werden, auf die anschließend jedes zusammengesetzte Material verweist, wenn die Verhältnisse angeben werden (jedes zusammengesetzte Material ist lediglich ein Verhältnis der Basismaterialien).Additonally, the Base Materials within this group that are to be made available must be listed out in a Material Indices list, which each Composite Material will then reference when specifying the ratios (every Composite Material is simply a ratio of Base Materials).

// 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);

TexturkoordinatenmaterialienTexture coordinate materials

3MF unterstützt die Verwendung von 2D-Bildern, um die Oberflächen von 3D-Modellen einzufärben.3MF supports the use of 2D images to color the surfaces of 3D models. Auf diese Weise kann das Modell deutlich mehr Farbdaten pro Dreiecksfläche übermitteln (als bei Verwendung eines einzelnen Farbwerts pro Dreiecksvertex).This way, the model can convey much more color data per triangle face (as opposed to having just one color value per triangle vertex). Ebenso wie Farbmaterialien können Texturkoordinatenmaterialien ausschließlich Farbdaten enthalten.Like Color Materials, texture coordinate materials only convery color data. Um eine 2D-Textur verwenden zu können, muss zunächst eine Texturressource deklariert werden:To use a 2D texture, a texture resource must first be declared:

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

Hinweis

Texturdaten gehören zum 3MF-Paket selbst und nicht zum Modellteil innerhalb des Pakets.Texture data belongs to the 3MF Package itself, not to the model part within the package.

Als Nächstes müssen die Texture3Coord-Materialien angegeben werden.Next, we must fill out Texture3Coord Materials. Jedes dieser Materialien verweist auf eine Texturressource und gibt einen bestimmten Punkt im Bild an (in UV-Koordinaten).Each of these references a texture resource and specifies a particular point on the image (in UV coordinates).

// 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);

Zuordnung von Materialien zu OberflächenMap materials to faces

Um festzulegen, welche Materialien welchen Scheitelpunkten der einzelnen Dreiecke zugeordnet werden sollen, wird noch einmal das Gitterobjekt für das Modell herangezogen (wenn ein Modell mehrere Gitter enthält, müssen die jeweiligen Materialien separat zugewiesen werden).In order to dictate which materials are mapped to which vertices on each triangle, we must do some more work on the mesh object of our model (if a model contains multiple meshes, they must each have their materials assigned separately). Wie bereits erwähnt, werden die Materialien pro Vertex, pro Dreieck zugewiesen.As mentioned above, materials are assigned per-vertex, per-triangle. Der nachfolgende Code veranschaulicht, wie diese Informationen eingegeben und interpretiert werden.Refer to the code below to see how this information is entered and interpreted.

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

Komponenten und ErstellungComponents and build

Die Komponentenstruktur ermöglicht es dem Benutzer, mehrere Gitterobjekte in einem druckbaren 3D-Modell zu platzieren.The component structure allows the user to place more than one mesh object in a printable 3D model. Ein Printing3DComponent-Objekt enthält ein einzelnes Gitter und eine Liste der Verweise auf andere Komponenten.A Printing3DComponent object contains a single mesh and a list of references to other components. Hierbei handelt es sich eigentlich um eine Liste der Printing3DComponentWithMatrix-Objekte.This is actually a list of Printing3DComponentWithMatrix objects. Printing3DComponentWithMatrix-Objekte enthalten jeweils eine Printing3DComponent und insbesondere eine Transformationsmatrix, die auf das Gitter und die enthaltenen Komponenten der Printing3DComponent angewendet wird.Printing3DComponentWithMatrix objects each contain a Printing3DComponent and, importantly, a transform matrix that applies to the mesh and contained components of said Printing3DComponent.

Das Modell eines Autos könnte zum Beispiel aus einer „Karosserie“-Printing3DComponent bestehen, die das Gitter für die Karosserie enthält.For example, a model of a car might consist of a "Body" Printing3DComponent that holds the mesh for the car's body. Die „Karosserie“-Komponente kann dann Verweise auf vier verschiedene Printing3DComponentWithMatrix-Objekte enthalten, die alle auf dieselbe Printing3DComponent mit dem Gitter „Reifen“ verweisen und vier verschiedene Transformationsmatrizen enthalten (die die Reifen vier verschiedenen Positionen an der Karosserie zuordnen).The "Body" component may then contain references to four different Printing3DComponentWithMatrix objects, which all reference the same Printing3DComponent with the "Wheel" mesh and contain four different transform matrices (mapping the wheels to four different positions on the car's body). In diesem Szenario müssen die Gitter „Karosserie“ und „Reifen“ nur jeweils einmal gespeichert werden, obwohl das endgültige Produkt insgesamt fünf Gitter umfassen würde.In this scenario, the "Body" mesh and "Wheel" mesh would each only need to be stored once, even though the final product would feature five meshes in total.

Auf alle Printing3DComponent-Objekte muss direkt in der Components-Eigenschaft des Modells verwiesen werden.All Printing3DComponent objects must be directly referenced in the model's Components property. Die spezifische Komponente, die für den Druckauftrag verwendet werden soll, wird in der Build-Eigenschaft gespeichert.The one particular component that is to be used in the printing job is stored in the Build Property.

// 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);

Speichern des PaketsSave package

Das vorliegende Modell mit den definierten Materialien und Komponenten kann nun im Paket gespeichert werden.Now that we have a model, with defined materials and components, we can save it to the package.

// 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);

Diese Funktion stellt sicher, dass die Textur ordnungsgemäß angegeben wird.This function ensures the texture is specified correctly.

/// <summary>
/// Ensure textures are saved correctly.
/// </summary>
/// <param name="modelStream">3dmodel.model data</param>
/// <returns></returns>
private async Task<IRandomAccessStream> FixTextureContentType(IRandomAccessStream modelStream) {
    XDocument xmldoc = XDocument.Load(modelStream.AsStreamForRead());

    var outputStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
    var writer = new Windows.Storage.Streams.DataWriter(outputStream);
    writer.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
    writer.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;
    writer.WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

    var text = xmldoc.ToString();
    // ensure that content type is set correctly
    // texture content can be either png or jpg
    var replacedText = text.Replace("contenttype=\"\"", "contenttype=\"image/png\"");
    writer.WriteString(replacedText);

    await writer.StoreAsync();
    await writer.FlushAsync();
    writer.DetachStream();
    return outputStream;
}

Jetzt kann ein Druckauftrag in der App gestartet (siehe 3D-Drucken in der App) oder das Printing3D3MFPackage als 3MF-Datei gespeichert werden.From here, we can either initiate a print job within the app (see 3D printing from your app), or save this Printing3D3MFPackage as a .3mf file.

Die folgende Methode akzeptiert ein fertiges Printing3D3MFPackage und speichert die Daten in einer 3MF-Datei.The following method takes a finished Printing3D3MFPackage and saves its data to a .3mf file.

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

3D-Druck über Ihre App3D printing from your app
Beispiel für 3D-Druck – UWP3D printing UWP sample