Skip to content

Commit 2516ea7

Browse files
authored
Merge pull request #491 from Unity-Technologies/UT-2939-derisk-anim-roundtrip-apis
Ut 2939 Add FBX recorder
2 parents 9383351 + c6ba2ce commit 2516ea7

14 files changed

+333
-12
lines changed

com.unity.formats.fbx/Editor/CameraVisitor.cs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
using UnityEngine;
22
using Autodesk.Fbx;
33
using UnityEditor.Formats.Fbx.Exporter.CustomExtensions;
4+
using System.Collections.Generic;
45

56
namespace UnityEditor.Formats.Fbx.Exporter
67
{
78
namespace Visitors
89
{
910
internal static class CameraVisitor
1011
{
12+
private static Dictionary<Camera.GateFitMode, FbxCamera.EGateFit> s_mapGateFit = new Dictionary<Camera.GateFitMode, FbxCamera.EGateFit>()
13+
{
14+
{ Camera.GateFitMode.Fill, FbxCamera.EGateFit.eFitFill },
15+
{ Camera.GateFitMode.Horizontal, FbxCamera.EGateFit.eFitHorizontal },
16+
{ Camera.GateFitMode.None, FbxCamera.EGateFit.eFitNone },
17+
{ Camera.GateFitMode.Overscan, FbxCamera.EGateFit.eFitOverscan },
18+
{ Camera.GateFitMode.Vertical, FbxCamera.EGateFit.eFitVertical }
19+
};
20+
1121
/// <summary>
1222
/// Visit Object and configure FbxCamera
1323
/// </summary>
@@ -56,6 +66,14 @@ private static void ConfigureGameCamera (FbxCamera fbxCamera, Camera unityCamera
5666
return ;
5767
}
5868

69+
public static Vector2 GetSizeOfMainGameView()
70+
{
71+
System.Type T = System.Type.GetType("UnityEditor.GameView,UnityEditor");
72+
System.Reflection.MethodInfo GetSizeOfMainGameView = T.GetMethod("GetSizeOfMainGameView", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
73+
System.Object Res = GetSizeOfMainGameView.Invoke(null, null);
74+
return (Vector2)Res;
75+
}
76+
5977
/// <summary>
6078
/// Configure FbxCameras from a Physical Camera
6179
/// </summary>
@@ -80,16 +98,19 @@ private static void ConfigurePhysicalCamera (FbxCamera fbxCamera, Camera unityCa
8098

8199
fbxCamera.ProjectionType.Set(projectionType);
82100
fbxCamera.FilmAspectRatio.Set(aspectRatio);
101+
102+
Vector2 gameViewSize = GetSizeOfMainGameView();
103+
fbxCamera.SetAspect(FbxCamera.EAspectRatioMode.eFixedRatio, gameViewSize.x/gameViewSize.y, 1.0);
83104
fbxCamera.SetApertureWidth (apertureWidthInInches);
84105
fbxCamera.SetApertureHeight (apertureHeightInInches);
85106

86107
// Fit the resolution gate horizontally within the film gate.
87-
fbxCamera.GateFit.Set(FbxCamera.EGateFit.eFitHorizontal);
108+
fbxCamera.GateFit.Set(s_mapGateFit[unityCamera.gateFit]);
88109

89110
// Lens Shift ( Film Offset ) as a percentage 0..1
90111
// FBX FilmOffset is in inches
91-
fbxCamera.FilmOffsetX.Set(apertureWidthInInches * Mathf.Clamp(unityCamera.lensShift.x, 0f, 1f));
92-
fbxCamera.FilmOffsetY.Set(apertureHeightInInches * Mathf.Clamp(unityCamera.lensShift.y, 0f, 1f));
112+
fbxCamera.FilmOffsetX.Set(apertureWidthInInches * Mathf.Clamp(Mathf.Abs(unityCamera.lensShift.x), 0f, 1f) * Mathf.Sign(unityCamera.lensShift.x));
113+
fbxCamera.FilmOffsetY.Set(apertureHeightInInches * Mathf.Clamp(Mathf.Abs(unityCamera.lensShift.y), 0f, 1f) * Mathf.Sign(unityCamera.lensShift.y));
93114

94115
// Focal Length
95116
fbxCamera.SetApertureMode (FbxCamera.EApertureMode.eFocalLength);
@@ -102,7 +123,6 @@ private static void ConfigurePhysicalCamera (FbxCamera fbxCamera, Camera unityCa
102123

103124
// FarPlane
104125
fbxCamera.SetFarPlane ((float)unityCamera.farClipPlane.Meters().ToCentimeters());
105-
106126
return ;
107127
}
108128
}

com.unity.formats.fbx/Editor/FbxExporter.cs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,14 +1984,22 @@ private void ExportAnimationCurve (FbxNode fbxNode,
19841984
Debug.LogError (string.Format ("no fbx property {0} found on {1} node or nodeAttribute ", fbxPropertyChannelPair.Property, fbxNode.GetName ()));
19851985
return;
19861986
}
1987+
if (!fbxProperty.GetFlag(FbxPropertyFlags.EFlags.eAnimatable))
1988+
{
1989+
Debug.LogErrorFormat("fbx property {0} found on node {1} is not animatable", fbxPropertyChannelPair.Property, fbxNode.GetName());
1990+
}
19871991

19881992
// Create the AnimCurve on the channel
19891993
FbxAnimCurve fbxAnimCurve = fbxProperty.GetCurve (fbxAnimLayer, fbxPropertyChannelPair.Channel, true);
1994+
if(fbxAnimCurve == null)
1995+
{
1996+
return;
1997+
}
19901998

19911999
// create a convert scene helper so that we can convert from Unity to Maya
19922000
// AxisSystem (LeftHanded to RightHanded) and FBX's default units
19932001
// (Meters to Centimetres)
1994-
var convertSceneHelper = new UnityToMayaConvertSceneHelper (uniPropertyName);
2002+
var convertSceneHelper = new UnityToMayaConvertSceneHelper (uniPropertyName, fbxNode);
19952003

19962004
// TODO: we'll resample the curve so we don't have to
19972005
// configure tangents
@@ -2008,10 +2016,14 @@ internal class UnityToMayaConvertSceneHelper
20082016
bool convertDistance = false;
20092017
bool convertLtoR = false;
20102018
bool convertToRadian = false;
2019+
bool convertLensShiftX = false;
2020+
bool convertLensShiftY = false;
2021+
2022+
FbxCamera camera = null;
20112023

20122024
float unitScaleFactor = 1f;
20132025

2014-
public UnityToMayaConvertSceneHelper(string uniPropertyName)
2026+
public UnityToMayaConvertSceneHelper(string uniPropertyName, FbxNode fbxNode)
20152027
{
20162028
System.StringComparison cc = System.StringComparison.CurrentCulture;
20172029

@@ -2025,6 +2037,12 @@ public UnityToMayaConvertSceneHelper(string uniPropertyName)
20252037
convertDistance |= partT;
20262038
convertDistance |= uniPropertyName.StartsWith ("m_Intensity", cc);
20272039
convertDistance |= uniPropertyName.ToLower().EndsWith("weight", cc);
2040+
convertLensShiftX |= uniPropertyName.StartsWith("m_LensShift.x", cc);
2041+
convertLensShiftY |= uniPropertyName.StartsWith("m_LensShift.y", cc);
2042+
if (convertLensShiftX || convertLensShiftY)
2043+
{
2044+
camera = fbxNode.GetCamera();
2045+
}
20282046

20292047
// The ParentConstraint's source Rotation Offsets are read in as radians, so make sure they are exported as radians
20302048
convertToRadian = uniPropertyName.StartsWith("m_RotationOffsets.Array.data", cc);
@@ -2043,9 +2061,26 @@ public UnityToMayaConvertSceneHelper(string uniPropertyName)
20432061

20442062
public float Convert(float value)
20452063
{
2064+
float convertedValue = value;
2065+
if (convertLensShiftX || convertLensShiftY)
2066+
{
2067+
convertedValue = Mathf.Clamp(Mathf.Abs(value), 0f, 1f)*Mathf.Sign(value);
2068+
}
2069+
if (camera != null)
2070+
{
2071+
if (convertLensShiftX)
2072+
{
2073+
convertedValue *= (float)camera.GetApertureWidth();
2074+
}
2075+
else if (convertLensShiftY)
2076+
{
2077+
convertedValue *= (float)camera.GetApertureHeight();
2078+
}
2079+
}
2080+
20462081
// left handed to right handed conversion
20472082
// meters to centimetres conversion
2048-
return unitScaleFactor * value;
2083+
return unitScaleFactor * convertedValue;
20492084
}
20502085

20512086
}

com.unity.formats.fbx/Editor/FbxPropertyChannelPair.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ public PropertyChannelMap(Dictionary<string,string> propertyMap, Dictionary<stri
9090
{
9191
{ "m_Intensity", "Intensity" },
9292
{ "field of view", "FieldOfView" },
93-
{ "m_Weight", "Weight" }
93+
{ "m_Weight", "Weight" },
94+
{ "m_FocalLength", "FocalLength" },
95+
{ "m_LensShift.x", "FilmOffsetX" },
96+
{ "m_LensShift.y", "FilmOffsetY" }
9497
};
9598

9699
/// <summary>

com.unity.formats.fbx/Editor/Sources.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

com.unity.formats.fbx/Editor/Sources/Recorders.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

com.unity.formats.fbx/Editor/Sources/Recorders/FbxRecorder.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
using UnityEditor.Recorder;
5+
using UnityEditor.Recorder.Input;
6+
using UnityEditor;
7+
8+
namespace UnityEditor.Formats.Fbx.Exporter
9+
{
10+
class FbxRecorder : GenericRecorder<FbxRecorderSettings>
11+
{
12+
protected override void RecordFrame(RecordingSession ctx)
13+
{
14+
15+
}
16+
17+
protected override void EndRecording(RecordingSession session)
18+
{
19+
var settings = (FbxRecorderSettings)session.settings;
20+
21+
foreach (var input in m_Inputs)
22+
{
23+
24+
var aInput = (AnimationInput)input;
25+
26+
if (aInput.GameObjectRecorder == null)
27+
continue;
28+
29+
var clip = new AnimationClip();
30+
31+
settings.FileNameGenerator.CreateDirectory(session);
32+
33+
var absolutePath = FileNameGenerator.SanitizePath(settings.FileNameGenerator.BuildAbsolutePath(session));
34+
var clipName = absolutePath.Replace(FileNameGenerator.SanitizePath(Application.dataPath), "Assets");
35+
36+
#if UNITY_2018_3_OR_NEWER
37+
aInput.GameObjectRecorder.SaveToClip(clip, settings.FrameRate);
38+
#else
39+
aInput.gameObjectRecorder.SaveToClip(clip);
40+
#endif
41+
var root = ((AnimationInputSettings)aInput.settings).gameObject;
42+
clip.name = "recorded_clip";
43+
clip.legacy = true;
44+
Animation animator = root.GetComponent<Animation>();
45+
bool hasAnimComponent = true;
46+
if (!animator)
47+
{
48+
animator = root.AddComponent<Animation>();
49+
hasAnimComponent = false;
50+
}
51+
52+
AnimationClip[] prevAnimClips = null;
53+
if (hasAnimComponent)
54+
{
55+
prevAnimClips = AnimationUtility.GetAnimationClips(root);
56+
}
57+
58+
AnimationUtility.SetAnimationClips(animator, new AnimationClip[] { clip });
59+
var exportSettings = new ExportModelSettingsSerialize();
60+
var toInclude = ExportSettings.Include.ModelAndAnim;
61+
if (!settings.ExportGeometry)
62+
{
63+
toInclude = ExportSettings.Include.Anim;
64+
}
65+
exportSettings.SetModelAnimIncludeOption(toInclude);
66+
ModelExporter.ExportObject(clipName, root, exportSettings);
67+
68+
69+
if (hasAnimComponent)
70+
{
71+
AnimationUtility.SetAnimationClips(animator, prevAnimClips);
72+
}
73+
else
74+
{
75+
Object.DestroyImmediate(animator);
76+
}
77+
aInput.GameObjectRecorder.ResetRecording();
78+
}
79+
base.EndRecording(session);
80+
}
81+
}
82+
}

com.unity.formats.fbx/Editor/Sources/Recorders/FbxRecorder/FbxRecorder.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
using UnityEditor.Recorder;
5+
using UnityEditor.Recorder.Input;
6+
7+
namespace UnityEditor.Formats.Fbx.Exporter
8+
{
9+
[RecorderSettings(typeof(FbxRecorder), "FBX", "fbx_recorder")]
10+
public class FbxRecorderSettings : RecorderSettings
11+
{
12+
[SerializeField] bool m_exportGeometry = true;
13+
public bool ExportGeometry
14+
{
15+
get
16+
{
17+
return m_exportGeometry;
18+
}
19+
set
20+
{
21+
m_exportGeometry = value;
22+
}
23+
}
24+
25+
[SerializeField] AnimationInputSettings m_AnimationInputSettings = new AnimationInputSettings();
26+
27+
public AnimationInputSettings animationInputSettings
28+
{
29+
get { return m_AnimationInputSettings; }
30+
set { m_AnimationInputSettings = value; }
31+
}
32+
33+
public FbxRecorderSettings()
34+
{
35+
var goWildcard = DefaultWildcard.GeneratePattern("GameObject");
36+
37+
FileNameGenerator.AddWildcard(goWildcard, GameObjectNameResolver);
38+
FileNameGenerator.AddWildcard(DefaultWildcard.GeneratePattern("GameObjectScene"), GameObjectSceneNameResolver);
39+
40+
FileNameGenerator.ForceAssetsFolder = false;
41+
FileNameGenerator.Root = OutputPath.Root.AssetsFolder;
42+
FileNameGenerator.FileName = "animation_" + goWildcard + "_" + DefaultWildcard.Take;
43+
}
44+
45+
string GameObjectNameResolver(RecordingSession session)
46+
{
47+
var go = m_AnimationInputSettings.gameObject;
48+
return go != null ? go.name : "None";
49+
}
50+
51+
string GameObjectSceneNameResolver(RecordingSession session)
52+
{
53+
var go = m_AnimationInputSettings.gameObject;
54+
return go != null ? go.scene.name : "None";
55+
}
56+
57+
public override bool IsPlatformSupported
58+
{
59+
get
60+
{
61+
return Application.platform == RuntimePlatform.LinuxEditor ||
62+
Application.platform == RuntimePlatform.OSXEditor ||
63+
Application.platform == RuntimePlatform.WindowsEditor;
64+
}
65+
}
66+
67+
public override IEnumerable<RecorderInputSettings> InputsSettings
68+
{
69+
get { yield return m_AnimationInputSettings; }
70+
}
71+
72+
protected override bool ValidityCheck(List<string> errors)
73+
{
74+
var ok = base.ValidityCheck(errors);
75+
76+
if (m_AnimationInputSettings.gameObject == null)
77+
{
78+
ok = false;
79+
errors.Add("No input object set");
80+
}
81+
82+
return ok;
83+
}
84+
85+
public override void OnAfterDuplicate()
86+
{
87+
m_AnimationInputSettings.DuplicateExposedReference();
88+
}
89+
90+
void OnDestroy()
91+
{
92+
m_AnimationInputSettings.ClearExposedReference();
93+
}
94+
95+
protected override string Extension
96+
{
97+
get { return "fbx"; }
98+
}
99+
}
100+
}

com.unity.formats.fbx/Editor/Sources/Recorders/FbxRecorder/FbxRecorderSettings.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)