// Populates glTF metadata and scene extras fields. private void SetExtras( GlTF_ScriptableExporter exporter, ExportUtils.SceneStatePayload payload) { Color skyColorA = payload.env.skyColorA; Color skyColorB = payload.env.skyColorB; Vector3 skyGradientDir = payload.env.skyGradientDir; // Scene-level extras: exporter.G.extras["TB_EnvironmentGuid"] = payload.env.guid.ToString("D"); exporter.G.extras["TB_Environment"] = payload.env.description; exporter.G.extras["TB_UseGradient"] = payload.env.useGradient ? "true" : "false"; exporter.G.extras["TB_SkyColorA"] = CommaFormattedFloatRGB(skyColorA); exporter.G.extras["TB_SkyColorB"] = CommaFormattedFloatRGB(skyColorB); Matrix4x4 exportFromUnity = AxisConvention.GetFromUnity(payload.axes); exporter.G.extras["TB_SkyGradientDirection"] = CommaFormattedVector3( exportFromUnity * skyGradientDir); exporter.G.extras["TB_FogColor"] = CommaFormattedFloatRGB(payload.env.fogColor); exporter.G.extras["TB_FogDensity"] = payload.env.fogDensity.ToString(); // TODO: remove when Poly starts using the new color data exporter.G.extras["TB_SkyColorHorizon"] = CommaFormattedFloatRGB(skyColorA); exporter.G.extras["TB_SkyColorZenith"] = CommaFormattedFloatRGB(skyColorB); }
private void WriteObjectsAndConnections(GlTF_ScriptableExporter exporter, SceneStatePayload payload) { foreach (BrushMeshPayload meshPayload in payload.groups.SelectMany(g => g.brushMeshes)) { exporter.ExportMeshPayload(payload, meshPayload, GetGroupNode(meshPayload.group)); } foreach (var sameInstance in payload.modelMeshes.GroupBy(m => (m.model, m.modelId))) { var modelMeshPayloads = sameInstance.ToList(); if (modelMeshPayloads.Count == 0) { continue; } // All of these pieces will come from the same Widget and therefore will have // the same group id, root transform, etc var first = modelMeshPayloads[0]; GlTF_Node groupNode = GetGroupNode(first.group); if (exporter.G.Gltf2) { // Non-Poly exports get a multi-level structure for meshes: transform node on top, // all the contents as direct children. string rootNodeName = $"model_{first.model.GetExportName()}_{first.modelId}"; if (modelMeshPayloads.Count == 1 && first.localXform.isIdentity) { // Condense the two levels into one; give the top-level node the same name // it would have had had it been multi-level. GlTF_Node newNode = exporter.ExportMeshPayload(payload, first, groupNode); newNode.PresentationNameOverride = rootNodeName; } else { GlTF_Node parentNode = GlTF_Node.Create( exporter.G, rootNodeName, first.parentXform, groupNode); foreach (var modelMeshPayload in modelMeshPayloads) { exporter.ExportMeshPayload(payload, modelMeshPayload, parentNode, modelMeshPayload.localXform); } } } else { // The new code's been tested with Poly and works fine, but out of // an abundance of caution, keep Poly unchanged foreach (var modelMeshPayload in modelMeshPayloads) { exporter.ExportMeshPayload(payload, modelMeshPayload, groupNode); } } } foreach (ImageQuadPayload meshPayload in payload.imageQuads) { exporter.ExportMeshPayload(payload, meshPayload, GetGroupNode(meshPayload.group)); } foreach (var(xformPayload, i) in payload.referenceThings.WithIndex()) { string uniqueName = $"empty_{xformPayload.name}_{i}"; var node = GlTF_Node.Create(exporter.G, uniqueName, xformPayload.xform, null); node.PresentationNameOverride = $"empty_{xformPayload.name}"; } }
private ExportResults ExportHelper( SceneStatePayload payload, string outputFile, bool binary, bool doExtras, int gltfVersion, bool allowHttpUri) { // TODO: Ownership of this temp directory is sloppy. // Payload and export share the same dir and we assume that the exporter: // 1. will not write files whose names conflict with payload's // 2. will clean up the entire directory when done // This works, as long as the payload isn't used for more than one export (it currently isn't) using (var exporter = new GlTF_ScriptableExporter(payload.temporaryDirectory, gltfVersion)) { exporter.AllowHttpUri = allowHttpUri; try { m_exporter = exporter; exporter.G.binary = binary; exporter.BeginExport(outputFile); exporter.SetMetadata(payload.generator, copyright: null); if (doExtras) { SetExtras(exporter, payload); } if (payload.env.skyCubemap != null) { // Add the skybox texture to the export. string texturePath = ExportUtils.GetTexturePath(payload.env.skyCubemap); string textureFilename = Path.GetFileName(texturePath); exporter.G.extras["TB_EnvironmentSkybox"] = ExportFileReference.CreateLocal(texturePath, textureFilename); } WriteObjectsAndConnections(exporter, payload); string[] exportedFiles = exporter.EndExport(); return(new ExportResults { success = true, exportedFiles = exportedFiles, numTris = exporter.NumTris }); } catch (InvalidOperationException e) { OutputWindowScript.Error("glTF export failed", e.Message); // TODO: anti-pattern. Let the exception bubble up so caller can log it properly // Actually, InvalidOperationException is now somewhat expected in experimental, since // the gltf exporter does not check IExportableMaterial.SupportsDetailedMaterialInfo. // But we still want the logging for standalone builds. Debug.LogException(e); return(new ExportResults { success = false }); } catch (IOException e) { OutputWindowScript.Error("glTF export failed", e.Message); return(new ExportResults { success = false }); } finally { payload.Destroy(); // The lifetime of ExportGlTF, GlTF_ScriptableExporter, and GlTF_Globals instances // is identical. This is solely to be pedantic. m_exporter = null; } } }