Beispiel #1
0
        // Instance API

        static VrAssetService()
        {
            Matrix4x4 polyFromUnity = AxisConvention.GetFromUnity(AxisConvention.kGltfAccordingToPoly);

            // Provably non-lossy: the mat4 is purely TRS, and the S is uniform
            kPolyFromUnity = TrTransform.FromMatrix4x4(polyFromUnity);
        }
Beispiel #2
0
        public void TestAxisConvention()
        {
            AxisConvention[] acs =
            {
                AxisConvention.kUnity,
                AxisConvention.kGltf2,
                AxisConvention.kUsd,
                AxisConvention.kStl,
                AxisConvention.kUnreal
            };

            foreach (var ac1 in acs)
            {
                foreach (var ac2 in acs)
                {
                    Matrix4x4 ac1FromAc2 = AxisConvention.GetToDstFromSrc(ac1, ac2);
                    Assert.AreEqual(ac1.forward, ac1FromAc2.MultiplyVector(ac2.forward));
                    Assert.AreEqual(ac1.right, ac1FromAc2.MultiplyVector(ac2.right));
                    Assert.AreEqual(ac1.up, ac1FromAc2.MultiplyVector(ac2.up));
                }
            }

            foreach (var ac in acs)
            {
                Matrix4x4 fromUnity = AxisConvention.GetFromUnity(ac);
                Assert.AreEqual(ac.forward, fromUnity.MultiplyVector(Vector3.forward));
                Assert.AreEqual(ac.right, fromUnity.MultiplyVector(Vector3.right));
                Assert.AreEqual(ac.up, fromUnity.MultiplyVector(Vector3.up));

                Matrix4x4 toUnity = AxisConvention.GetToUnity(ac);
                Assert.AreEqual(Vector3.forward, toUnity.MultiplyVector(ac.forward));
                Assert.AreEqual(Vector3.right, toUnity.MultiplyVector(ac.right));
                Assert.AreEqual(Vector3.up, toUnity.MultiplyVector(ac.up));
            }
        }
Beispiel #3
0
 /// Returns a matrix that converts to dst from Unity's axis conventions.
 public static Matrix4x4 GetFromUnity(AxisConvention dst)
 {
     // Solve for M:
     //   M * (1, 0, 0) = ac.right   (because 1,0,0 is Unity right)
     //   M * (0, 1, 0) = ac.up
     //   M * (0, 0, 1) = ac.forward
     return(new Matrix4x4(dst.right, dst.up, dst.forward, new Vector4(0, 0, 0, 1)));
 }
Beispiel #4
0
 // If you pass a temporary directory, it may (or may not) be used
 // for memory optimizations during the export. In this case, take
 // care to call Destroy() if you want the payload to clean up after itself.
 public SceneStatePayload(AxisConvention axes, string temporaryDirectory)
 {
     this.axes = axes;
     this.temporaryDirectory = temporaryDirectory;
     // The determinant can be used to detect if the basis-change has a mirroring.
     // This matters because a mirroring turns the triangles inside-out, requiring
     // us to flip their winding to preserve the surface orientation.
     this.reverseWinding = (GetFromUnity_Axes(this).determinant < 0);
 }
Beispiel #5
0
        /// Given a transform, returns that transform in another basis.
        /// Since it's a Transform, xfInput is in Global (Room) space, Unity axes, decimeters.
        /// The new basis is: Scene space, with the Payload's axes and units.
        public static Matrix4x4 ChangeBasis(
            Transform xfInput, SceneStatePayload payload)
        {
            Matrix4x4 basis        = AxisConvention.GetFromUnity(payload.axes);
            Matrix4x4 basisInverse = AxisConvention.GetToUnity(payload.axes);

            return(ChangeBasis(App.Scene.AsScene[xfInput], basis, basisInverse)
                   .TransformBy(TrTransform.S(payload.exportUnitsFromAppUnits))
                   .ToMatrix4x4());
        }
Beispiel #6
0
        // This exports the scene into glTF. Brush strokes are exported in the style of the FBX exporter
        // by building individual meshes for the brush strokes, merging them by brush type, and exporting
        // the merged meshes. The merged meshes are split at 64k vert boundaries as required by Unity.
        // Also, scene lights are exported.
        // Pass:
        //   doExtras - true to add a bunch of poly-specific metadata to the scene
        //   selfContained - true to force a more-compatible gltf that doesn't have http:// URIs
        //     The drawback is that the result is messier and contains data that TBT does not need.
        public ExportResults ExportBrushStrokes(
            string outputFile, AxisConvention axes, bool binary, bool doExtras,
            bool includeLocalMediaContent, int gltfVersion,
            bool selfContained = false)
        {
            var payload = ExportCollector.GetExportPayload(
                axes,
                includeLocalMediaContent: includeLocalMediaContent,
                temporaryDirectory: Path.Combine(Application.temporaryCachePath, "exportgltf"));

            return(ExportHelper(payload, outputFile, binary, doExtras: doExtras, gltfVersion: gltfVersion,
                                allowHttpUri: !selfContained));
        }
Beispiel #7
0
        /// Plays back a named transform onto the current transform from a usd path.
        /// The transform can optionally be smoothed using exponential smoothing.
        /// Smoothing will be clamped between 0 - 1.
        public void StartPlayback(string sketchName = "/Sketch", string xformName = "/VideoCamera",
                                  float smoothing   = 0)
        {
            m_xformName   = xformName;
            m_Smoothing   = Mathf.Clamp01(smoothing);
            m_IsRecording = false;

            // Older versions of Tilt Brush exported usda camera paths in decimeters. We now
            // export in meters to match USD geometry export. Older versions also didn't export any sketch
            // data so we check here for the presence of sketch data to decide how to treat the camera
            // path units.
            bool hasSketchRoot = m_Scene.Stage.GetPrimAtPath(new pxr.SdfPath(sketchName));

            m_xformName = hasSketchRoot ? sketchName + xformName : xformName;
            float scale = hasSketchRoot ? App.UNITS_TO_METERS : 1;

            m_UnitsInMeters = hasSketchRoot;

            m_Scene.Time            = null;
            m_UsdCameraInfo         = new UsdCameraSample();
            m_UsdCameraInfo.shutter = new USD.NET.Unity.CameraSample.Shutter();
            m_Scene.Read(m_xformName, m_UsdCameraInfo);

            m_UsdCamera  = new UsdCameraXformSample();
            m_Scene.Time = 0;

            m_Scene.Read(m_xformName, m_UsdCamera);
            var basisMat = AxisConvention.GetFromUnity(AxisConvention.kUsd)
                           * Matrix4x4.Scale(Vector3.one * scale);

            m_UsdCamera.transform = ExportUtils.ChangeBasis(m_UsdCamera.transform, basisMat, basisMat.inverse);

            TrTransform xf_WS = UsdXformToWorldSpaceXform(m_UsdCamera);

            xf_WS.ToTransform(transform);

            m_PlaybackCameras = FindObjectsOfType <Camera>();
        }
Beispiel #8
0
        // Populates glTF metadata and scene extras fields.
        private void SetExtras(
            GlTF_ScriptableExporter exporter, ExportUtils.SceneStatePayload payload)
        {
            Color   skyColorA      = payload.env.skyColorA;
            Color   skyColorB      = payload.env.skyColorB;
            Vector3 skyGradientDir = payload.env.skyGradientDir;

            // Scene-level extras:
            exporter.G.extras["TB_EnvironmentGuid"] = payload.env.guid.ToString("D");
            exporter.G.extras["TB_Environment"]     = payload.env.description;
            exporter.G.extras["TB_UseGradient"]     = payload.env.useGradient ? "true" : "false";
            exporter.G.extras["TB_SkyColorA"]       = CommaFormattedFloatRGB(skyColorA);
            exporter.G.extras["TB_SkyColorB"]       = CommaFormattedFloatRGB(skyColorB);
            Matrix4x4 exportFromUnity = AxisConvention.GetFromUnity(payload.axes);

            exporter.G.extras["TB_SkyGradientDirection"] = CommaFormattedVector3(
                exportFromUnity * skyGradientDir);
            exporter.G.extras["TB_FogColor"]   = CommaFormattedFloatRGB(payload.env.fogColor);
            exporter.G.extras["TB_FogDensity"] = payload.env.fogDensity.ToString();

            // TODO: remove when Poly starts using the new color data
            exporter.G.extras["TB_SkyColorHorizon"] = CommaFormattedFloatRGB(skyColorA);
            exporter.G.extras["TB_SkyColorZenith"]  = CommaFormattedFloatRGB(skyColorB);
        }
Beispiel #9
0
        public static SceneStatePayload GetExportPayloadForGameObject(GameObject gameObject,
                                                                      AxisConvention axes,
                                                                      Environment env)
        {
            var payload = new SceneStatePayload(axes);

            payload.env.skyCubemap = env == null ? null : env.m_RenderSettings.m_SkyboxCubemap;
            payload.lights         = new ExportUtils.LightsPayload();
            // unused test code
#if TEST_ENVIRONMENTS_WITH_SCENE_LIGHTS
            {
                var lights = payload.lights;
                lights.ambientColor = RenderSettings.ambientLight;

#if true
                // Scene lights from Standard enviroment
                lights.elements.Add(new ExportUtils.Light {
                    name       = "SceneLight0",
                    id         = 0,
                    type       = LightType.Directional,
                    lightColor = new Color32(198, 208, 253),
                    xform      = ExportUtils.ChangeBasisNonUniformScale(
                        payload, Matrix4x4.TRS(
                            new Vector3(0f, 0.21875f, -.545875f),
                            Quaternion.Euler(60, 0, 26),
                            Vector3.one))
                });

                lights.elements.Add(new ExportUtils.Light {
                    name       = "SceneLight1",
                    id         = 1,
                    type       = LightType.Directional,
                    lightColor = new Color32(109, 107, 88),
                    xform      = ExportUtils.ChangeBasisNonUniformScale(
                        payload,
                        Matrix4x4.TRS(
                            new Vector3(0f, 0.21875f, -.545875f),
                            Quaternion.Euler(140, 0, 40),
                            Vector3.one)),
                });
#else
                // Scene lights from Dress Form environment
                lights.elements.Add(new ExportUtils.Light {
                    name       = "SceneLight0",
                    id         = 0,
                    type       = LightType.Directional,
                    lightColor = new Color32(255, 234, 198),
                    xform      = ExportUtils.ChangeBasisNonUniformScale(
                        payload, Matrix4x4.TRS(
                            new Vector3(0f, 0.7816665f, -.220875f),
                            Quaternion.Euler(50, 42, 26),
                            Vector3.one))
                });

                lights.elements.Add(new ExportUtils.Light {
                    name       = "SceneLight1",
                    id         = 1,
                    type       = LightType.Directional,
                    lightColor = new Color32(91, 90, 74),
                    xform      = ExportUtils.ChangeBasisNonUniformScale(
                        payload,
                        Matrix4x4.TRS(
                            new Vector3(0f, .636532f, -.6020539f),
                            Quaternion.Euler(140, 47, 40),
                            Vector3.one)),
                });
#endif
            }
#endif

            // The determinant can be used to detect if the basis-change has a mirroring.
            // This matters because a mirroring turns the triangles inside-out, requiring
            // us to flip their winding to preserve the surface orientation.
            bool reverseTriangleWinding = (ExportUtils.GetBasisMatrix(payload).determinant < 0);

            BuildModelMeshesFromGameObject(gameObject, payload, reverseTriangleWinding);
            return(payload);
        }
Beispiel #10
0
        // -------------------------------------------------------------------------------------------- //
        // Public API
        // -------------------------------------------------------------------------------------------- //

        public static SceneStatePayload GetExportPayload(
            AxisConvention axes,
            bool includeLocalMediaContent = false,
            string temporaryDirectory     = null)
        {
            UnityEngine.Profiling.Profiler.BeginSample("GetSceneStatePayload");

            var payload = new SceneStatePayload(axes, temporaryDirectory);

            BuildGenerator(payload);
            BuildEnvironment(payload);
            BuildLights(payload);

            UnityEngine.Profiling.Profiler.BeginSample("BuildBrushMeshes");
            BuildBrushMeshes(payload);
            UnityEngine.Profiling.Profiler.EndSample();

            {
                bool IsModelExportable(ModelWidget w)
                {
                    if (!w.Model.AllowExport)
                    {
                        return(false);
                    }
                    if (w.Model.GetLocation().GetLocationType() == Model.Location.Type.LocalFile)
                    {
                        return(includeLocalMediaContent && App.Config.m_EnableReferenceModelExport);
                    }
                    else
                    {
                        return(true);
                    }
                }

                UnityEngine.Profiling.Profiler.BeginSample("BuildModelMeshes");
                // TODO: inactive ModelWidgets should be fixed in WidgetManager.
                var(exportable, notExportable) = WidgetManager.m_Instance.ModelWidgets
                                                 .Where(w => w.Model != null && w.isActiveAndEnabled)
                                                 .Partition(IsModelExportable);
                BuildModelsAsModelMeshes(payload, exportable);
                BuildEmptyXforms(payload, notExportable);
                UnityEngine.Profiling.Profiler.EndSample();
            }

            {
                bool IsImageExportable(ImageWidget w)
                {
                    return(includeLocalMediaContent && w.ReferenceImage != null);
                }

                var media2dWidgets = WidgetManager.m_Instance.MediaWidgets
                                     .Select(grab => grab.m_WidgetScript as Media2dWidget)
                                     .Where(w => w != null && w.isActiveAndEnabled);
                var(images, notImages)         = media2dWidgets.Partition(w => w is ImageWidget);
                var(exportable, notExportable) = images.Cast <ImageWidget>().Partition(IsImageExportable);

                foreach (var group in exportable.GroupBy(widget => widget.ReferenceImage))
                {
                    ReferenceImage ri = group.Key;
                    if (ri == null)
                    {
                        Debug.Assert(false, "Empty ImageWidgets");
                        continue;
                    }
                    var material = CreateImageQuadMaterial(ri);
                    foreach ((ImageWidget image, int idx) in group.WithIndex())
                    {
                        payload.imageQuads.Add(BuildImageQuadPayload(payload, image, material, idx));
                    }
                }

                BuildEmptyXforms(payload, notImages);
                BuildEmptyXforms(payload, notExportable);
            }

            UnityEngine.Profiling.Profiler.EndSample();
            return(payload);
        }
Beispiel #11
0
 public static SceneStatePayload GetSceneStateForGameObjectForExport(
     GameObject gameObject, AxisConvention axes, Environment env)
 {
     return(ExportCollector.GetExportPayloadForGameObject(gameObject, axes, env));
 }
Beispiel #12
0
 /// Returns a basis-change matrix that transforms from Unity axis conventions to
 /// the conventions specified in the payload.
 ///
 /// Does *not* perform unit conversion, hence the name.
 public static Matrix4x4 GetFromUnity_Axes(SceneStatePayload payload)
 {
     return(AxisConvention.GetFromUnity(payload.axes));
 }
Beispiel #13
0
 /// General-purpose conversion.
 public static Matrix4x4 GetToDstFromSrc(AxisConvention dst, AxisConvention src)
 {
     // It doesn't really matter which system we pivot through, so use Unity
     return(GetFromUnity(dst) * GetToUnity(src));
 }
Beispiel #14
0
 /// Returns a matrix that converts to Unity's axis conventions from src.
 public static Matrix4x4 GetToUnity(AxisConvention src)
 {
     // transpose == inverse since these conversions are all orthonormal.
     return(GetFromUnity(src).transpose);
 }