コード例 #1
0
        /// <summary>
        /// Copy mesh data from USD to Unity with the given import options.
        /// </summary>
        public static void BuildMesh(string path,
                                     MeshSample usdMesh,
                                     GeometrySubsets geomSubsets,
                                     GameObject go,
                                     SceneImportOptions options,
                                     bool isDynamic)
        {
            var mf = ImporterBase.GetOrAddComponent <MeshFilter>(go);
            var mr = ImporterBase.GetOrAddComponent <MeshRenderer>(go);

            if (mf.sharedMesh == null)
            {
                mf.sharedMesh = new Mesh {
                    name = UniqueMeshName(go.name)
                };
            }

            // We only check if a mesh is dynamic when scene.IsPopulatingAccessMask is True. It only happens when a playable is
            // created, potentially way after mesh creation.
            if (isDynamic)
            {
                mf.sharedMesh.MarkDynamic();
            }

            BuildMesh_(path, usdMesh, mf.sharedMesh, geomSubsets, go, mr, options);
        }
コード例 #2
0
    private void UpdateArcs()
    {
        FingerArc.UpdateArcLights();

        int maxActiveArcs = surfaceArcs.Length - numFingersEngaged;

        for (int i = 0; i < surfaceArcs.Length; i++)
        {
            surfaceArcs[i].gameObject.SetActive(i < maxActiveArcs);
        }

        if (Random.value < randomSurfaceArcChange)
        {
            SurfaceArc arc = surfaceArcs[Random.Range(0, surfaceArcs.Length)];
            if (Random.value > 0.5f)
            {
                arc.gameObject.SetActive(true);
                MeshSample point1 = sampler.Samples[Random.Range(0, sampler.Samples.Length)];
                MeshSample point2 = sampler.Samples[Random.Range(0, sampler.Samples.Length)];
                arc.SetArc(point1, point2, transform.position, SurfaceRadius);
            }
            else
            {
                arc.gameObject.SetActive(false);
            }
        }
    }
コード例 #3
0
    public override void Initialize(Vector3 surfacePosition)
    {
        base.Initialize(surfacePosition);

        sampler.SampleMesh(false);

        meshBounds = sampler.Bounds;

        boids        = new Boid[numBoids];
        surfaceBoids = new SurfaceBoid[numBoids];
        boidMatrices = new Matrix4x4[numBoids];
        for (int i = 0; i < numBoids; i++)
        {
            Boid       b = new Boid();
            MeshSample s = sampler.Samples[Random.Range(0, sampler.Samples.Length)];
            b.Position = s.UV;
            b.Rotation = Random.Range(0, 360);
            boids[i]   = b;

            SurfaceBoid sb = new SurfaceBoid();
            sb.Offset       = Random.value;
            surfaceBoids[i] = sb;
        }

        forces = new Force[fingers.Length];
    }
コード例 #4
0
    public override void Initialize(Vector3 surfacePosition)
    {
        base.Initialize(surfacePosition);

        emptyBlock = new MaterialPropertyBlock();

        sampler.SampleMesh();

        blorbs          = new Blorb[sampler.Samples.Length];
        matrixes        = new Matrix4x4[sampler.Samples.Length];
        fingerPositions = new Vector3[fingers.Length];

        for (int i = 0; i < sampler.Samples.Length; i++)
        {
            MeshSample sample = sampler.Samples[i];
            Blorb      e      = new Blorb();
            e.Point         = sample.Point;
            e.Dir           = e.Point.normalized;
            e.Radius        = Random.Range(minRadius, maxRadius);
            e.Agitation     = Random.value;
            e.Goop          = GameObject.Instantiate(goopBlorbPrefabs[Random.Range(0, goopBlorbPrefabs.Length)], transform).GetComponent <GoopBlorb>();
            e.Rotation      = Random.Range(0, 360);
            e.RotationSpeed = Random.Range(-rotationSpeed, rotationSpeed);
            blorbs[i]       = e;
        }

        timeLastPopped = -100;

        updateBlorbs = true;
        Task updateTask = UpdateBlorbsLoop();
    }
コード例 #5
0
        public void Import(string filename)
        {
            Scene scene = Scene.Open(filename);

            CommandGroup group = new CommandGroup();

            var cameras = scene.ReadAll <CameraControllerSample>();

            foreach (var camera in cameras)
            {
                CameraControllerSample sample = camera.sample;

                GameObject cameraPrefab = ResourceManager.GetPrefab(PrefabID.Camera);
                GameObject instance     = SceneManager.InstantiateUnityPrefab(cameraPrefab);
                GameObject newObject    = SceneManager.AddObject(instance);

                newObject.name = camera.path.GetName();
                sample.CopyToCamera(newObject.GetComponent <CameraController>());
                Maths.DecomposeMatrix(sample.transform, out Vector3 position, out Quaternion rotation, out Vector3 scale);
                newObject.transform.localPosition = position;
                newObject.transform.localRotation = rotation;
                newObject.transform.localScale    = scale;
            }

            foreach (var m in scene.ReadAll <MeshSample>())
            {
                MeshSample sample = m.sample;

                GameObject gobject = new GameObject();
                gobject.name = m.path.GetName();
                Maths.DecomposeMatrix(sample.transform, out Vector3 position, out Quaternion rotation, out Vector3 scale);
                gobject.transform.localPosition = position;
                gobject.transform.localRotation = rotation;
                gobject.transform.localScale    = scale;

                Mesh mesh = new Mesh();
                mesh.SetVertices(sample.points);
                mesh.SetNormals(sample.normals);
                mesh.SetUVs(0, sample.st as Vector2[]);
                mesh.SetTriangles(sample.faceVertexIndices, 0);

                MeshFilter meshFilter = gobject.AddComponent <MeshFilter>();
                meshFilter.sharedMesh = mesh;
                MeshRenderer mr = gobject.AddComponent <MeshRenderer>();
                mr.sharedMaterial = ResourceManager.GetMaterial(MaterialID.ObjectOpaque);
                gobject.AddComponent <MeshCollider>();

                SceneManager.AddObject(gobject);
            }

            group.Submit();

            scene.Close();
        }
コード例 #6
0
    public void SetArc(MeshSample point1, MeshSample point2, Vector3 gravityOrigin, float surfaceRadius)
    {
        this.point1.position = point1.Point;
        this.point2.position = point2.Point;
        this.point1.forward  = point1.Normal;
        this.point2.forward  = point2.Normal;
        this.gravityOrigin   = gravityOrigin;
        this.surfaceRadius   = surfaceRadius;

        timeLastSet = Time.time;
        randomWidth = Random.Range(minWidth, maxWidth);
    }
コード例 #7
0
        void InitExportableObjects(GameObject go)
        {
            SampleBase     sample     = null;
            ExportFunction exportFunc = null;

            if (go.GetComponent <MeshFilter>() != null && go.GetComponent <MeshRenderer>() != null)
            {
                sample     = new MeshSample();
                exportFunc = ExportMesh;
                foreach (var mat in go.GetComponent <MeshRenderer>().materials)
                {
                    if (!m_materialMap.ContainsKey(mat))
                    {
                        string usdPath = "/World/Materials/" + pxr.UsdCs.TfMakeValidIdentifier(mat.name);
                        m_materialMap.Add(mat, usdPath);
                    }
                }
            }
            else if (go.GetComponent <Camera>())
            {
                sample     = new CameraSample();
                exportFunc = ExportCamera;
            }
            else
            {
                return;
            }

            // This is an exportable object.
            string path = Unity.UnityTypeConverter.GetPath(go.transform);

            m_primMap.Add(go, new ExportPlan {
                path = path, sample = sample, exportFunc = exportFunc
            });
            Debug.Log(path + " " + sample.GetType().Name);

            // Include the parent xform hierarchy.
            // Note that the parent hierarchy is memoised, so despite looking expensive, the time
            // complexity is linear.
            Transform xf = go.transform.parent;

            while (xf)
            {
                if (!InitExportableParents(xf.gameObject))
                {
                    break;
                }
                xf = xf.parent;
            }
        }
コード例 #8
0
    private void UpdateFingers()
    {
        numFingersEngaged = 0;
        for (int i = 0; i < fingers.Length; i++)
        {
            Transform finger = fingers[i];
            FingerArc arc    = fingerArcs[i];

            if (!finger.gameObject.activeSelf)
            {
                arc.gameObject.SetActive(false);
                continue;
            }

            if (arc.gameObject.activeSelf)
            {
                // See if we're too far away
                MeshSample sample = sampler.Samples[arc.Point1SampleIndex];
                if (Vector3.Distance(sample.Point, finger.position) > fingerDisengageDistance)
                {   // If we are, disable the arc and move on
                    arc.gameObject.SetActive(false);
                    continue;
                }
                else
                {     // If we aren't, see if it's time to zap to a different position
                    if (Random.value < randomFingerArcChange)
                    { // Get the closest point on the sphere
                        MeshSample point1 = sampler.ClosestSample(finger.position);
                        // Then get a random sample somewhere nearby
                        point1 = sampler.RandomSample(point1.Point, fingerRandomPosRadius);
                        arc.SetArc(point1, fingerArcSources[i]);
                    }
                    numFingersEngaged++;
                }
            }
            else
            {   // See if we're close enough to any samples to start
                // Get the closest point on the sphere
                MeshSample point1 = sampler.ClosestSample(finger.position);
                if (Vector3.Distance(point1.Point, finger.position) < fingerEngageDistance)
                {   // Then get a random sample somewhere nearby
                    point1 = sampler.RandomSample(point1.Point, fingerRandomPosRadius);
                    arc.gameObject.SetActive(true);
                    arc.SetArc(point1, fingerArcSources[i]);
                    numFingersEngaged++;
                }
            }
        }
    }
コード例 #9
0
    public override void Initialize(Vector3 surfacePosition)
    {
        base.Initialize(surfacePosition);

        sampler.SampleMesh(true);

        for (int i = 0; i < surfaceArcs.Length; i++)
        {
            MeshSample point1 = sampler.Samples[Random.Range(0, sampler.Samples.Length)];
            MeshSample point2 = sampler.Samples[Random.Range(0, sampler.Samples.Length)];
            surfaceArcs[i].SetArc(point1, point2, Vector3.zero, SurfaceRadius);
        }

        buzzAudio.pitch = 0;
    }
コード例 #10
0
        /// <summary>
        /// Copy mesh data from USD to Unity with the given import options, setup for skinning.
        /// </summary>
        public static void BuildSkinnedMesh(string path,
                                            MeshSample usdMesh,
                                            GeometrySubsets geomSubsets,
                                            GameObject go,
                                            SceneImportOptions options)
        {
            var smr = ImporterBase.GetOrAddComponent <SkinnedMeshRenderer>(go);

            if (smr.sharedMesh == null)
            {
                smr.sharedMesh = new Mesh();
            }

            BuildMesh_(path, usdMesh, smr.sharedMesh, geomSubsets, go, smr, options);
        }
コード例 #11
0
    internal MeshSample RandomSample(Vector3 point, float searchRadius)
    {
        float      sqrSearchRadius = searchRadius * searchRadius;
        List <int> samplesInRange  = new List <int>();

        for (int i = 0; i < samples.Length; i++)
        {
            MeshSample sample  = samples[i];
            float      sqrDist = (sample.Point - point).sqrMagnitude;
            if (sqrDist < sqrSearchRadius)
            {
                samplesInRange.Add(i);
            }
        }
        return(samples[samplesInRange[Random.Range(0, samplesInRange.Count)]]);
    }
コード例 #12
0
    internal MeshSample ClosestSample(Vector3 point)
    {
        float closestDistSoFar = Mathf.Infinity;
        int   closestIndex     = 0;

        for (int i = 0; i < samples.Length; i++)
        {
            MeshSample sample  = samples[i];
            float      sqrDist = (sample.Point - point).sqrMagnitude;
            if (sqrDist < closestDistSoFar)
            {
                closestDistSoFar = sqrDist;
                closestIndex     = i;
            }
        }
        return(samples[closestIndex]);
    }
コード例 #13
0
    public void SetArc(MeshSample point1, Transform fingerTarget)
    {
        Point1SampleIndex = point1.Index;

        this.point1.position = point1.Point;
        this.point1.forward  = point1.Normal;

        this.fingerTarget    = fingerTarget;
        this.point2.position = fingerTarget.position;
        this.point2.forward  = fingerTarget.forward;

        randomWidth = Random.Range(minWidth, maxWidth);

        fingerAudio.pitch = Random.Range(0.7f, 1.3f);

        timeLastSet = Time.time;
    }
コード例 #14
0
    private void UpdateGoopSlime()
    {
        for (int i = 0; i < fingers.Length; i++)
        {
            if (!fingers[i].gameObject.activeSelf)
            {
                goopSlimes[i].gameObject.SetActive(false);
                continue;
            }

            if (Vector3.Distance(fingers[i].position, transform.position) < SurfaceRadius + goopDistance)
            {
                MeshSample closestSample = sampler.ClosestSample(fingers[i].localPosition);
                goopSlimes[i].SetGoop(closestSample, fingers[i]);
            }
        }
    }
コード例 #15
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);
        }
コード例 #16
0
    MeshSample SampleRandomPoint(int index, bool transformPoint = false)
    {
        MeshSample sample = default(MeshSample);

        sample.Index         = index;
        sample.TriangleIndex = GetRandomTriangleIndex();
        Vector3 BC = Random.insideUnitSphere.normalized;

        BC.x = Random.value;
        BC.y = 1f - BC.x;
        BC.z = 1f - BC.x - BC.z;
        sample.BarycentricCoordinate = BC;

        Vector3 P1 = verts[tris[sample.TriangleIndex + 0]];
        Vector3 P2 = verts[tris[sample.TriangleIndex + 1]];
        Vector3 P3 = verts[tris[sample.TriangleIndex + 2]];

        Vector2 UV1 = uvs[tris[sample.TriangleIndex + 0]];
        Vector2 UV2 = uvs[tris[sample.TriangleIndex + 0]];
        Vector2 UV3 = uvs[tris[sample.TriangleIndex + 0]];

        UV1 = Vector2.Lerp(UV1, UV2, BC.x);
        UV2 = Vector2.Lerp(UV2, UV3, BC.y);

        P1           = Vector3.Lerp(P1, P2, BC.x);
        P1           = Vector3.Lerp(P1, P3, BC.y);
        sample.Point = P1;
        sample.UV    = UV1;

        if (transformPoint)
        {
            sample.Point = transform.TransformPoint(sample.Point);
        }

        // Interpolated vertex normal
        Vector3 N1 = normals[tris[sample.TriangleIndex + 0]];
        Vector3 N2 = normals[tris[sample.TriangleIndex + 1]];
        Vector3 N3 = normals[tris[sample.TriangleIndex + 2]];

        N1            = Vector3.Lerp(N1, N2, BC.x);
        N1            = Vector3.Lerp(N1, N3, BC.y);
        sample.Normal = N1;
        return(sample);
    }
コード例 #17
0
    public void SetGoop(MeshSample origin, Transform target)
    {
        this.target = target;
        this.origin = origin;

        if (droop == null)
        {
            droop           = new float[lineRenderer.positionCount];
            normalizedTimes = new float[lineRenderer.positionCount];
            follow          = new float[lineRenderer.positionCount];

            for (int i = 0; i < lineRenderer.positionCount; i++)
            {
                normalizedTimes[i] = (float)i / (lineRenderer.positionCount - 1);
                droop[i]           = droopCurve.Evaluate(normalizedTimes[i]);
                follow[i]          = followCurve.Evaluate(normalizedTimes[i]);
            }
        }

        if (positions.Length != lineRenderer.positionCount)
        {
            positions          = new Vector3[lineRenderer.positionCount];
            targetPositions    = new Vector3[lineRenderer.positionCount];
            prevPositions      = new Vector3[lineRenderer.positionCount];
            inertialVelocities = new Vector3[lineRenderer.positionCount];
        }

        for (int i = 0; i < lineRenderer.positionCount; i++)
        {
            lineRenderer.SetPosition(i, origin.Point);
            positions[i]          = transform.TransformPoint(origin.Point);
            targetPositions[i]    = transform.TransformPoint(origin.Point);
            prevPositions[i]      = transform.TransformPoint(origin.Point);
            inertialVelocities[i] = Vector3.zero;
        }

        gameObject.SetActive(true);
    }
コード例 #18
0
    private Vector2 ProjectFingerPosition(Vector3 position)
    {
        MeshSample sample = sampler.ClosestSample(surfaceTransform.InverseTransformPoint(position));

        return(sample.UV);
    }
コード例 #19
0
ファイル: QueryTests.cs プロジェクト: khunrobot/usd-unity-sdk
        public static void BasicTest()
        {
            var cubeSample = new CubeSample();
            var meshSample = new MeshSample();

            meshSample.visibility = Visibility.Invisible;
            var scene = Scene.Create();

            scene.Write("/Root/Cube", cubeSample);
            scene.Write("/Root/Mesh", meshSample);
            scene.Write("/Root/Mesh2", meshSample);

            foreach (var mesh in scene.ReadAll <XformableQuery>(rootPath:"/Root"))
            {
                Console.WriteLine("ReadAll Test: " + mesh.path);
            }

            foreach (var path in scene.Find <XformableQuery>(rootPath: "/Root"))
            {
                Console.WriteLine("Find Test: " + path);
            }

            try {
                Util.DiagnosticHandler.Instance.LastError = null;

                foreach (var mesh in scene.ReadAll <XformableQuery>(rootPath: "/Bogus/Root/Path"))
                {
                    Console.WriteLine("Query Test: " + mesh.path);
                }

                // TODO: for some reason, these stop working after the first exception is thrown,
                //       but it seems like *only* this code path is affected.
                if (!string.IsNullOrEmpty(Util.DiagnosticHandler.Instance.LastError))
                {
                    throw new ApplicationException(Util.DiagnosticHandler.Instance.LastError);
                }
                else
                {
                    throw new Exception("Expected exception but was not thrown.");
                }
            } catch (ApplicationException ex) {
                Console.WriteLine("Caught expected exception: " + ex.Message);
            }

            try {
                Util.DiagnosticHandler.Instance.LastError = null;

                foreach (var mesh in scene.ReadAll <BadBaseTypeQuery>(rootPath: "/Root"))
                {
                    Console.WriteLine("Query Test: " + mesh.path);
                }

                // TODO: for some reason, these stop working after the first exception is thrown,
                //       but it seems like *only* this code path is affected.
                if (!string.IsNullOrEmpty(Util.DiagnosticHandler.Instance.LastError))
                {
                    throw new ApplicationException(Util.DiagnosticHandler.Instance.LastError);
                }
                else
                {
                    throw new Exception("Expected exception but was not thrown.");
                }
            } catch (ApplicationException ex) {
                Console.WriteLine("Caught expected exception: " + ex.Message);
            }
        }
コード例 #20
0
        // -------------------------------------------------------------------------------------------- //
        // Export Logic
        // -------------------------------------------------------------------------------------------- //

        /// Exports either all brush strokes or the given selection to the specified file.
        static public void ExportPayload(string outputFile)
        {
            // Would be nice to find a way to kick this off automatically.
            // Redundant calls are ignored.
            if (!InitUsd.Initialize())
            {
                return;
            }

            // Unity is left handed (DX), USD is right handed (GL)
            var payload      = ExportCollector.GetExportPayload(AxisConvention.kUsd);
            var brushCatalog = BrushCatalog.m_Instance;

            // The Scene object provids serialization methods arbitrary C# objects to USD.
            USD.NET.Scene scene = USD.NET.Scene.Create(outputFile);

            // The target time at which samples will be written.
            //
            // In this case, all data is being written to the "default" time, which means it can be
            // overridden by animated values later.
            scene.Time = null;

            // Bracketing times to specify the valid animation range.
            scene.StartTime = 1.0;
            scene.EndTime   = 1.0;

            const string kGeomName   = "/Geom";
            const string kCurvesName = "/Curves";

            string path = "";

            AddSketchRoot(scene, GetSketchPath()); // Create: </Sketch>

            CreateXform(scene, GetStrokesPath());  // Create: </Sketch/Strokes>
            CreateXform(scene, GetModelsPath());   // Create: </Sketch/Models>

            // Main export loop.
            try
            {
                foreach (ExportUtils.GroupPayload group in payload.groups)
                {
                    // Example: </Sketch/Strokes/Group_0>
                    path = GetGroupPath(group.id);
                    CreateXform(scene, path);

                    // Example: </Sketch/Strokes/Group_0/Geom>
                    CreateXform(scene, path + kGeomName);

                    // Example: </Sketch/Strokes/Group_0/Curves>
                    CreateXform(scene, path + kCurvesName);

                    int iBrushMeshPayload = -1;
                    foreach (var brushMeshPayload in group.brushMeshes)
                    {
                        ++iBrushMeshPayload;
                        // Conditionally moves Normal into Texcoord1 so that the normal semantic is respected.
                        // This only has an effect when layout.bFbxExportNormalAsTexcoord1 == true.
                        // Note that this modifies the GeometryPool in place.
                        FbxUtils.ApplyFbxTexcoordHack(brushMeshPayload.geometry);

                        // Brushes are expected to be batched by type/GUID.
                        Guid   brushGuid = brushMeshPayload.strokes[0].m_BrushGuid;
                        string brushName = "/" +
                                           SanitizeIdentifier(brushCatalog.GetBrush(brushGuid).DurableName) + "_";

                        // Example: </Sketch/Strokes/Group_0/Geom/Marker_0>
                        string meshPath = path + kGeomName + brushName;

                        // Example: </Sketch/Strokes/Group_0/Curves/Marker_0>
                        string curvePath = path + kCurvesName + brushName;

                        var geomPool       = brushMeshPayload.geometry;
                        var strokes        = brushMeshPayload.strokes;
                        var mat44          = Matrix4x4.identity;
                        var meshPrimPath   = new pxr.SdfPath(meshPath + iBrushMeshPayload.ToString());
                        var curvesPrimPath = new pxr.SdfPath(curvePath + iBrushMeshPayload.ToString());

                        //
                        // Geometry
                        //
                        BrushSample brushSample = GetBrushSample(geomPool, strokes, mat44);

                        // Write the BrushSample to the same point in the scenegraph at which it exists in Tilt
                        // Brush. Notice this method is Async, it is queued to a background thread to perform I/O
                        // which means it is not safe to read from the scene until WaitForWrites() is called.
                        scene.Write(meshPrimPath, brushSample);

                        //
                        // Stroke Curves
                        //
                        var curvesSample = GetCurvesSample(payload, strokes, Matrix4x4.identity);
                        scene.Write(curvesPrimPath, curvesSample);

                        //
                        // Materials
                        //
                        double?oldTime = scene.Time;
                        scene.Time = null;

                        string materialPath = CreateMaterialNetwork(
                            scene,
                            brushMeshPayload.exportableMaterial,
                            GetStrokesPath());

                        BindMaterial(scene, meshPrimPath.ToString(), materialPath);
                        BindMaterial(scene, curvesPrimPath.ToString(), materialPath);

                        scene.Time = oldTime;
                    }
                }

                //
                // Models
                //

                var knownModels = new Dictionary <Model, string>();

                int iModelMeshPayload = -1;
                foreach (var modelMeshPayload in payload.modelMeshes)
                {
                    ++iModelMeshPayload;
                    var modelId         = modelMeshPayload.modelId;
                    var modelNamePrefix = "/Model_"
                                          + SanitizeIdentifier(modelMeshPayload.model.GetExportName())
                                          + "_";
                    var modelName = modelNamePrefix + modelId;

                    var xf = modelMeshPayload.xform;
                    // Geometry pools may be repeated and should be turned into references.
                    var geomPool = modelMeshPayload.geometry;

                    var modelRootPath = new pxr.SdfPath(GetModelsPath() + modelName);

                    // Example: </Sketch/Models/Model_Andy_0>
                    CreateXform(scene, modelRootPath, xf);

                    // Example: </Sketch/Models/Model_Andy_0/Geom>
                    CreateXform(scene, modelRootPath + kGeomName);

                    string modelPathToReference;
                    if (knownModels.TryGetValue(modelMeshPayload.model, out modelPathToReference) &&
                        modelPathToReference != modelRootPath)
                    {
                        // Create an Xform, note that the world transform here will override the referenced model.
                        var meshXf = new MeshXformSample();
                        meshXf.transform = xf;
                        scene.Write(modelRootPath, meshXf);
                        // Add a USD reference to previously created model.
                        var prim = scene.Stage.GetPrimAtPath(modelRootPath);
                        prim.GetReferences().AddReference("", new pxr.SdfPath(modelPathToReference));
                        continue;
                    }

                    // Example: </Sketch/Models/Geom/Model_Andy_0/Mesh_0>
                    path = modelRootPath + kGeomName + "/Mesh_" + iModelMeshPayload.ToString();

                    var meshPrimPath = new pxr.SdfPath(path);
                    var meshSample   = new MeshSample();

                    GetMeshSample(geomPool, Matrix4x4.identity, meshSample);
                    scene.Write(path, meshSample);
                    scene.Stage.GetPrimAtPath(new pxr.SdfPath(path)).SetInstanceable(true);

                    //
                    // Materials
                    //

                    // Author at default time.
                    double?oldTime = scene.Time;
                    scene.Time = null;

                    // Model materials must live under the model root, since we will reference the model.
                    string materialPath = CreateMaterialNetwork(
                        scene,
                        modelMeshPayload.exportableMaterial,
                        modelRootPath);
                    BindMaterial(scene, meshPrimPath.ToString(), materialPath);

                    // Continue authoring at the desired time index.
                    scene.Time = oldTime;

                    //
                    // Setup to be referenced.
                    //
                    if (!knownModels.ContainsKey(modelMeshPayload.model))
                    {
                        knownModels.Add(modelMeshPayload.model, modelRootPath);
                    }
                }
            }
            catch
            {
                scene.Save();
                scene.Close();
                throw;
            }

            // Save will force a sync with all async reads and writes.
            scene.Save();
            scene.Close();
        }
コード例 #21
0
        private static void BuildMesh_(string path,
                                       MeshSample usdMesh,
                                       Mesh unityMesh,
                                       GeometrySubsets geomSubsets,
                                       GameObject go,
                                       Renderer renderer,
                                       SceneImportOptions options)
        {
            // TODO: Because this method operates on a GameObject, it must be single threaded. For this
            // reason, it should be extremely light weight. All computation should be completed prior to
            // this step, allowing heavy computations to happen in parallel. This is not currently the
            // case, triangulation and change of basis are non-trivial operations. Computing the mesh
            // bounds, normals and tangents should similarly be moved out of this function and should not
            // rely on the UnityEngine.Mesh API.

            Material mat = renderer.sharedMaterial;
            bool     changeHandedness = options.changeHandedness == BasisTransformation.SlowAndSafe;

            //
            // Points.
            //

            if (options.meshOptions.points == ImportMode.Import && usdMesh.points != null)
            {
                if (changeHandedness)
                {
                    for (int i = 0; i < usdMesh.points.Length; i++)
                    {
                        usdMesh.points[i] = UnityTypeConverter.ChangeBasis(usdMesh.points[i]);
                    }
                }

                if (usdMesh.faceVertexIndices != null)
                {
                    // Annoyingly, there is a circular dependency between vertices and triangles, which makes
                    // it impossible to have a fixed update order in this function. As a result, we must clear
                    // the triangles before setting the points, to break that dependency.
                    unityMesh.SetTriangles(new int[0] {
                    }, 0);
                }
                unityMesh.vertices = usdMesh.points;
            }

            //
            // Purpose.
            //

            // Deactivate non-geometry prims (e.g. guides, render, etc).
            if (usdMesh.purpose != Purpose.Default)
            {
                go.SetActive(false);
            }

            //
            // Mesh Topology.
            //

            // TODO: indices should not be accessed if topology is not requested, however it may be
            // needed for facevarying primvars; that special case should throw a warning, rather than
            // reading the value.
            int[] originalIndices = new int[usdMesh.faceVertexIndices == null
                                      ? 0
                                      : usdMesh.faceVertexIndices.Length];
            // Optimization: only do this when there are face varying primvars.
            if (usdMesh.faceVertexIndices != null)
            {
                Array.Copy(usdMesh.faceVertexIndices, originalIndices, originalIndices.Length);
            }

            if (options.meshOptions.topology == ImportMode.Import && usdMesh.faceVertexIndices != null)
            {
                Profiler.BeginSample("Triangulate Mesh");
                if (options.meshOptions.triangulateMesh)
                {
                    // Triangulate n-gons.
                    // For best performance, triangulate off-line and skip conversion.
                    if (usdMesh.faceVertexIndices == null)
                    {
                        Debug.LogWarning("Mesh had no face indices: " + UnityTypeConverter.GetPath(go.transform));
                        return;
                    }
                    if (usdMesh.faceVertexCounts == null)
                    {
                        Debug.LogWarning("Mesh had no face counts: " + UnityTypeConverter.GetPath(go.transform));
                        return;
                    }
                    var indices = UnityTypeConverter.ToVtArray(usdMesh.faceVertexIndices);
                    var counts  = UnityTypeConverter.ToVtArray(usdMesh.faceVertexCounts);
                    UsdGeomMesh.Triangulate(indices, counts);
                    UnityTypeConverter.FromVtArray(indices, ref usdMesh.faceVertexIndices);
                }
                Profiler.EndSample();

                Profiler.BeginSample("Convert LeftHanded");
                bool isLeftHanded = usdMesh.orientation == Orientation.LeftHanded;
                if (changeHandedness && !isLeftHanded || !changeHandedness && isLeftHanded)
                {
                    // USD is right-handed, so the mesh needs to be flipped.
                    // Unity is left-handed, but that doesn't matter here.
                    for (int i = 0; i < usdMesh.faceVertexIndices.Length; i += 3)
                    {
                        int tmp = usdMesh.faceVertexIndices[i];
                        usdMesh.faceVertexIndices[i]     = usdMesh.faceVertexIndices[i + 1];
                        usdMesh.faceVertexIndices[i + 1] = tmp;
                    }
                }
                Profiler.EndSample();

                if (usdMesh.faceVertexIndices.Length > 65535)
                {
                    unityMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                }

                Profiler.BeginSample("Breakdown triangles for Mesh Subsets");
                if (geomSubsets.Subsets.Count == 0)
                {
                    unityMesh.triangles = usdMesh.faceVertexIndices;
                }
                else
                {
                    unityMesh.subMeshCount = geomSubsets.Subsets.Count;
                    int subsetIndex = 0;
                    foreach (var kvp in geomSubsets.Subsets)
                    {
                        int[] faceIndices     = kvp.Value;
                        int[] triangleIndices = new int[faceIndices.Length * 3];

                        for (int i = 0; i < faceIndices.Length; i++)
                        {
                            triangleIndices[i * 3 + 0] = usdMesh.faceVertexIndices[faceIndices[i] * 3 + 0];
                            triangleIndices[i * 3 + 1] = usdMesh.faceVertexIndices[faceIndices[i] * 3 + 1];
                            triangleIndices[i * 3 + 2] = usdMesh.faceVertexIndices[faceIndices[i] * 3 + 2];
                        }

                        unityMesh.SetTriangles(triangleIndices, subsetIndex);
                        subsetIndex++;
                    }
                }
                Profiler.EndSample();
            }

            //
            // Extent / Bounds.
            //

            bool hasBounds = usdMesh.extent.size.x > 0 ||
                             usdMesh.extent.size.y > 0 ||
                             usdMesh.extent.size.z > 0;

            if (ShouldImport(options.meshOptions.boundingBox) && hasBounds)
            {
                Profiler.BeginSample("Import Bounds");
                if (changeHandedness)
                {
                    usdMesh.extent.center  = UnityTypeConverter.ChangeBasis(usdMesh.extent.center);
                    usdMesh.extent.extents = UnityTypeConverter.ChangeBasis(usdMesh.extent.extents);
                }
                unityMesh.bounds = usdMesh.extent;
                Profiler.EndSample();
            }
            else if (ShouldCompute(options.meshOptions.boundingBox))
            {
                Profiler.BeginSample("Calculate Bounds");
                unityMesh.RecalculateBounds();
                Profiler.EndSample();
            }

            //
            // Normals.
            //

            if (usdMesh.normals != null && ShouldImport(options.meshOptions.normals))
            {
                Profiler.BeginSample("Import Normals");
                if (changeHandedness)
                {
                    for (int i = 0; i < usdMesh.points.Length; i++)
                    {
                        usdMesh.normals[i] = UnityTypeConverter.ChangeBasis(usdMesh.normals[i]);
                    }
                }
                // If more normals than verts, assume face-varying.
                if (usdMesh.normals.Length > usdMesh.points.Length)
                {
                    usdMesh.normals = UnrollFaceVarying(usdMesh.points.Length, usdMesh.normals, usdMesh.faceVertexCounts, originalIndices);
                }
                unityMesh.normals = usdMesh.normals;
                Profiler.EndSample();
            }
            else if (ShouldCompute(options.meshOptions.normals))
            {
                Profiler.BeginSample("Calculate Normals");
                unityMesh.RecalculateNormals();
                Profiler.EndSample();
            }

            //
            // Tangents.
            //

            if (usdMesh.tangents != null && ShouldImport(options.meshOptions.tangents))
            {
                Profiler.BeginSample("Import Tangents");
                if (changeHandedness)
                {
                    for (int i = 0; i < usdMesh.points.Length; i++)
                    {
                        var w = usdMesh.tangents[i].w;
                        var t = UnityTypeConverter.ChangeBasis(usdMesh.tangents[i]);
                        usdMesh.tangents[i] = new Vector4(t.x, t.y, t.z, w);
                    }
                }
                unityMesh.tangents = usdMesh.tangents;
                Profiler.EndSample();
            }
            else if (ShouldCompute(options.meshOptions.tangents))
            {
                Profiler.BeginSample("Calculate Tangents");
                unityMesh.RecalculateTangents();
                Profiler.EndSample();
            }

            //
            // Display Color.
            //

            if (ShouldImport(options.meshOptions.color) && usdMesh.colors != null && usdMesh.colors.Length > 0)
            {
                Profiler.BeginSample("Import Display Color");
                // NOTE: The following color conversion assumes PlayerSettings.ColorSpace == Linear.
                // For best performance, convert color space to linear off-line and skip conversion.

                if (usdMesh.colors.Length == 1)
                {
                    // Constant color can just be set on the material.
                    if (options.useDisplayColorAsFallbackMaterial && options.materialImportMode != MaterialImportMode.None)
                    {
                        mat = options.materialMap.InstantiateSolidColor(usdMesh.colors[0].gamma);
                    }
                }
                else if (usdMesh.colors.Length == usdMesh.points.Length)
                {
                    // Vertex colors map on to verts.
                    // TODO: move the conversion to C++ and use the color management API.
                    for (int i = 0; i < usdMesh.colors.Length; i++)
                    {
                        usdMesh.colors[i] = usdMesh.colors[i];
                    }
                    unityMesh.colors = usdMesh.colors;
                }
                else if (usdMesh.colors.Length == usdMesh.faceVertexCounts.Length)
                {
                    // Uniform colors, one per face.
                    // Unroll face colors into vertex colors. This is not strictly correct, but it's much faster
                    // than the fully correct solution.
                    var colors = new Color[unityMesh.vertexCount];
                    int idx    = 0;
                    try {
                        for (int faceIndex = 0; faceIndex < usdMesh.colors.Length; faceIndex++)
                        {
                            var faceColor = usdMesh.colors[faceIndex];
                            for (int f = 0; f < usdMesh.faceVertexCounts[faceIndex]; f++)
                            {
                                int vertexInFaceIdx = originalIndices[idx++];
                                colors[vertexInFaceIdx] = faceColor;
                            }
                        }
                        unityMesh.colors = colors;
                    } catch (Exception ex) {
                        Debug.LogException(new Exception("Failed loading uniform/per-face colors at " + path, ex));
                    }
                }
                else if (usdMesh.colors.Length > usdMesh.points.Length)
                {
                    try {
                        usdMesh.colors = UnrollFaceVarying(unityMesh.vertexCount,
                                                           usdMesh.colors,
                                                           usdMesh.faceVertexCounts,
                                                           originalIndices);
                        for (int i = 0; i < usdMesh.colors.Length; i++)
                        {
                            usdMesh.colors[i] = usdMesh.colors[i];
                        }
                        unityMesh.colors = usdMesh.colors;
                    } catch (Exception ex) {
                        Debug.LogException(
                            new Exception("Error unrolling Face-Varying colors at <" + path + ">", ex));
                    }
                }
                else
                {
                    Debug.LogWarning("Uniform (color per face) display color not supported");
                }
                Profiler.EndSample();
            } // should import color

            //
            // UVs / Texture Coordinates.
            //

            // TODO: these should also be driven by the UV privmars required by the bound shader.
            Profiler.BeginSample("Import UV Sets");
            ImportUv(path, unityMesh, 0, usdMesh.st, usdMesh.indices, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord0, go);
            ImportUv(path, unityMesh, 0, usdMesh.uv, null, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord0, go);
            ImportUv(path, unityMesh, 1, usdMesh.uv2, null, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord1, go);
            ImportUv(path, unityMesh, 2, usdMesh.uv3, null, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord2, go);
            ImportUv(path, unityMesh, 3, usdMesh.uv4, null, usdMesh.faceVertexCounts, originalIndices, options.meshOptions.texcoord3, go);
            Profiler.EndSample();

            Profiler.BeginSample("Request Material Bindings");

            //
            // Materials.
            //

            if (options.materialImportMode != MaterialImportMode.None)
            {
                if (mat == null)
                {
                    mat = options.materialMap.InstantiateSolidColor(Color.white);
                }

                if (unityMesh.subMeshCount == 1)
                {
                    renderer.sharedMaterial = mat;
                    if (options.ShouldBindMaterials)
                    {
                        options.materialMap.RequestBinding(path,
                                                           (scene, boundMat, primvars) => BindMat(scene, unityMesh, boundMat, renderer, path, primvars, usdMesh.faceVertexCounts, originalIndices));
                    }
                }
                else
                {
                    var mats = new Material[unityMesh.subMeshCount];
                    for (int i = 0; i < mats.Length; i++)
                    {
                        mats[i] = mat;
                    }
                    renderer.sharedMaterials = mats;
                    if (options.ShouldBindMaterials)
                    {
                        Debug.Assert(geomSubsets.Subsets.Count == unityMesh.subMeshCount);
                        var subIndex = 0;
                        foreach (var kvp in geomSubsets.Subsets)
                        {
                            int idx = subIndex++;
                            options.materialMap.RequestBinding(kvp.Key,
                                                               (scene, boundMat, primvars) => BindMat(scene, unityMesh, boundMat, renderer, idx, path, primvars, usdMesh.faceVertexCounts, originalIndices));
                        }
                    }
                }
            }
            Profiler.EndSample();

            //
            // Lightmap UV Unwrapping.
            //

#if UNITY_EDITOR
            if (options.meshOptions.generateLightmapUVs)
            {
#if !UNITY_2018_3_OR_NEWER
                if (unityMesh.indexFormat == UnityEngine.Rendering.IndexFormat.UInt32)
                {
                    Debug.LogWarning("Skipping prim " + path + " due to large IndexFormat (UInt32) bug in older vesrsions of Unity");
                    return;
                }
#endif
                Profiler.BeginSample("Unwrap Lightmap UVs");
                var unwrapSettings = new UnityEditor.UnwrapParam();

                unwrapSettings.angleError = options.meshOptions.unwrapAngleError;
                unwrapSettings.areaError  = options.meshOptions.unwrapAngleError;
                unwrapSettings.hardAngle  = options.meshOptions.unwrapHardAngle;

                // Convert pixels to unitless UV space, which is what unwrapSettings uses internally.
                unwrapSettings.packMargin = options.meshOptions.unwrapPackMargin / 1024.0f;

                UnityEditor.Unwrapping.GenerateSecondaryUVSet(unityMesh, unwrapSettings);
                Profiler.EndSample();
            }
#else
            if (options.meshOptions.generateLightmapUVs)
            {
                Debug.LogWarning("Lightmap UVs were requested to be generated, but cannot be generated outside of the editor");
            }
#endif
        }