Skip to content

Commit fd48735

Browse files
judubuvickycllee-aandrew
authored
Fix Export Transform Overrides (#USDU-216) (#279)
* Fix the XForm override export and add the option to the recorder * Remove sublayers, remove ref from root, ass tests * Rename exportXformOverride to exportTransformOverride * Update changelog * Fix UI Labels to workaround layout issues * Fixes from PR review. - Fix for null ref exception when the source GO is not a UsdAsset - Fix for unclear UI * XFormable schema type should not override the actual schema type. * Removes the reference to the original file from exported override files written out by Recorder. * Switch transform export back to Xform from Xformable, because using base UsdGeomXformable prim types is unusual --------- Co-authored-by: Vicky Clark <[email protected]> Co-authored-by: Andrew Lee <[email protected]> Co-authored-by: Vicky Clark <[email protected]>
1 parent 5f70448 commit fd48735

14 files changed

+248
-83
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,5 @@ TestProject/**/Logs
7272
TestProject/**/*.csproj
7373
TestProject/**/*.sln
7474
TestProject/Usd-Development/Library
75+
TestProject/Usd-Development/.vs
7576
build_usdcs

README.md

+28
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,34 @@ When compatibility with runtime is required (i.e for a standalone build), the re
124124

125125
> **Note:** This feature has no dependency to and is not based on the Recorder package.
126126
127+
### Exporting Transform Overrides
128+
129+
Modifications to transforms in USD files can be exported as overrides to the original files.
130+
131+
Overrides can be exported from the USD menu with the GameObject containing the UsdAsset component selected, which will export transform overrides for the entire hierarchy. Alternatively, you can also export just the overrides when exporting from the Recorder window by changing the 'Override Setting' to 'Export Transform Overrides Only'.
132+
133+
For full asset pipeline flexibility these override files do not include a reference to the original file, but this can be added by manually adding a sublayer in the header of the resulting USDA file:
134+
135+
```
136+
#usda 1.0
137+
(
138+
defaultPrim = "myCube"
139+
endTimeCode = 0
140+
startTimeCode = 0
141+
upAxis = "Y"
142+
subLayers = [
143+
@c:/path/to/original/myCube.usda@
144+
]
145+
)
146+
147+
over "myCube"
148+
{
149+
...
150+
}
151+
```
152+
153+
Note: Modifications to the transform of the Root GameObject is not currently reflected in the override, as Unity assumes the root in all USD files is at the origin.
154+
127155
# License
128156

129157
The USD Unity SDK is licensed under the terms of the Apache

package/com.unity.formats.usd/CHANGELOG.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
# Changes in usd-unitysdk for Unity
1+
# Changes in usd-unity-sdk for Unity
22

33
## Unreleased
4+
### Features
5+
- The USD Recorder now has an option to export transform overrides.
6+
47
### Bug Fixes
8+
- "Export Transform Override" now properly exports modified transforms only.
59
- Fixed a bug where importing materials exported from USD version >= 21.11 would fail.
610
- Fixed loading of meshes with arbitrary primvars.
711
- Fixed regression in animated mesh properties.
@@ -17,7 +21,7 @@
1721
- Fixed an import bug causing instanced primitives not to be sanitized to fit Unity formats, including converting basis, triangulating and unwinding meshes, and unrolling primvars.
1822

1923
### Changed
20-
- GC allocs reduced by half for Scene.GetAttributeAtPath and Scene.GetRelationshipAtPath
24+
- GC allocs reduced by half for Scene.GetAttributeAtPath and Scene.GetRelationshipAtPath.
2125
- Disabled plugins on unsupported platforms.
2226
- Optimized triangulation to reduce the chance of a "Timed out while waiting for thread" error on importing a complex mesh.
2327
- Optimized PointInstance importing.

package/com.unity.formats.usd/Editor/Recorder/Editors/UsdRecorderSettingsEditor.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#if RECORDER_AVAILABLE
22
using UnityEditor.Recorder;
3+
using UnityEngine;
34

45
namespace UnityEditor.Formats.USD.Recorder
56
{
@@ -12,7 +13,8 @@ protected override void FileTypeAndFormatGUI()
1213
EditorGUILayout.PropertyField(serializedObject.FindProperty("interpolationType"));
1314
EditorGUILayout.PropertyField(serializedObject.FindProperty("coordinateConversion"));
1415
EditorGUILayout.PropertyField(serializedObject.FindProperty("activePolicy"));
15-
EditorGUILayout.PropertyField(serializedObject.FindProperty("exportMaterials"));
16+
EditorGUILayout.PropertyField(serializedObject.FindProperty("exportTransformOverrides"), new GUIContent("Override Setting"));
17+
EditorGUILayout.PropertyField(serializedObject.FindProperty("exportMaterials"), new GUIContent("Materials"));
1618
EditorGUILayout.PropertyField(serializedObject.FindProperty("scale"));
1719
}
1820
}

package/com.unity.formats.usd/Editor/Recorder/UsdRecorder.cs

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ protected override void SessionCreated(RecordingSession session)
7070
context.basisTransform = Settings.BasisTransformation;
7171
context.activePolicy = Settings.ActivePolicy;
7272
context.exportMaterials = Settings.ExportMaterials;
73+
context.exportTransformOverrides = Settings.ExportTransformOverrides;
7374

7475
context.scale = Settings.Scale;
7576

package/com.unity.formats.usd/Editor/Recorder/UsdRecorderInput.cs

+19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#if RECORDER_AVAILABLE
22
using Unity.Formats.USD;
33
using UnityEditor.Recorder;
4+
using USD.NET;
45

56
namespace UnityEditor.Formats.USD.Recorder
67
{
@@ -11,10 +12,28 @@ public class UsdRecorderInput : RecorderInput
1112

1213
protected override void BeginRecording(RecordingSession session)
1314
{
15+
if (Context.exportTransformOverrides)
16+
{
17+
// Settings.
18+
UsdAsset usdAsset = Settings.GameObject.GetComponentInParent<UsdAsset>(); // Get the UsdAsset component in this GameObject or its nearest parent
19+
if (usdAsset != null)
20+
{
21+
Context.scene.AddSubLayer(usdAsset.GetScene());
22+
Context.scene.WriteMode = Scene.WriteModes.Over;
23+
}
24+
else
25+
UnityEngine.Debug.LogError($"Unable to perform a 'transform overrides only' recording as <{Settings.GameObject.name}> is not a UsdAsset.");
26+
}
1427
SceneExporter.SyncExportContext(Settings.GameObject, Context);
1528
SceneExporter.Export(Settings.GameObject,
1629
Context,
1730
zeroRootTransform: false);
31+
32+
if (Context.exportTransformOverrides)
33+
{
34+
// this is very brittle- if we have the chance of other sublayers in future we should store the index it was added at and only erase that one.
35+
Context.scene.Stage.GetRootLayer().GetSubLayerPaths().Erase(0);
36+
}
1837
}
1938

2039
protected override void NewFrameReady(RecordingSession session)

package/com.unity.formats.usd/Editor/Recorder/UsdRecorderSettings.cs

+13
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public class UsdRecorderSettings : RecorderSettings
1818
[SerializeField] ActiveExportPolicy activePolicy = ActiveExportPolicy.ExportAsVisibility;
1919
[SerializeField] bool exportMaterials = true;
2020
[SerializeField] float scale = 1;
21+
[SerializeField] ExportOverridesSetting exportTransformOverrides;
2122

2223
public UsdRecorderSettings()
2324
{
@@ -31,6 +32,12 @@ public enum Format
3132
USDZ,
3233
}
3334

35+
public enum ExportOverridesSetting
36+
{
37+
ExportInFull,
38+
ExportTransformOverridesOnly
39+
}
40+
3441
public UsdInterpolationType InterpolationType
3542
{
3643
get => interpolationType;
@@ -49,6 +56,12 @@ public bool ExportMaterials
4956
set => exportMaterials = value;
5057
}
5158

59+
public bool ExportTransformOverrides
60+
{
61+
get => exportTransformOverrides == ExportOverridesSetting.ExportTransformOverridesOnly ? true : false;
62+
set => exportTransformOverrides = value ? ExportOverridesSetting.ExportTransformOverridesOnly : ExportOverridesSetting.ExportInFull;
63+
}
64+
5265
public ActiveExportPolicy ActivePolicy
5366
{
5467
get => activePolicy;

package/com.unity.formats.usd/Editor/Unity.Formats.USD.Editor.api

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ namespace UnityEditor.Formats.USD.Recorder
8282
public Unity.Formats.USD.BasisTransformation BasisTransformation { get; set; }
8383
public UnityEditor.Formats.USD.Recorder.UsdRecorderSettings.Format ExportFormat { get; }
8484
public bool ExportMaterials { get; set; }
85+
public bool ExportTransformOverrides { get; set; }
8586
protected virtual string Extension { get; }
8687
public virtual System.Collections.Generic.IEnumerable<UnityEditor.Recorder.RecorderInputSettings> InputsSettings { get; }
8788
public pxr.UsdInterpolationType InterpolationType { get; set; }

package/com.unity.formats.usd/Runtime/Scripts/Behaviors/UsdAsset.cs

+7-6
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ public void ExportOverrides(Scene sceneInWhichToStoreTransforms)
600600
{
601601
throw new Exception("Could not open base layer: " + sceneToReference.usdFullPath);
602602
}
603+
overs.AddSubLayer(baseLayer);
603604

604605
overs.Time = baseLayer.Time;
605606
overs.StartTime = baseLayer.StartTime;
@@ -614,20 +615,20 @@ public void ExportOverrides(Scene sceneInWhichToStoreTransforms)
614615
overs,
615616
BasisTransformation.SlowAndSafe,
616617
exportUnvarying: false,
617-
zeroRootTransform: true);
618-
619-
var rel = ImporterBase.MakeRelativePath(overs.FilePath, sceneToReference.usdFullPath);
620-
GetFirstPrim(overs).GetReferences().AddReference(rel, GetFirstPrim(baseLayer).GetPath());
618+
zeroRootTransform: true,
619+
exportOverrides: true);
621620
}
622-
catch (System.Exception ex)
621+
catch (Exception ex)
623622
{
624623
Debug.LogException(ex);
625-
return;
626624
}
627625
finally
628626
{
629627
if (overs != null)
630628
{
629+
// Remove the reference to the original USD from the override file for flexibility in an asset pipeline
630+
// TODO: Make this an optional setting
631+
overs.Stage.GetRootLayer().GetSubLayerPaths().Erase(0);
631632
overs.Save();
632633
overs.Close();
633634
}

package/com.unity.formats.usd/Runtime/Scripts/IO/Geometry/XformExporter.cs

+25-4
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ public static void ExportXform(ObjectContext objContext, ExportContext exportCon
2525
UnityEngine.Profiling.Profiler.BeginSample("USD: Xform Conversion");
2626

2727
XformSample sample = (XformSample)objContext.sample;
28-
var localRot = objContext.gameObject.transform.localRotation;
29-
var localScale = objContext.gameObject.transform.localScale;
3028
var path = new pxr.SdfPath(objContext.path);
3129

3230
// If exporting for Z-Up, rotate the world.
@@ -37,9 +35,32 @@ public static void ExportXform(ObjectContext objContext, ExportContext exportCon
3735
correctZUp,
3836
path.IsRootPrimPath(),
3937
exportContext.basisTransform);
40-
4138
UnityEngine.Profiling.Profiler.EndSample();
4239

40+
// If exporting overrides, only export what changed
41+
if (exportContext.exportTransformOverrides)
42+
{
43+
UnityEngine.Profiling.Profiler.BeginSample("USD: Xform override check");
44+
var sourceSample = new XformSample();
45+
float tolerance = 0.0001f;
46+
exportContext.scene.Read(path, sourceSample);
47+
bool areClose = true;
48+
for (int i = 0; i < 16; i++)
49+
{
50+
if (Mathf.Abs(sample.transform[i] - sourceSample.transform[i]) > tolerance)
51+
{
52+
areClose = false;
53+
break;
54+
}
55+
}
56+
UnityEngine.Profiling.Profiler.EndSample();
57+
if (areClose)
58+
{
59+
return;
60+
}
61+
}
62+
63+
4364
UnityEngine.Profiling.Profiler.BeginSample("USD: Xform Write");
4465
exportContext.scene.Write(objContext.path, sample);
4566
UnityEngine.Profiling.Profiler.EndSample();
@@ -55,7 +76,7 @@ public static void WriteSparseOverrides(Scene scene,
5576

5677
try
5778
{
58-
foreach (var path in scene.Find<XformableSample>())
79+
foreach (var path in scene.Find<XformSample>())
5980
{
6081
GameObject go;
6182
if (!primMap.TryGetValue(path, out go))

0 commit comments

Comments
 (0)