Пример #1
0
        // Copy a 4-channel texcoord into 2 2-channel texcoords.
        // If the source isn't 4-channel, one or both lists may be left empty.
        static void DemuxTexcoord(GeometryPool pool, int uvSize, GeometryPool.TexcoordData texcoordData,
                                  out List <Vector2> destXy, out List <Vector2> destZw)
        {
            destXy = null;
            destZw = null;
            switch (uvSize)
            {
            case 0:
                break;

            case 2:
                destXy = texcoordData.v2;
                break;

            case 3:
                destXy = new List <Vector2>(texcoordData.v3.Select(v3 => new Vector2(v3.x, v3.y)));
                destZw = new List <Vector2>(texcoordData.v3.Select(v3 => new Vector2(v3.z, 0)));
                break;

            case 4:
                destXy = new List <Vector2>(texcoordData.v4.Select(v4 => new Vector2(v4.x, v4.y)));
                destZw = new List <Vector2>(texcoordData.v4.Select(v4 => new Vector2(v4.z, v4.w)));
                break;

            default:
                Debug.Assert(false);
                break;
            }
        }
Пример #2
0
 private static void AppendTriangle(ref StringBuilder buffer, GeometryPool pool,
                                    int j, int chunkStartingVertex) {
   buffer.Append("\t\t\t"  + (pool.m_Tris[j + 0] - chunkStartingVertex) + " "
                           + (pool.m_Tris[j + 1] - chunkStartingVertex) + " "
                           + (pool.m_Tris[j + 2] - chunkStartingVertex) + " "
                           + "-1,\n");
 }
Пример #3
0
            // If geometry does not contain normals, colors, and/or uvs, dummy values
            // will be added.
            public ExportMesh(GeometryPool pool)
            {
                m_pool = pool;
                FbxUtils.ApplyFbxTexcoordHack(m_pool);
                m_linearColor = ExportUtils.ConvertToLinearColorspace(m_pool.m_Colors);

                var layout   = m_pool.Layout;
                var numVerts = m_pool.m_Vertices.Count;

                // TODO: all this padding code seems super bogus; try to remove.
                if (!layout.bUseNormals)
                {
                    var lst = m_pool.m_Normals;
                    lst.SetCount(numVerts);
                    for (int i = 0; i < numVerts; ++i)
                    {
                        lst[i] = Vector3.up;
                    }
                }

                if (!layout.bUseColors)
                {
                    var lst = m_linearColor;
                    lst.SetCount(numVerts);
                    for (int i = 0; i < numVerts; ++i)
                    {
                        lst[i] = Color.white;
                    }
                }
            }
Пример #4
0
        /// Destroys the batch and all resources+objects owned by it.
        /// The batch is no longer usable after this.
        public void Destroy()
        {
            m_ParentPool = null;

            // Writing a BatchSubset.Destroy() wouldn't be worth it; there's nothing really to destroy
            foreach (var subset in m_Groups)
            {
                subset.m_ParentBatch = null;
            }
            m_Groups = null;

            // Don't bother with mesh.Clear() since we're about to destroy it.
            // m_MeshFilter.mesh.Clear();

            // Don't bother with m_Geometry.Reset(). Internally it uses List<>.Clear()
            // which wastes time zeroing out the list entries. That's wasted work since
            // we're going to garbage the whole thing.
            // m_Geometry.Reset();

            // I don't think we want to do this until GeometryPool.Free() is smart enough
            // to limit the number of instances on the freelist.
            // GeometryPool.Free(m_Geometry);
            m_Geometry.Destroy();
            m_Geometry = null;

            Destroy(m_InstantiatedMaterial);

            Destroy(m_MeshFilter.mesh);
            m_MeshFilter = null;
            Destroy(gameObject);
        }
Пример #5
0
        public void TestLayoutAssignmentAndReset()
        {
            var pool = new GeometryPool {
                Layout = new VertexLayout {
                    texcoord0 = new TexcoordInfo {
                        size = 2
                    },
                    texcoord1 = new TexcoordInfo {
                        size = 3
                    },
                    texcoord2 = new TexcoordInfo {
                        size = 4
                    },
                }
            };

            Assert.IsNotNull(pool.m_Texcoord0.v2);
            Assert.IsNotNull(pool.m_Texcoord1.v3);
            Assert.IsNotNull(pool.m_Texcoord2.v4);

            int N = 30;

            pool.m_Texcoord0.v2.AddRange(MathTestUtils.RandomVector2List(N));
            pool.m_Texcoord1.v3.AddRange(MathTestUtils.RandomVector3List(N));
            pool.m_Texcoord2.v4.AddRange(MathTestUtils.RandomVector4List(N));
            pool.Reset();
            Assert.AreEqual(0, pool.m_Texcoord0.v2.Count);
            Assert.AreEqual(0, pool.m_Texcoord1.v3.Count);
            Assert.AreEqual(0, pool.m_Texcoord2.v4.Count);
        }
Пример #6
0
        /// Creates and returns a new subset containing the passed geometry.
        /// Pass:
        ///   brush - Selects the material/batch
        ///   nVerts - Amount to copy from the MasterBrush
        public BatchSubset CreateSubset(BrushDescriptor brush, GeometryPool geometry)
        {
            var pool  = GetPool(brush);
            var batch = GetBatch(pool, geometry.NumVerts);

            return(batch.AddSubset(geometry));
        }
Пример #7
0
        private static void ConvertScaleAndChangeBasis(
            GeometryPool pool,
            float unitChange,
            Matrix4x4 basisChange)
        {
            // If there's translation, it's ambiguous whether scale is applied before or after
            // (probably the user means after, but still)
            Debug.Assert((Vector3)basisChange.GetColumn(3) == Vector3.zero);
            Matrix4x4 basisAndUnitChange = Matrix4x4.Scale(unitChange * Vector3.one) * basisChange;

#if false // this code is pendantic but is useful to describe what's _really_ going on here
            // xfBivector is the transform to use for normals, tangents, and other cross-products.
            // Extracting rotation from a mat4 is hard, so take advantage of the fact that basisChange
            // is a (maybe improper) rotation, an improper rotation being a rotation with scale -1.
            // Matrix4x4 xfBivector = ExtractRotation(basisAndUnitChange);
            Matrix4x4 xfBivector = basisChange;
            if (basisChange.determinant < 0)
            {
                // remove the -1 uniform scale by giving it yet more -1 uniform scale.
                xfBivector = Matrix4x4.Scale(-Vector3.one) * xfBivector;
            }

            // The exporter flips triangle winding when handedness flips, but it leaves the job unfinished;
            // it needs to also flip the normals and tangents, since they're calculated from cross products.
            // Detect that and kludge in an extra -1 scale to finish the job.
            if (basisChange.determinant < 0)
            {
                xfBivector = Matrix4x4.Scale(-Vector3.one) * xfBivector;
            }
#else
            Matrix4x4 xfBivector = basisChange; // The mirroring and the winding-flip cancel each other out
#endif
            pool.ApplyTransform(basisAndUnitChange, xfBivector, unitChange, 0, pool.NumVerts);
        }
Пример #8
0
        protected override void InitBrush(BrushDescriptor desc, TrTransform localPointerXf)
        {
            base.InitBrush(desc, localPointerXf);
            m_bM11Compatibility = desc.m_M11Compatibility;
            m_geometry          = GeometryPool.Allocate();

            m_knots.Clear();
            Vector3    pos  = localPointerXf.translation;
            Quaternion ori  = localPointerXf.rotation;
            Knot       knot = new Knot {
                point = new PointerManager.ControlPoint {
                    m_Pos = pos, m_Orient = ori, m_Pressure = 1
                },
                length      = 0,
                smoothedPos = pos
            };

            m_knots.Add(knot);
            m_knots.Add(knot);

            MeshFilter mf = GetComponent <MeshFilter>();

            mf.mesh = null; // Force a new, empty, mf-owned mesh to be generated
            mf.mesh.MarkDynamic();
        }
Пример #9
0
        // Move normals into texcoord1, clearing normals and overwriting texcoord1
        // (which may have data, but it's assumed not to be useful for the export)
        public static void ApplyFbxTexcoordHack(GeometryPool pool)
        {
            var layout = pool.Layout;

            if (!layout.bFbxExportNormalAsTexcoord1)
            {
                return;
            }

            // Fix up the layout
            layout.bFbxExportNormalAsTexcoord1 = false;
            // Should uv1Semantic be "Vector"? Or "Unspecified"? This case currently
            // does not come up, but guard for it when/if it does.
            Debug.Assert(layout.normalSemantic != GeometryPool.Semantic.Unspecified,
                         "Ambiguous normalSemantic");
            layout.texcoord1.semantic = layout.normalSemantic;
            layout.texcoord1.size     = 3;
            layout.bUseNormals        = false;
            layout.normalSemantic     = GeometryPool.Semantic.Unspecified;
            pool.Layout = layout;

            // Swap m_Normals <-> m_UvSet1.v3
            var tmp = pool.m_Normals;

            pool.m_Normals      = pool.m_Texcoord1.v3;
            pool.m_Texcoord1.v3 = tmp;
            pool.m_Normals.Clear();
        }
Пример #10
0
        private static void AssertAreEqual(GeometryPool expected, GeometryPool actual)
        {
            string why   = "";
            bool   equal = AreEqual(expected, actual, ref why);

            Assert.AreEqual("", why);
            Assert.IsTrue(equal);
        }
Пример #11
0
 // Danger! This destroys resources shared by the entire SceneStatePayload.
 // It is only public so it can be called during SceneStatePayload shutdown.
 public void Destroy()
 {
     if (geometry != null)
     {
         geometry.Destroy();
         geometry = null;
     }
 }
Пример #12
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);
        }
Пример #13
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,
            });
        }
    // Doesn't do material export; for that see ExportMeshPayload
    private GlTF_Node ExportMeshPayload_NoMaterial(
        BaseMeshPayload mesh,
        [CanBeNull] GlTF_Node parent,
        Matrix4x4?localXf = null)
    {
        ObjectName   meshNameAndId = new ObjectName(mesh.legacyUniqueName);
        GeometryPool pool          = mesh.geometry;
        Matrix4x4    xf            = localXf ?? mesh.xform;
        // Create a Node and (usually) a Mesh, both named after meshNameAndId.
        // This is safe because the namespaces for Node and Mesh are distinct.
        // If we have already seen the GeometryPool, the Mesh will be reused.
        // In this (less common) case, the Node and Mesh will have different names.

        // We don't actually ever use the "VERTEXID" attribute, even in gltf1.
        // It's time to cut it away.
        // Also, in gltf2, it needs to be called _VERTEXID anyway since it's a custom attribute
        GlTF_VertexLayout gltfLayout = new GlTF_VertexLayout(G, pool.Layout);

        int numTris = pool.NumTriIndices / 3;

        if (numTris < 1)
        {
            return(null);
        }

        NumTris += numTris;

        GlTF_Mesh gltfMesh;

        // Share meshes for any repeated geometry pool.
        if (!m_meshCache.TryGetValue(pool, out gltfMesh))
        {
            gltfMesh      = new GlTF_Mesh(G);
            gltfMesh.name = GlTF_Mesh.GetNameFromObject(meshNameAndId);
            gltfMesh.PresentationNameOverride = mesh.geometryName;
            m_meshCache.Add(pool, gltfMesh);

            // Populate mesh data only once.
            AddMeshDependencies(meshNameAndId, mesh.exportableMaterial, gltfMesh, gltfLayout);
            gltfMesh.Populate(pool);
            G.meshes.Add(gltfMesh);
        }

        // The mesh may or may not be shared, but every mesh will have a distinct node to allow them
        // to have unique transforms.
        GlTF_Node node = GlTF_Node.GetOrCreate(G, meshNameAndId, xf, parent, out _);

        node.m_mesh = gltfMesh;
        node.PresentationNameOverride = mesh.nodeName;
        return(node);
    }
Пример #15
0
        override public void FinalizeSolitaryBrush()
        {
            var mesh = GetComponent <MeshFilter>().mesh;

            m_geometry.CopyToMesh(mesh);

            m_CachedNumVerts = NumVerts;
            m_CachedNumTris  = NumTris;

            GeometryPool.Free(m_geometry);
            m_geometry = null;

            mesh.RecalculateBounds();
        }
Пример #16
0
        static void WriteStroke(JsonWriter json, Stroke stroke,
                                Dictionary <Guid, int> brushMap)
        {
            json.WriteStartObject();

            var             brushGuid = stroke.m_BrushGuid;
            BrushDescriptor desc      = BrushCatalog.m_Instance.GetBrush(brushGuid);
            int             brushIndex;

            if (!brushMap.TryGetValue(brushGuid, out brushIndex))
            {
                brushIndex          = brushMap.Count;
                brushMap[brushGuid] = brushIndex;
            }

            json.WritePropertyName("brush");
            json.WriteValue(brushIndex);

            if (stroke.m_Type == Stroke.Type.BrushStroke)
            {
                // Some strokes (eg particles) don't have meshes. For now, assume that
                // if the stroke has a mesh, it should be written.
                var meshFilter = stroke.m_Object.GetComponent <MeshFilter>();
                if (meshFilter != null)
                {
                    var mesh = meshFilter.sharedMesh;
                    if (mesh != null)
                    {
                        WriteMesh(json, mesh, desc.VertexLayout);
                    }
                }
            }
            else if (stroke.m_Type == Stroke.Type.BatchedBrushStroke)
            {
                BatchSubset  subset = stroke.m_BatchSubset;
                GeometryPool geom   = subset.m_ParentBatch.Geometry;

                Mesh tempMesh = new Mesh();
                geom.CopyToMesh(tempMesh,
                                subset.m_StartVertIndex, subset.m_VertLength,
                                subset.m_iTriIndex, subset.m_nTriIndex);
                WriteMesh(json, tempMesh, geom.Layout);
                tempMesh.Clear();
                UnityEngine.Object.Destroy(tempMesh);
            }

            json.WriteEndObject();
        }
Пример #17
0
        /// Converts a GeometryPool into a MeshSample.
        static void GetMeshSample(GeometryPool geomPool,
                                  Matrix4x4 mat44,
                                  MeshSample sample)
        {
            var vertexLayout = geomPool.Layout;

            // Used for shader binding.
            sample.doubleSided       = true;
            sample.orientation       = USD.NET.Orientation.LeftHanded;
            sample.points            = geomPool.m_Vertices.ToArray();
            sample.faceVertexIndices = geomPool.m_Tris.ToArray();
            sample.transform         = mat44;

            sample.extent = new Bounds(sample.points[0], Vector3.zero);
            for (int i = 0; i < sample.points.Length; i++)
            {
                sample.extent.Encapsulate(sample.points[i]);
            }

            // Yuck. Perhaps push this down to a lower layer.
            sample.faceVertexCounts = new int[sample.faceVertexIndices.Length / 3];
            for (int i = 0; i < sample.faceVertexCounts.Length; i++)
            {
                sample.faceVertexCounts[i] = 3;
            }

            if (vertexLayout.bUseNormals)
            {
                sample.normals = geomPool.m_Normals.ToArray();
            }

            if (vertexLayout.bUseTangents)
            {
                sample.tangents = geomPool.m_Tangents.ToArray();
            }

            if (vertexLayout.bUseColors)
            {
                sample.colors = geomPool.m_Colors.Select(
                    c => (new Color(c.r, c.g, c.b, c.a) / 255.0f).linear).ToArray();
            }

            sample.uv  = GetUv(0, vertexLayout.texcoord0.size, geomPool);
            sample.uv2 = GetUv(1, vertexLayout.texcoord1.size, geomPool);
        }
Пример #18
0
        public static bool AreEqual(GeometryPool lhs, GeometryPool rhs, ref string outWhy)
        {
            string why = "";

            if (!(lhs.Layout == rhs.Layout))
            {
                why += "Layout,";
            }
            if (!(ElementEqual(lhs.m_Vertices, rhs.m_Vertices, ref why)))
            {
                why += "verts,";
            }
            if (!(ElementEqual(lhs.m_Tris, rhs.m_Tris, ref why)))
            {
                why += "tris,";
            }
            if (!(ElementEqual(lhs.m_Normals, rhs.m_Normals, ref why)))
            {
                why += "normals,";
            }
            if (!(ElementEqual(lhs.m_Colors, rhs.m_Colors, ref why)))
            {
                why += "colors,";
            }
            if (!(ElementEqual(lhs.m_Tangents, rhs.m_Tangents, ref why)))
            {
                why += "tangents,";
            }

            if (!(AreEqual(lhs.m_Texcoord0, rhs.m_Texcoord0, rhs.Layout.texcoord0.size, ref why)))
            {
                why += "texcoord0,";
            }
            if (!(AreEqual(lhs.m_Texcoord1, rhs.m_Texcoord1, rhs.Layout.texcoord1.size, ref why)))
            {
                why += "texcoord1,";
            }
            if (!(AreEqual(lhs.m_Texcoord2, rhs.m_Texcoord2, rhs.Layout.texcoord2.size, ref why)))
            {
                why += "texcoord2,";
            }

            outWhy += why;
            return(why == "");
        }
Пример #19
0
        public void TestAppendMeshFallback()
        {
            var mesh = new Mesh();

            mesh.vertices = new[] { Vector3.one };

            var pool = new GeometryPool {
                Layout = new VertexLayout {
                    bUseColors = true
                }
            };
            Color32 white = Color.white;

            pool.Append(mesh, fallbackColor: white);
            Assert.AreEqual(white, pool.m_Colors[0]);

            Object.DestroyImmediate(mesh);
        }
Пример #20
0
        /// Converts a GeometryPool into a BrushSample.
        static BrushSample GetBrushSample(GeometryPool geomPool,
                                          List <Stroke> strokes,
                                          Matrix4x4 mat44)
        {
            var sample = new BrushSample();

            GetMeshSample(geomPool, mat44, sample);

            var vertexLayout = geomPool.Layout;

            // Used for shader binding.
            sample.brush = strokes[0].m_BrushGuid;

            // Optional StrokeInfo, this can be disabled to improve performance.
            sample.stroke = GetStrokeBatchInfo(strokes);

            return(sample);
        }
Пример #21
0
        public void TestStructByReference()
        {
            var pool = new GeometryPool();

            pool.Layout = new VertexLayout {
                texcoord0 = new TexcoordInfo {
                    size = 2, semantic = GeometryPool.Semantic.XyIsUv
                }
            };
            Assert.IsNotNull(pool.m_Texcoord0.v2 != null);
            // One or the other of m_UvSetN, m_TexcoordN is a property.
            // Normally, properties can only return structs by value.
            // Check that these properties are references.
            pool.m_Texcoord1.v2 = pool.m_Texcoord0.v2;
            Assert.IsNotNull(pool.m_Texcoord1.v2);
            pool.m_Texcoord0.v2 = null;
            Assert.IsNull(pool.m_Texcoord0.v2);
        }
Пример #22
0
        // Returns meshes in meters, in the proper basis, with proper winding
        static IEnumerable <ModelMesh> GetModelMeshesFromGameObject(GameObject obj,
                                                                    SceneStatePayload payload,
                                                                    bool reverseWinding)
        {
            int    i          = -1;
            string exportName = obj.name;

            foreach (MeshData data in VisitMeshes(obj))
            {
                i++;
                var mesh = data.mesh;
                for (int sm = 0; sm < mesh.subMeshCount; sm++)
                {
                    var exportableMaterial = GetMaterialForMeshData(data);

                    // TODO: The geometry pools could be aggregated, for faster downstream rendering.
                    var geo = new GeometryPool();
                    geo.Layout = exportableMaterial.VertexLayout;
                    geo.Append(mesh, geo.Layout);

                    // Important: This transform should only be applied once, since the pools are shared, and
                    // cannot include any mesh-local transformations.
                    ExportUtils.ConvertToMetersAndChangeBasis(geo, ExportUtils.GetBasisMatrix(payload));

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

                    var objectMesh = new ModelMesh {
                        model = null, // The model is only used for uniquefying the texture names.
                        name  = exportName + "_" + i + "_" + sm,
                        id    = data.renderer.gameObject.GetInstanceID(),
                        pool  = geo,
                        xform = ExportUtils.ChangeBasisNonUniformScale(payload, data.renderer.localToWorldMatrix),
                        exportableMaterial = exportableMaterial,
                        meshIndex          = i
                    };

                    yield return(objectMesh);
                }
            }
        }
Пример #23
0
        public void TestAppendMeshFailure()
        {
            var mesh = new Mesh();

            mesh.vertices = new[] { Vector3.one };

            {
                var pool = new GeometryPool {
                    Layout = new VertexLayout {
                        bUseNormals = true
                    }
                };
                Assert.Throws <InvalidOperationException>(() => pool.Append(mesh));
            }
            {
                var pool = new GeometryPool {
                    Layout = new VertexLayout {
                        bUseColors = true
                    }
                };
                Assert.Throws <InvalidOperationException>(() => pool.Append(mesh));
            }
            {
                var pool = new GeometryPool {
                    Layout = new VertexLayout {
                        bUseTangents = true
                    }
                };
                Assert.Throws <InvalidOperationException>(() => pool.Append(mesh));
            }
            {
                var pool = new GeometryPool
                {
                    Layout = new VertexLayout {
                        texcoord0 = new TexcoordInfo {
                            size = 2
                        }
                    }
                };
                Assert.Throws <InvalidOperationException>(() => pool.Append(mesh));
            }

            Object.DestroyImmediate(mesh);
        }
Пример #24
0
        void Init(BatchPool parentPool, Bounds bounds, ushort batchId)
        {
            BatchId      = batchId;
            m_ParentPool = parentPool;
            parentPool.m_Batches.Add(this);

            m_Groups     = new List <BatchSubset>();
            m_MeshFilter = GetComponent <MeshFilter>();
            Debug.Assert(m_MeshFilter.sharedMesh == null);

            m_Geometry = new GeometryPool();

            var rNewMesh = new Mesh();

            rNewMesh.MarkDynamic();

            gameObject.layer = ParentPool.Owner.Canvas.gameObject.layer;

            // This is a fix for b/27266757. I don't know precisely why it works.
            //
            // I think the mesh needs to spend "some amount of time" with a non-zero-length
            // vtx buffer. If this line is followed by .vertices = new Vector3[0], the bug
            // appears again. The mysterious thing is that immediately after creation, we
            // start filling up .vertices. Why does the first assignment need to happen here,
            // instead of waiting just a few ms for the mesh to be updated with real data?
            //
            // This seems related to how and when Unity decides to upload mesh data to the GPU.
            rNewMesh.vertices = new Vector3[1];

            // TODO: why set bounds?
            rNewMesh.bounds   = bounds;
            m_MeshFilter.mesh = rNewMesh;

            // Instantiate mesh so we can destroy rNewMesh; destroy rNewMesh to protect
            // against it leaking if/when someone reads m_MeshFilter.mesh.
            bool instantiationSucceeded = (m_MeshFilter.mesh != rNewMesh);

            Debug.Assert(instantiationSucceeded);
            DestroyImmediate(rNewMesh);

            m_bVertexDataDirty = false;
            m_bTopologyDirty   = false;
        }
Пример #25
0
            PreserveBatchResidency(IEnumerable <Stroke> input)
            {
                // We could do the "make it resident, make it not resident" dance on a stroke-by-stroke
                // basis, but that would be ridiculously wasteful. Optimize by grouping adjacent strokes
                // together if they share the same batch.
                //
                // When a sketch first loads, this optimization works extremely well because batches are
                // contiguous in the stroke list. The more the user mutates (select, unselect, recolor)
                // the less this will be true.  There's not a lot we can do about it unless we want to
                // sort the strokes by batch rather than by draw time (or whatever criteria the incoming
                // iterator uses), which I think would be too invasive.
                foreach (IGrouping <GeometryPool, Stroke> group in
                         input.GroupBy(stroke => GetPool(stroke)))
                {
                    GeometryPool pool = group.Key;

                    // If we have to bring the pool into memory, save off enough data so we can
                    // push it back out.
                    Mesh previousBackingMesh = null;
                    if (pool != null && !pool.IsGeometryResident)
                    {
                        previousBackingMesh = pool.GetBackingMesh();
                        // We currently only eject batch-owned GeometryPool to Mesh, so this is unlikely to trip;
                        // but we eventually may want to eject them to disk to save even more memory.
                        if (previousBackingMesh == null)
                        {
                            Debug.LogWarning("Not yet able to eject pool back to file; leaving it in memory");
                        }
                        pool.EnsureGeometryResident();
                    }

                    foreach (Stroke stroke in group)
                    {
                        yield return(stroke);
                    }

                    if (previousBackingMesh != null)
                    {
                        pool.MakeGeometryNotResident(previousBackingMesh);
                    }
                }
            }
Пример #26
0
        // Fbx only supports 2-channel texcoord data; turn (up to) 2 float4s
        // into (up to) 4 float2s.
        //
        // The resulting List will have no nulls at the end, but may have some
        // gaps with missing data.
        static List <List <Vector2> > DemuxTexcoords(GeometryPool pool)
        {
            var allSets = new List <List <Vector2> >();

            {
                List <Vector2> tmpXy, tmpZw;
                DemuxTexcoord(pool, pool.Layout.texcoord0.size, pool.m_Texcoord0, out tmpXy, out tmpZw);
                allSets.Add(tmpXy);
                allSets.Add(tmpZw);
                DemuxTexcoord(pool, pool.Layout.texcoord1.size, pool.m_Texcoord1, out tmpXy, out tmpZw);
                allSets.Add(tmpXy);
                allSets.Add(tmpZw);
            }
            // Remove unused sets from the end
            while (allSets.Count > 0 && allSets[allSets.Count - 1] == null)
            {
                allSets.RemoveAt(allSets.Count - 1);
            }
            return(allSets);
        }
Пример #27
0
 // Puts the passed timestamp data into pool.texcoord2.
 // It's assumed that the pool does not already have anything in texcoord2.
 private static void AugmentWithTimestamps(GeometryPool pool, ref List <Vector3> timestamps)
 {
     if (App.UserConfig.Export.ExportStrokeTimestamp)
     {
         GeometryPool.VertexLayout withTxc2 = pool.Layout;
         if (withTxc2.texcoord2.size == 0 && timestamps.Count == pool.NumVerts)
         {
             withTxc2.texcoord2 = new TexcoordInfo {
                 size = 3, semantic = Semantic.Timestamp
             };
             pool.Layout         = withTxc2;
             pool.m_Texcoord2.v3 = timestamps;
             timestamps          = null; // don't let caller reuse the list
         }
         else
         {
             Debug.LogError("Internal error; cannot add timestamps");
         }
     }
 }
Пример #28
0
        /// Flips winding order by swapping indices indexA and indexB.
        /// indexA and indexB must be in the range [0, 2] and not equal to each other.
        public static void ReverseTriangleWinding(GeometryPool pool, int indexA, int indexB)
        {
            if (indexA == indexB || indexA < 0 || indexA > 2)
            {
                throw new ArgumentException("indexA");
            }
            if (indexB < 0 || indexB > 2)
            {
                throw new ArgumentException("indexB");
            }
            var tris  = pool.m_Tris;
            int count = tris.Count;

            for (int i = 0; i < count; i += 3)
            {
                var tmp = tris[i + indexA];
                tris[i + indexA] = tris[i + indexB];
                tris[i + indexB] = tmp;
            }
        }
Пример #29
0
        private static GeometryPool RandomGeometryPool()
        {
            int vertexCount = 20;
            int indexCount  = 60;
            var pool        = new GeometryPool();

            pool.Layout = new VertexLayout {
                texcoord0 = new TexcoordInfo {
                    size = 2, semantic = Semantic.XyIsUv
                },
                bUseNormals  = true,
                bUseColors   = true,
                bUseTangents = true
            };
            pool.m_Vertices     = MathTestUtils.RandomVector3List(vertexCount);
            pool.m_Tris         = MathTestUtils.RandomIntList(indexCount, 0, vertexCount);
            pool.m_Normals      = MathTestUtils.RandomVector3List(vertexCount);
            pool.m_Colors       = MathTestUtils.RandomColor32List(vertexCount);
            pool.m_Tangents     = MathTestUtils.RandomVector4List(vertexCount);
            pool.m_Texcoord0.v2 = MathTestUtils.RandomVector2List(vertexCount);
            return(pool);
        }
Пример #30
0
        public void TestAppendMeshExtraData()
        {
            // Mesh has all the data but pool doesn't want any of it
            var mesh = new Mesh();

            mesh.vertices = new[] { Vector3.one };
            mesh.normals  = new[] { Vector3.up };
            mesh.SetUVs(0, new List <Vector2> {
                Vector2.zero
            });
            mesh.colors   = new[] { Color.white };
            mesh.tangents = new[] { Vector4.one };

            var pool = new GeometryPool {
                Layout = new VertexLayout()
            };

            // This should not throw
            pool.Append(mesh);

            Object.DestroyImmediate(mesh);
        }