Gerar um pacote 3MFGenerate a 3MF package

APIs importantesImportant APIs

Este guia descreve a estrutura do tipo de arquivo de Formato de Manufatura 3D e como ele pode ser criado e manipulado com a API Windows.Graphics.Printing3D.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.

O que é 3MF?What is 3MF?

O Formato de Manufatura 3D é um conjunto de convenções para usar XML para descrever a aparência e a estrutura de modelos 3D para fins de fabricação (impressão em 3D).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). Ele define um conjunto de partes (algumas necessárias e outras opcionais) e suas relações, com o objetivo de fornecer todas as informações necessárias a um dispositivo de fabricação 3D.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. Um conjunto de dados que segue o Formato de Manufatura 3D pode ser salvo como um arquivo com a extensão .3mf.A data set that adheres to the 3D Manufacturing Format can be saved as a file with the .3mf extension.

No Windows 10, a classe Printing3D3MFPackage no namespace Windows.Graphics.Printing3D é análoga a um arquivo único .3mf e outras classes são mapeadas para os elementos XML específicos no arquivo.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. Este guia descreve como cada uma das partes principais de um documento 3MF pode ser criada e definida de forma programática, como a Extensão de Materiais 3MF pode ser utilizada e como um objeto Printing3D3MFPackage pode ser convertido e salvo como um arquivo .3mf.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. Para saber mais sobre os padrões de 3MF ou a Extensão de Materiais 3MF, consulte a Especificação 3MF.For more information on the standards of 3MF or the 3MF Materials Extension, see the 3MF Specification.

Classes principais na estrutura 3MFCore classes in the 3MF structure

A classe Printing3D3MFPackage representa um documento 3MF completo, e no núcleo de um documento 3MF está sua parte do modelo, representada pela classe Printing3DModel.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. A maioria das informações que desejamos especificar sobre um modelo 3D será armazenada por meio da definição das propriedades da classe Printing3DModel e das propriedades das classes subjacentes.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;

MetadadosMetadata

A parte do modelo de documento 3MF pode conter metadados na forma de pares de chave/valor de cadeias de caracteres armazenadas na propriedade Metadados.The model part of a 3MF document can hold metadata in the form of key/value pairs of strings stored in the Metadata property. Há um número de nomes de metadados predefinidos, mas outros pares podem ser adicionados como parte de uma extensão (descrito mais detalhadamente em Especificação 3MF).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). Fica a cargo do receptor do pacote (um dispositivo de fabricação 3D) determinar se e como lidar com metadados, mas é uma prática recomendada incluir o máximo de informações básicas possível no pacote 3MF: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");

Dados de malhaMesh data

No contexto deste guia, uma malha é um corpo de geometria tridimensional construído a partir de um único conjunto de vértices (embora ela não tenha que aparecer como um sólido único).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). Uma parte de malha é representada pela classe Printing3DMesh.A mesh part is represented by the Printing3DMesh class. Um objeto de malha válido deve conter informações sobre a localização de todos os seus vértices, bem como todas as faces de triângulo que existem entre determinados conjuntos de vértices.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.

O método a seguir adiciona vértices a uma malha e dá a eles locais no espaço 3D: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;
}

O próximo método define todos os triângulos a serem desenhados nesses vértices: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);
    }

}

Observação

Todos os triângulos devem ter seus índices definidos no sentido anti-horário (ao exibir o triângulo fora do objeto de malha), para que seus vetores de face normal apontem para fora.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.

Quando um objeto Printing3DMesh contém conjuntos de vértices e triângulos válidos, ele deve ser adicionado à propriedade Malhas do modelo.When a Printing3DMesh object contains valid sets of vertices and triangles, it should then be added to the model's Meshes property. Todos os objetos Printing3DMesh em um pacote devem ser armazenados na propriedade Malhas da classe Printing3DModel.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);

Criar materiaisCreate materials

Um modelo 3D pode armazenar dados de vários materiais.A 3D model can hold data for multiple materials. Essa convenção destina-se a tirar proveito dos dispositivos de fabricação 3D que podem usar vários materiais em uma única tarefa de impressão.This convention is intended to take advantage of 3D manufacturing devices that can use multiple materials on a single print job. Há também vários tipos de grupos de materiais, cada um capaz de oferecer suporte a um número de materiais individuais diferentes.There are also multiple types of material gropus, each one capable of supporting a number of different individual materals. Cada grupo de material deve ter um número de id de referência exclusivo, e cada material desse grupo também deve ter uma id exclusiva.Each material group must have a unique reference id number, and each material within that group must also have a unique id.

Os diferentes objetos de malha dentro de um modelo podem fazer referência a esses materiais.The different mesh objects within a model can then reference these materials. Além disso, triângulos individuais em cada malha podem especificar diferentes materiais.Furthermore, individual triangles on each mesh can specify different materials. E mais, materiais diferentes podem ser representados dentro de um triângulo único, com cada vértice do triângulo tendo um material diferente atribuído a ele e o material de face calculado como o gradiente entre eles.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.

Este guia mostrará primeiramente como criar diferentes tipos de materiais dentro de seus respectivos grupos de materiais e armazená-los como recursos no objeto de modelo.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. Em seguida, atribuiremos materiais diferentes a malhas individuais e triângulos individuais.Then, we will go about assigning different materials to individual meshes and individual triangles.

Materiais de baseBase materials

O tipo de material padrão é Material de base, que tem tanto um valor de Material de cor (descrito abaixo) quanto um atributo de nome que se destina a especificar o tipo de material a ser usado.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);

Observação

 O dispositivo de fabricação 3D determinará quais materiais físicos disponíveis serão mapeados para quais elementos de materiais virtuais armazenados no 3MF. The 3D manufacturing device will determine which available physical materials map to which virtual material elements stored in the 3MF. Não é necessário que o mapeamento de material seja 1:1: se uma impressora 3D usa apenas um material, ela imprimirá todo o modelo nesse material, independentemente de quais objetos ou faces sejam atribuídos a materiais diferentes.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.

Materiais de coresColor materials

Materiais de cor são semelhantes aos Materiais de base, mas eles não contêm um nome.Color Materials are similar to Base Materials, but they do not contain a name. Assim, não dão nenhuma instrução sobre que tipo de material deve ser usado pela máquina.Thus, they give no instructions as to what type of material should be used by the machine. Eles contêm apenas dados de cor e permitem que a máquina escolha o tipo de material (e a máquina pode solicitar que o usuário escolha).They hold only color data, and let the machine choose the material type (and the machine may then prompt the user to choose). No código a seguir, os objetos colrMat do método anterior são usados de forma isolada.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);

Materiais de composiçãoComposite materials

Materiais de composição simplesmente instruem o dispositivo de fabricação a usar uma mistura uniforme de diferentes Materiais de base.Composite Materials simply instruct the manufacturing device to use a uniform mixture of different Base Materials. Cada Grupo de Material de Composição deve fazer referência a exatamente um Grupo de Material de Base do qual retira ingredientes.Each Composite Material Group must reference exactly one Base Material Group from which to draw ingredients. Além disso, os Materiais de base dentro desse grupo que serão disponibilizados devem estar em uma lista de Índices de Materiais, na qual cada Material de composição fará referência ao especificar as proporções (cada Material de composição é simplesmente uma proporção de Materiais de Base).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);

Materiais de coordenadas de texturaTexture coordinate materials

3MF dá suporte ao uso de imagens 2D para colorir as superfícies de modelos 3D.3MF supports the use of 2D images to color the surfaces of 3D models. Dessa forma, o modelo pode transmitir muito mais dados de cor por face de triângulo (ao contrário de ter apenas um valor de cor por vértice de triângulo).This way, the model can convey much more color data per triangle face (as opposed to having just one color value per triangle vertex). Semelhante a Materiais de cor, materiais de coordenadas de textura transmitem apenas dados de cor.Like Color Materials, texture coordinate materials only convery color data. Para usar uma textura 2D, um recurso de textura deve ser declarado primeiramente: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;

Observação

Os dados de textura pertencem ao pacote 3MF em si, não à parte do modelo dentro do pacote.Texture data belongs to the 3MF Package itself, not to the model part within the package.

Em seguida, devemos preencher Materiais Texture3Coord.Next, we must fill out Texture3Coord Materials. Cada um deles faz referência a um recurso de textura e especifica um ponto em particular na imagem (em coordenadas UV).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);

Mapear materiais para facesMap materials to faces

Para ditar quais materiais são mapeados para quais vértices em cada triângulo, precisamos trabalhar um pouco mais no objeto de malha do nosso modelo (se um modelo contiver várias malhas, cada uma delas deve ter seus materiais atribuídos separadamente).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). Conforme mencionado acima, materiais são atribuídos por vértice, por triângulo.As mentioned above, materials are assigned per-vertex, per-triangle. Consulte o código a seguir para ver como essas informações são inseridas e interpretadas.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);
    }
}

Componentes e compilaçãoComponents and build

A estrutura do componente permite que o usuário coloque mais de um objeto de malha em um modelo 3D imprimível.The component structure allows the user to place more than one mesh object in a printable 3D model. O objeto Printing3DComponent contém uma única malha e uma lista de referências a outros componentes.A Printing3DComponent object contains a single mesh and a list of references to other components. Isso é realmente uma lista de objetos Printing3DComponentWithMatrix.This is actually a list of Printing3DComponentWithMatrix objects. Cada um dos objetos Printing3DComponentWithMatrix contém um Printing3DComponent e, principalmente, uma matriz de transformação que é aplicável à malha e componentes contidos do dito Printing3DComponent.Printing3DComponentWithMatrix objects each contain a Printing3DComponent and, importantly, a transform matrix that applies to the mesh and contained components of said Printing3DComponent.

Por exemplo, um modelo de um carro pode consistir em um "Corpo" Printing3DComponent que mantém a malha para o corpo do carro.For example, a model of a car might consist of a "Body" Printing3DComponent that holds the mesh for the car's body. O componente "Corpo" pode conter referências a quatro objetos Printing3DComponentWithMatrix diferentes, que fazem referência ao mesmo Printing3DComponent com a malha "Roda" e conter quatro matrizes de transformação diferente (mapeando as rodas para quatro posições diferentes no corpo do carro).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). Nesse cenário, a malha "Corpo" e a malha "Roda" só precisariam ser armazenadas uma vez, embora o produto final apresentasse cinco malhas no total.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.

Todos os objetos Printing3DComponent devem fazer referência diretamente na propriedade Componentes do modelo.All Printing3DComponent objects must be directly referenced in the model's Components property. Um componente específico a ser usado no trabalho de impressão é armazenado na propriedade Compilar.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);

Salvar um pacoteSave package

Agora que temos um modelo, com materiais definidos e componentes, podemos salvá-lo no pacote.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);

Essa função garante que a textura seja especificada corretamente.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;
}

Daqui, podemos iniciar um trabalho de impressão dentro do aplicativo (veja Impressão 3D a do seu aplicativo) ou salvar esse Printing3D3MFPackage como um arquivo .3mf.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.

O método a seguir pega um Printing3D3MFPackage concluído e salva os dados em um arquivo .3mf.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);
        }
    }
}

Impressão 3D a partir de seu aplicativo3D printing from your app
Exemplo UWP de impressão 3D3D printing UWP sample