Skip to content

Commit b47b3bc

Browse files
authored
Merge pull request #393 from Unity-Technologies/Uni-45921-physical-camera
Uni-45921-physical-camera
2 parents e06ad24 + 7e85c00 commit b47b3bc

File tree

11 files changed

+614
-113
lines changed

11 files changed

+614
-113
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// NOTE: uncomment the next line to leave temporary FBX files on disk
2+
// and create a imported object in the scene.
3+
//#define DEBUG_UNITTEST
4+
5+
using UnityEngine;
6+
using UnityEditor;
7+
using NUnit.Framework;
8+
using System.Collections.Generic;
9+
using System.Collections;
10+
using FbxExporters.CustomExtensions;
11+
using Unity.FbxSdk;
12+
13+
namespace FbxExporters.UnitTests
14+
{
15+
public class CustomExtensionsTest : ExporterTestBase
16+
{
17+
private float Value1 { get { return 1f; } }
18+
19+
[TearDown]
20+
public override void Term ()
21+
{
22+
#if (!DEBUG_UNITTEST)
23+
base.Term ();
24+
#endif
25+
}
26+
27+
[Test]
28+
public void Vector3ExtensionTest()
29+
{
30+
var v3 = new Vector3(1f,2f,3f);
31+
Assert.That(v3.RightHanded(), Is.EqualTo(new Vector3(-1f,2f,3f)));
32+
Assert.That(v3.FbxVector4(), Is.EqualTo(new FbxVector4(1f,2f,3f)));
33+
}
34+
35+
[Test]
36+
public void AnimationCurveExtensionTest()
37+
{
38+
var ac = new AnimationCurve();
39+
ac.Dump();
40+
ac.Dump("hello world");
41+
ac.Dump(keyTimesExpected:new float[]{});
42+
ac.Dump(keyValuesExpected:new float[]{});
43+
ac.Dump(keyTimesExpected:new float[]{}, keyValuesExpected:new float[]{});
44+
}
45+
46+
[Test]
47+
public void FloatExtensionTest()
48+
{
49+
Assert.That(Value1.Meters().ToCentimeters(), Is.EqualTo(100f));
50+
51+
Assert.That(1f.Meters(), Is.EqualTo(100f.Centimeters()));
52+
Assert.That(10f.Millimeters().ToMeters(), Is.EqualTo(1f.Centimeters().ToMeters()).Within(0.00001f));
53+
Assert.That(1f.Centimeters().ToMeters(), Is.EqualTo(10f.Millimeters().ToMeters()).Within(0.00001f));
54+
Assert.That(0.0254f.Meters(), Is.EqualTo(1f.Inches().ToMetric()));
55+
Assert.That(1f.Meters().ToImperial(), Is.EqualTo(39.3701f.Inches()));
56+
}
57+
58+
[Test]
59+
public void ImperialDistanceTest()
60+
{
61+
var one_inch = new ImperialDistance(1f); // 1 inch
62+
var one_foot = new ImperialDistance(12f); // 12 inches
63+
64+
Assert.That(ImperialDistance.Inch, Is.Not.EqualTo(new MetricDistance(1f)));
65+
Assert.That(ImperialDistance.Inch, Is.EqualTo(new ImperialDistance(1f)));
66+
Assert.That(ImperialDistance.Foot, Is.EqualTo(new ImperialDistance(12f)));
67+
68+
Assert.That(one_inch, Is.EqualTo(ImperialDistance.Inch));
69+
Assert.That(one_inch.ToInches(), Is.EqualTo(ImperialDistance.Inch.ToInches()));
70+
Assert.That(one_inch.ToMetric().ToMeters(), Is.EqualTo(0.0254f));
71+
Assert.That(one_inch.ToMeters(), Is.EqualTo(0.0254f));
72+
Assert.That(one_inch.ToInches(), Is.EqualTo(1f));
73+
Assert.That(one_inch.GetHashCode(), Is.GreaterThan(0));
74+
Assert.That(one_inch == ImperialDistance.Inch, Is.True);
75+
Assert.That(one_inch == ImperialDistance.Inch, Is.True);
76+
77+
Assert.That(one_foot, Is.EqualTo(ImperialDistance.Foot));
78+
Assert.That(one_foot!=one_inch, Is.True);
79+
80+
Assert.That(one_inch+one_inch, Is.EqualTo(new ImperialDistance(2f)));
81+
Assert.That(one_inch-one_inch, Is.EqualTo(new ImperialDistance(0f)));
82+
Assert.That(new ImperialDistance(2f)*new ImperialDistance(6f), Is.EqualTo(ImperialDistance.Foot));
83+
Assert.That(ImperialDistance.Foot / ImperialDistance.Inch, Is.EqualTo(ImperialDistance.Foot));
84+
}
85+
86+
[Test]
87+
public void MetricDistanceTest()
88+
{
89+
var one_cm = new MetricDistance(0.01f); // 1 cm
90+
var one_m = new MetricDistance(1f); // 100 cm
91+
92+
Assert.That(MetricDistance.Millimeter, Is.EqualTo(new MetricDistance(0.001f)));
93+
Assert.That(MetricDistance.Centimeter, Is.EqualTo(new MetricDistance(0.01f)));
94+
Assert.That(MetricDistance.Meter, Is.EqualTo(new MetricDistance(1f)));
95+
96+
Assert.That(one_m, Is.EqualTo(MetricDistance.Meter));
97+
Assert.That(one_m.ToMeters(), Is.EqualTo(MetricDistance.Meter.ToMeters()));
98+
Assert.That(one_m.ToImperial().ToInches(), Is.EqualTo(39.3701f));
99+
Assert.That(one_m.ToMeters(), Is.EqualTo(1f));
100+
Assert.That(one_m.GetHashCode(), Is.GreaterThan(0));
101+
Assert.That(one_m == MetricDistance.Meter, Is.True);
102+
Assert.That(one_cm == MetricDistance.Centimeter, Is.True);
103+
104+
Assert.That(one_m, Is.EqualTo(MetricDistance.Meter));
105+
Assert.That(one_m!=one_cm, Is.True);
106+
107+
Assert.That(one_m+one_cm, Is.EqualTo(new MetricDistance(1.01f)));
108+
Assert.That(one_m-one_cm, Is.EqualTo(new MetricDistance(0.99f)));
109+
Assert.That(MetricDistance.Centimeter*MetricDistance.Meter, Is.EqualTo(new MetricDistance(0.01f)));
110+
Assert.That(MetricDistance.Meter / MetricDistance.Centimeter, Is.EqualTo(new MetricDistance(100f)));
111+
}
112+
}
113+
}

Assets/com.unity.formats.fbx.tests/CustomExtensionsTest.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.

Assets/com.unity.formats.fbx.tests/FbxCameraTests.cs

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// NOTE: uncomment the next line to leave temporary FBX files on disk
1+
// NOTE: uncomment the next line to leave temporary FBX files on disk
22
// and create a imported object in the scene.
33
//#define DEBUG_UNITTEST
44

@@ -7,11 +7,14 @@
77
using NUnit.Framework;
88
using System.Collections.Generic;
99
using System.Collections;
10+
using FbxExporters.CustomExtensions;
1011

1112
namespace FbxExporters.UnitTests
1213
{
1314
public class FbxCameraTest : ExporterTestBase
1415
{
16+
const float EPSILON = 0.00001f;
17+
1518
[TearDown]
1619
public override void Term ()
1720
{
@@ -34,5 +37,81 @@ public void AnimationWithCameraFOVTest()
3437

3538
tester.DoIt();
3639
}
40+
41+
[Test]
42+
public void GameCameraTest()
43+
{
44+
var filename = GetRandomFileNamePath();
45+
46+
var original = FbxAnimationTest.AnimTester.CreateTargetObject("GameCamera", typeof (Camera));
47+
48+
var origCam = original.GetComponent<Camera>();
49+
50+
// Configure Game Camera
51+
origCam.fieldOfView = 59;
52+
53+
// FBX Value range is [0.001, 600000.0] centimeters
54+
// Unity Property Inspector range is [0.01, MAX_FLT] meters
55+
// Unity Importer range is [0.3, MAX_FLT] meters
56+
origCam.nearClipPlane = 30f.Centimeters().ToMeters(); // minumum
57+
origCam.farClipPlane = 6000f;
58+
59+
// Convert it to FBX. The asset file will be deleted automatically
60+
// on termination.
61+
var fbxAsset = FbxExporters.Editor.ModelExporter.ExportObject(
62+
filename, original);
63+
64+
// refresh the assetdata base so that we can query for the model
65+
AssetDatabase.Refresh ();
66+
67+
var source = AssetDatabase.LoadMainAssetAtPath(fbxAsset) as GameObject;
68+
var srcCam = source.GetComponent<Camera>();
69+
70+
Assert.That( srcCam.aspect, Is.EqualTo(origCam.aspect));
71+
Assert.That( srcCam.fieldOfView, Is.EqualTo(origCam.fieldOfView));
72+
Assert.That( srcCam.farClipPlane, Is.EqualTo(origCam.farClipPlane));
73+
Assert.That( srcCam.nearClipPlane, Is.EqualTo(origCam.nearClipPlane));
74+
}
75+
76+
[Test]
77+
public void PhysicalCameraTest()
78+
{
79+
var filename = GetRandomFileNamePath();
80+
81+
var original = FbxAnimationTest.AnimTester.CreateTargetObject("GameCamera", typeof (Camera));
82+
83+
var origCam = original.GetComponent<Camera>();
84+
85+
// Configure FilmBack Super 8mm, 5.79f x 4.01mm
86+
origCam.usePhysicalProperties = true;
87+
origCam.aspect = 4.01f / 5.79f;
88+
origCam.focalLength = 50f.Centimeters().ToMillimeters();
89+
origCam.sensorSize = new Vector2(5.79f, 4.01f);
90+
91+
// Lens Shift ( Film Offset ) as a percentage between 0 and 1
92+
origCam.lensShift = new Vector2(1f, 1f);
93+
94+
origCam.nearClipPlane = 30f.Centimeters().ToMeters();
95+
origCam.farClipPlane = 600000f.Centimeters().ToMeters();
96+
97+
// Convert it to FBX. The asset file will be deleted automatically
98+
// on termination.
99+
var fbxAsset = FbxExporters.Editor.ModelExporter.ExportObject(
100+
filename, original);
101+
102+
var source = AssetDatabase.LoadMainAssetAtPath(fbxAsset) as GameObject;
103+
var srcCam = source.GetComponent<Camera>();
104+
105+
Assert.That( srcCam.fieldOfView, Is.EqualTo(origCam.fieldOfView).Within(EPSILON));
106+
Assert.That( srcCam.focalLength, Is.EqualTo(origCam.focalLength));
107+
Assert.That( srcCam.sensorSize.x, Is.EqualTo(origCam.sensorSize.x).Within(EPSILON));
108+
Assert.That( srcCam.sensorSize.y, Is.EqualTo(origCam.sensorSize.y).Within(EPSILON));
109+
Assert.That( srcCam.usePhysicalProperties, Is.EqualTo(origCam.usePhysicalProperties));
110+
Assert.That( srcCam.lensShift.x, Is.EqualTo(origCam.lensShift.x).Within(EPSILON));
111+
Assert.That( srcCam.lensShift.y, Is.EqualTo(origCam.lensShift.y).Within(EPSILON));
112+
Assert.That( srcCam.aspect, Is.EqualTo(origCam.aspect).Within(EPSILON));
113+
Assert.That( srcCam.nearClipPlane, Is.EqualTo(origCam.nearClipPlane));
114+
Assert.That( srcCam.farClipPlane, Is.EqualTo(origCam.farClipPlane));
115+
}
37116
}
38117
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using UnityEngine;
2+
using Unity.FbxSdk;
3+
using FbxExporters.CustomExtensions;
4+
5+
namespace FbxExporters
6+
{
7+
namespace Visitors
8+
{
9+
internal static class CameraVisitor
10+
{
11+
/// <summary>
12+
/// Visit Object and configure FbxCamera
13+
/// </summary>
14+
public static void ConfigureCamera (Camera unityCamera, FbxCamera fbxCamera)
15+
{
16+
if (unityCamera.usePhysicalProperties)
17+
ConfigurePhysicalCamera(fbxCamera, unityCamera);
18+
else
19+
ConfigureGameCamera(fbxCamera, unityCamera);
20+
}
21+
22+
/// <summary>
23+
/// Configure FbxCameras from GameCamera
24+
/// </summary>
25+
private static void ConfigureGameCamera (FbxCamera fbxCamera, Camera unityCamera)
26+
{
27+
// Configure FilmBack settings as a 35mm TV Projection (0.816 x 0.612)
28+
float aspectRatio = unityCamera.aspect;
29+
30+
float apertureHeightInInches = 0.612f;
31+
float apertureWidthInInches = aspectRatio * apertureHeightInInches;
32+
33+
FbxCamera.EProjectionType projectionType =
34+
unityCamera.orthographic ? FbxCamera.EProjectionType.eOrthogonal : FbxCamera.EProjectionType.ePerspective;
35+
36+
fbxCamera.ProjectionType.Set(projectionType);
37+
fbxCamera.FilmAspectRatio.Set(aspectRatio);
38+
fbxCamera.SetApertureWidth (apertureWidthInInches);
39+
fbxCamera.SetApertureHeight (apertureHeightInInches);
40+
fbxCamera.SetApertureMode (FbxCamera.EApertureMode.eVertical);
41+
42+
// Focal Length
43+
double focalLength = fbxCamera.ComputeFocalLength (unityCamera.fieldOfView);
44+
45+
fbxCamera.FocalLength.Set(focalLength);
46+
47+
// Field of View
48+
fbxCamera.FieldOfView.Set (unityCamera.fieldOfView);
49+
50+
// NearPlane
51+
fbxCamera.SetNearPlane (unityCamera.nearClipPlane.Meters().ToCentimeters());
52+
53+
// FarPlane
54+
fbxCamera.SetFarPlane (unityCamera.farClipPlane.Meters().ToCentimeters());
55+
56+
return ;
57+
}
58+
59+
/// <summary>
60+
/// Configure FbxCameras from a Physical Camera
61+
/// </summary>
62+
private static void ConfigurePhysicalCamera (FbxCamera fbxCamera, Camera unityCamera)
63+
{
64+
Debug.Assert(unityCamera.usePhysicalProperties);
65+
66+
// Configure FilmBack settings
67+
float apertureHeightInInches = unityCamera.sensorSize.y.Millimeters().ToInches();
68+
float apertureWidthInInches = unityCamera.sensorSize.x.Millimeters().ToInches();
69+
float aspectRatio = apertureWidthInInches / apertureHeightInInches;
70+
71+
FbxCamera.EProjectionType projectionType = unityCamera.orthographic
72+
? FbxCamera.EProjectionType.eOrthogonal
73+
: FbxCamera.EProjectionType.ePerspective;
74+
75+
// NOTE: it is possible to match some of the sensor sizes to the
76+
// predefined EApertureFormats : e16mmTheatrical, eSuper16mm,
77+
// e35mmFullAperture, eIMAX. However the round in the sizes is not
78+
// consistent between Unity and FBX so we choose
79+
// to leave the values as a eCustomAperture setting.
80+
81+
fbxCamera.ProjectionType.Set(projectionType);
82+
fbxCamera.FilmAspectRatio.Set(aspectRatio);
83+
fbxCamera.SetApertureWidth (apertureWidthInInches);
84+
fbxCamera.SetApertureHeight (apertureHeightInInches);
85+
86+
// Fit the resolution gate horizontally within the film gate.
87+
fbxCamera.GateFit.Set(FbxCamera.EGateFit.eFitHorizontal);
88+
89+
// Lens Shift ( Film Offset ) as a percentage 0..1
90+
// 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));
93+
94+
// Focal Length
95+
fbxCamera.SetApertureMode (FbxCamera.EApertureMode.eFocalLength);
96+
97+
double focalLength = (double)unityCamera.focalLength;
98+
fbxCamera.FocalLength.Set(focalLength); /* in millimeters */
99+
100+
// NearPlane
101+
fbxCamera.SetNearPlane ((double)unityCamera.nearClipPlane.Meters().ToCentimeters());
102+
103+
// FarPlane
104+
fbxCamera.SetFarPlane ((float)unityCamera.farClipPlane.Meters().ToCentimeters());
105+
106+
return ;
107+
}
108+
}
109+
}
110+
}
111+

Packages/com.unity.formats.fbx/Editor/Scripts/CameraVisitor.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)