Exemplo n.º 1
0
        static ExportUtils.GroupPayload BuildGroupPayload(SceneStatePayload payload,
                                                          ExportUtils.ExportGroup exportGroup)
        {
            var group = new ExportUtils.GroupPayload();

            group.id = exportGroup.m_group == SketchGroupTag.None ? 0
                : payload.groupIdMapping.GetId(exportGroup.m_group);

            // Flattens the two-level (brush, batch) iteration to a single list of meshes
            // with heterogeneous materials.
            foreach (ExportUtils.ExportBrush brush in exportGroup.SplitByBrush())
            {
                var desc = brush.m_desc;
                foreach (var(batch, batchIndex) in brush.ToGeometryBatches().WithIndex())
                {
                    GeometryPool  geometry = batch.pool;
                    List <Stroke> strokes  = batch.strokes;

                    string legacyUniqueName     = $"{desc.m_DurableName}_{desc.m_Guid}_{group.id}_i{batchIndex}";
                    string friendlyGeometryName = $"brush_{desc.m_DurableName}_g{group.id}_b{batchIndex}";

                    UnityEngine.Profiling.Profiler.BeginSample("ConvertToMetersAndChangeBasis");
                    ExportUtils.ConvertUnitsAndChangeBasis(geometry, payload);
                    UnityEngine.Profiling.Profiler.EndSample();

                    if (payload.reverseWinding)
                    {
                        // Note: this triangle flip intentionally un-does the Unity FBX import flip.
                        ExportUtils.ReverseTriangleWinding(geometry, 1, 2);
                    }

                    if (App.PlatformConfig.EnableExportMemoryOptimization &&
                        payload.temporaryDirectory != null)
                    {
                        string filename = Path.Combine(
                            payload.temporaryDirectory,
                            legacyUniqueName + ".Gpoo");
                        geometry.MakeGeometryNotResident(filename);
                    }
                    group.brushMeshes.Add(new ExportUtils.BrushMeshPayload(
                                              payload.groupIdMapping.GetId(exportGroup.m_group))
                    {
                        legacyUniqueName = legacyUniqueName,
                        // This is the only instance of the mesh, so the node doesn't need an extra instance id
                        nodeName           = friendlyGeometryName,
                        xform              = Matrix4x4.identity,
                        geometry           = geometry,
                        geometryName       = friendlyGeometryName,
                        exportableMaterial = brush.m_desc,
                        strokes            = strokes,
                    });
                }
            }
            return(group);
        }
Exemplo n.º 2
0
        // widget.ReferenceImage must be != null
        // Never returns null
        // id is an instance id
        static ImageQuadPayload BuildImageQuadPayload(
            SceneStatePayload payload, ImageWidget widget, DynamicExportableMaterial material, int id)
        {
            string nodeName = $"image_{widget.GetExportName()}_{id}";

            // The child has no T or R but has some non-uniform S that we need to preserve.
            // I'm going to do this by baking it into the GeometryPool

            GameObject widgetChild = widget.m_ImageQuad.gameObject;
            Matrix4x4  xform       = ExportUtils.ChangeBasis(widget.transform, payload);
            Vector3    localScale  = widgetChild.transform.localScale;

            // localScale is a muddle of aspect ratio and overall size. We don't know which of x or y
            // was modified to set the aspect ratio, so get the size from z.
            if (localScale.z > 0)
            {
                float overallSize = localScale.z;
                localScale /= overallSize;
                xform       = xform * Matrix4x4.Scale(Vector3.one * overallSize);
            }

            // Create pool and bake in the leftover non-uniform scale
            GeometryPool pool = new GeometryPool();

            pool.Layout = material.VertexLayout;
            pool.Append(widgetChild.GetComponent <MeshFilter>().sharedMesh, fallbackColor: Color.white);
            pool.ApplyTransform(
                Matrix4x4.Scale(localScale), Matrix4x4.identity, 1f,
                0, pool.NumVerts);

            // Important: This transform should only be applied once, since the pools are shared, and
            // cannot include any mesh-local transformations.
            ExportUtils.ConvertUnitsAndChangeBasis(pool, payload);
            if (payload.reverseWinding)
            {
                // Note: this triangle flip intentionally un-does the Unity FBX import flip.
                ExportUtils.ReverseTriangleWinding(pool, 1, 2);
            }

            return(new ExportUtils.ImageQuadPayload(payload.groupIdMapping.GetId(widget.Group))
            {
                // because Count always increments, this is guaranteed unique even if two different images
                // have the same export name
                legacyUniqueName = $"refimage_i{payload.imageQuads.Count}",
                // We could (but don't) share the same aspect-ratio'd-quad for all instances of a refimage.
                // Since the mesh is unique to the node, it can have the same name as the node.
                geometryName = nodeName,
                nodeName = nodeName,
                xform = xform,
                geometry = pool,
                exportableMaterial = material,
            });
        }
Exemplo n.º 3
0
        // Helper for GetModelMeshPayloads() -- this is the level 4 iteration.
        // Pass:
        //   mesh / meshMaterials - the Mesh to generate geometry for
        //   payload - the payload being exported
        //   prefab - the owner "prefab"
        //   meshIndex - the index of this Mesh within its owner "prefab"
        static IEnumerable <PrefabGeometry> GetPrefabGameObjMeshes(
            Mesh mesh, Material[] meshMaterials,
            SceneStatePayload payload, Model prefab, int meshIndex)
        {
            if (meshMaterials.Length != mesh.subMeshCount)
            {
                throw new ArgumentException("meshMaterials length");
            }
            string exportName = prefab.GetExportName();

            IExportableMaterial[] exportableMaterials = meshMaterials.Select(
                mat => prefab.GetExportableMaterial(mat)).ToArray();
            VertexLayout?[] layouts = exportableMaterials.Select(iem => iem?.VertexLayout).ToArray();
            // TODO(b/142396408)
            // Is it better to write color/texcoord that we don't need, just to satisfy the layout?
            // Or should we remove color/texcoord from the layout if the Mesh doesn't have them?
            // Right now we do the former. I think the fix should probably be in the collector;
            // it shouldn't return an exportableMaterial that is a superset of what the mesh contains.
            GeometryPool[] subMeshPools = GeometryPool.FromMesh(
                mesh, layouts, fallbackColor: Color.white, useFallbackTexcoord: true);

            for (int subMeshIndex = 0; subMeshIndex < mesh.subMeshCount; subMeshIndex++)
            {
                // See if this material is a Blocks material.
                Material mat = meshMaterials[subMeshIndex];

                // At import time, ImportMaterialCollector now ensures that _every_ UnityEngine.Material
                // imported also comes with an IExportableMaterial of some kind (BrushDescriptor for
                // Blocks/TB, and DynamicExportableMaterial for everything else). This lookup shouldn't fail.
                IExportableMaterial exportableMaterial = exportableMaterials[subMeshIndex];
                if (exportableMaterial == null)
                {
                    Debug.LogWarning($"Model {prefab.HumanName} has a non-exportable material {mat.name}");
                    continue;
                }

                GeometryPool geo = subMeshPools[subMeshIndex];
                // TODO(b/140634751): lingering sanity-checking; we can probably remove this for M24
                if (geo.Layout.bUseColors)
                {
                    Debug.Assert(geo.m_Colors.Count == geo.NumVerts);
                }

                // Important: This transform should only be applied once per prefab, since the pools are
                // shared among all the instances, and cannot include any mesh-local transformations.
                // If the pools share data (which is currently impossible), then additionally
                // the transform should only be applied once to each set of vertex data.
                ExportUtils.ConvertUnitsAndChangeBasis(geo, payload);

                if (payload.reverseWinding)
                {
                    // There are many ways of reversing winding; choose the one that matches Unity's fbx flip
                    ExportUtils.ReverseTriangleWinding(geo, 1, 2);
                }

                yield return(new PrefabGeometry
                {
                    model = prefab,
                    name = exportName + "_" + meshIndex + "_" + subMeshIndex,
                    pool = geo,
                    exportableMaterial = exportableMaterial,
                });
            }
        }