Skip to content

Commit 22982e2

Browse files
authored
Merge pull request #395 from Unity-Technologies/v5.0/5.0.4
V5.0/5.0.4
2 parents 6a81f04 + fcb74be commit 22982e2

File tree

11 files changed

+143
-93
lines changed

11 files changed

+143
-93
lines changed

Addons/Fbx.cs

Lines changed: 20 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
// todo Once we drop support for 2018.3, use optional assembly definitions
2-
using System;
1+
#if FBX_EXPORTER
2+
33
using UnityEditor;
44
using System.Reflection;
55
using System.Linq;
6+
using UnityEditor.Formats.Fbx.Exporter;
67
using UnityEditor.ProBuilder;
8+
using UnityEditor.ProBuilder.Actions;
79

810
namespace UnityEngine.ProBuilder.Addons.FBX
911
{
@@ -26,29 +28,7 @@ class FbxOptions
2628
[InitializeOnLoad]
2729
static class Fbx
2830
{
29-
private static Assembly FbxExporterAssembly
30-
{
31-
get
32-
{
33-
try
34-
{
35-
return Assembly.Load("Unity.Formats.Fbx.Editor");
36-
}
37-
catch (System.IO.FileNotFoundException)
38-
{
39-
return null;
40-
}
41-
}
42-
}
43-
44-
static readonly Type[] k_ProBuilderTypes = new Type[]
45-
{
46-
typeof(BezierShape),
47-
typeof(PolyShape),
48-
typeof(Entity)
49-
};
50-
51-
static FbxOptions m_FbxOptions = new FbxOptions() {
31+
static FbxOptions s_FbxOptions = new FbxOptions() {
5232
quads = true
5333
};
5434

@@ -59,52 +39,35 @@ static Fbx()
5939

6040
static void TryLoadFbxSupport()
6141
{
62-
if (FbxExporterAssembly == null)
63-
{
64-
return;
65-
}
66-
67-
var modelExporter = FbxExporterAssembly.GetType("UnityEditor.Formats.Fbx.Exporter.ModelExporter");
68-
var registerMeshCallback = modelExporter.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(x => x.Name == "RegisterMeshCallback").First(x => x.ContainsGenericParameters);
69-
registerMeshCallback = registerMeshCallback.MakeGenericMethod(typeof(ProBuilderMesh));
70-
71-
var getMeshForComponent = FbxExporterAssembly.GetTypes()
72-
.Where(t => t.BaseType == typeof(MulticastDelegate) && t.Name.StartsWith("GetMeshForComponent"))
73-
.First(t => t.ContainsGenericParameters);
74-
75-
getMeshForComponent = getMeshForComponent.MakeGenericType(typeof(ProBuilderMesh));
76-
var meshDelegate = Delegate.CreateDelegate(getMeshForComponent, typeof(Fbx).GetMethod("GetMeshForComponent", BindingFlags.NonPublic | BindingFlags.Static));
77-
78-
registerMeshCallback.Invoke(null, new object[] { meshDelegate, true });
79-
80-
m_FbxOptions.quads = ProBuilderSettings.Get<bool>("Export::m_FbxQuads", SettingsScope.User, true);
42+
ModelExporter.RegisterMeshCallback<ProBuilderMesh>(GetMeshForPBComponent, true);
43+
s_FbxOptions.quads = ProBuilderSettings.Get<bool>("Export::m_FbxQuads", SettingsScope.User, true);
8144
}
8245

83-
static bool GetMeshForComponent(object exporter, ProBuilderMesh pmesh, object node)
46+
static bool GetMeshForPBComponent(ModelExporter exporter, ProBuilderMesh pmesh, Autodesk.Fbx.FbxNode node)
8447
{
8548
Mesh mesh = new Mesh();
86-
MeshUtility.Compile(pmesh, mesh, m_FbxOptions.quads ? MeshTopology.Quads : MeshTopology.Triangles);
49+
MeshUtility.Compile(pmesh, mesh, s_FbxOptions.quads ? MeshTopology.Quads : MeshTopology.Triangles);
8750

88-
// using reflection to call: exporter.ExportMesh(mesh, node, pmesh.GetComponent<MeshRenderer>().sharedMaterials)
8951
var pMeshRenderer = pmesh.GetComponent<MeshRenderer>();
9052
var sharedMaterials = pMeshRenderer ? pMeshRenderer.sharedMaterials : null;
91-
var exportMeshMethod = exporter.GetType().GetMethod("ExportMesh", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(Mesh), node.GetType(), typeof(Material[]) }, null);
92-
exportMeshMethod.Invoke(exporter, new object[] { mesh, node, sharedMaterials });
53+
54+
exporter.ExportMesh(mesh, node, sharedMaterials);
9355

9456
Object.DestroyImmediate(mesh);
9557

96-
// probuilder can't handle mesh assets that may be externally reloaded, just strip pb stuff for now.
97-
foreach (var type in k_ProBuilderTypes)
58+
//Need to have ExportOptions accessible to remove this reflection
59+
var exporterType = exporter.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
60+
.First(x => x.Name == "get_ExportOptions").Invoke(exporter, null).GetType();
61+
62+
if(exporterType == typeof(ConvertToPrefabSettingsSerialize))
9863
{
99-
var component = pmesh.GetComponent(type);
100-
if (component != null)
101-
Object.DestroyImmediate(component);
64+
// probuilder can't handle mesh assets that may be externally reloaded, just strip pb stuff for now.
65+
StripProBuilderScripts.DoStrip(pmesh);
10266
}
10367

104-
pmesh.preserveMeshAssetOnDestroy = true;
105-
Object.DestroyImmediate(pmesh);
106-
10768
return true;
10869
}
10970
}
11071
}
72+
73+
#endif
Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
{
22
"name": "Unity.ProBuilder.AddOns.Editor",
3+
"rootNamespace": "",
34
"references": [
45
"Unity.ProBuilder",
5-
"Unity.ProBuilder.Editor"
6+
"Unity.ProBuilder.Editor",
7+
"Unity.Formats.Fbx.Editor",
8+
"Autodesk.Fbx"
69
],
7-
"optionalUnityReferences": [],
810
"includePlatforms": [
911
"Editor"
1012
],
1113
"excludePlatforms": [],
1214
"allowUnsafeCode": false,
1315
"overrideReferences": false,
1416
"precompiledReferences": [],
15-
"autoReferenced": true
16-
}
17+
"autoReferenced": true,
18+
"defineConstraints": [],
19+
"versionDefines": [
20+
{
21+
"name": "com.unity.formats.fbx",
22+
"expression": "4.0.0",
23+
"define": "FBX_EXPORTER"
24+
}
25+
],
26+
"noEngineReferences": false
27+
}

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8+
## [5.0.4] - 2021-06-08
9+
10+
### Bug Fixes
11+
12+
- [case: 1334017] Fixed errors while exporting a PBShape using FBX Exporter and cleaning export.
13+
- [case: 1332226] Fixed issue where some Gizmos menu items would be missing in projects that have ProBuilder package installed.
14+
- [case: 1324374] Fixed incorrect vertex/edge/face rect selection when mesh's parent is rotated and/or scaled.
15+
816
## [5.0.3] - 2021-04-01
917

1018
### Bug Fixes

Editor/EditorCore/HierarchyListener.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,7 @@ static class HierarchyListener
1212
{
1313
static HierarchyListener()
1414
{
15-
// The inspector icon for ProBuilderMesh is set in the component metadata. However, this also serves as the
16-
// scene view gizmo icon, which we do not want. To avoid drawing an icon for every mesh in the Scene View,
17-
// we simply tell the AnnotationManager to not render the icon. This _does_ put ProBuilderMesh in the
18-
// "Recently Changed" list, but only when it is modified the first time.
19-
// The alternative method of setting an icon is to place it in a folder named "Editor Default Resources/Icons",
20-
// however that requires that the resources directory be in "Assets", which we do not want to do.
21-
EditorUtility.SetGizmoIconEnabled(typeof(ProBuilderMesh), false);
22-
15+
AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
2316
// When a prefab is updated, this is raised. For some reason it's
2417
// called twice?
2518
EditorApplication.hierarchyChanged += HierarchyWindowChanged;
@@ -29,6 +22,17 @@ static HierarchyListener()
2922
PrefabUtility.prefabInstanceUpdated += PrefabInstanceUpdated;
3023
}
3124

25+
static void OnAfterAssemblyReload()
26+
{
27+
// The inspector icon for ProBuilderMesh is set in the component metadata. However, this also serves as the
28+
// scene view gizmo icon, which we do not want. To avoid drawing an icon for every mesh in the Scene View,
29+
// we simply tell the AnnotationManager to not render the icon. This _does_ put ProBuilderMesh in the
30+
// "Recently Changed" list, but only when it is modified the first time.
31+
// The alternative method of setting an icon is to place it in a folder named "Editor Default Resources/Icons",
32+
// however that requires that the resources directory be in "Assets", which we do not want to do.
33+
EditorApplication.delayCall += () => EditorUtility.SetGizmoIconEnabled(typeof(ProBuilderMesh), false);
34+
}
35+
3236
static void PrefabInstanceUpdated(GameObject go)
3337
{
3438
if (EditorApplication.isPlayingOrWillChangePlaymode)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ mesh.Optimize();
8787

8888
## Third Party Licenses<a name="third-party-licenses"></a>
8989

90-
[Third Party Licenses](https://github.com/Unity-Technologies/com.unity.probuilder/blob/master/com.unity.probuilder/Third%20Party%20Notices.md)
90+
[Third Party Licenses](https://github.com/Unity-Technologies/com.unity.probuilder/blob/master/Third%20Party%20Notices.md)
9191

9292
## Contributing
9393

Runtime/Core/InternalUtility.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static T[] GetComponents<T>(this IEnumerable<Transform> transforms) where
3939
public static GameObject EmptyGameObjectWithTransform(Transform t)
4040
{
4141
GameObject go = new GameObject();
42-
go.transform.position = t.position;
42+
go.transform.localPosition = t.localPosition;
4343
go.transform.localRotation = t.localRotation;
4444
go.transform.localScale = t.localScale;
4545

@@ -50,6 +50,20 @@ public static GameObject EmptyGameObjectWithTransform(Transform t)
5050
return go;
5151
}
5252

53+
public static GameObject MeshGameObjectWithTransform(string name, Transform t, Mesh mesh, Material mat, bool inheritParent)
54+
{
55+
GameObject go = InternalUtility.EmptyGameObjectWithTransform(t);
56+
go.name = name;
57+
go.AddComponent<MeshFilter>().sharedMesh = mesh;
58+
go.AddComponent<MeshRenderer>().sharedMaterial = mat;
59+
go.hideFlags = HideFlags.HideAndDontSave;
60+
61+
if (inheritParent)
62+
go.transform.SetParent(t.parent, false);
63+
64+
return go;
65+
}
66+
5367
public static T NextEnumValue<T>(this T current) where T : IConvertible
5468
{
5569
Assert.IsTrue(current is Enum);

Runtime/Core/SelectionPickerRenderer.cs

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -540,9 +540,6 @@ static GameObject[] GenerateFacePickingObjects(
540540
{
541541
var pb = selection[i];
542542

543-
GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
544-
go.name = pb.name + " (Face Depth Test)";
545-
546543
Mesh m = new Mesh();
547544
m.vertices = pb.positionsInternal;
548545
m.triangles = pb.facesInternal.SelectMany(x => x.indexesInternal).ToArray();
@@ -559,8 +556,8 @@ static GameObject[] GenerateFacePickingObjects(
559556

560557
m.colors32 = colors;
561558

562-
go.AddComponent<MeshFilter>().sharedMesh = m;
563-
go.AddComponent<MeshRenderer>().sharedMaterial = BuiltinMaterials.facePickerMaterial;
559+
GameObject go = InternalUtility.MeshGameObjectWithTransform(pb.name + " (Face Depth Test)", pb.transform, m,
560+
BuiltinMaterials.facePickerMaterial, true);
564561

565562
pickerObjects[i] = go;
566563
}
@@ -587,10 +584,11 @@ static void GenerateVertexPickingObjects(
587584
{
588585
// build vertex billboards
589586
var pb = selection[i];
590-
GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
591-
go.name = pb.name + " (Vertex Billboards)";
592-
go.AddComponent<MeshFilter>().sharedMesh = BuildVertexMesh(pb, map, ref index);
593-
go.AddComponent<MeshRenderer>().sharedMaterial = BuiltinMaterials.vertexPickerMaterial;
587+
588+
var mesh = BuildVertexMesh(pb, map, ref index);
589+
GameObject go = InternalUtility.MeshGameObjectWithTransform(pb.name + " (Vertex Billboards)", pb.transform, mesh,
590+
BuiltinMaterials.vertexPickerMaterial, true);
591+
594592
pickerObjects[i] = go;
595593
}
596594

@@ -602,10 +600,10 @@ static void GenerateVertexPickingObjects(
602600
for (int i = 0; i < selectionCount; i++)
603601
{
604602
var pb = selection[i];
605-
GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
606-
go.name = pb.name + " (Depth Mask)";
607-
go.AddComponent<MeshFilter>().sharedMesh = pb.mesh;
608-
go.AddComponent<MeshRenderer>().sharedMaterial = BuiltinMaterials.facePickerMaterial;
603+
604+
GameObject go = InternalUtility.MeshGameObjectWithTransform(pb.name + " (Depth Mask)", pb.transform, pb.mesh,
605+
BuiltinMaterials.facePickerMaterial, true);
606+
609607
depthObjects[i] = go;
610608
}
611609
}
@@ -632,10 +630,11 @@ static void GenerateEdgePickingObjects(
632630
{
633631
// build edge billboards
634632
var pb = selection[i];
635-
GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
636-
go.name = pb.name + " (Edge Billboards)";
637-
go.AddComponent<MeshFilter>().sharedMesh = BuildEdgeMesh(pb, map, ref index);
638-
go.AddComponent<MeshRenderer>().sharedMaterial = BuiltinMaterials.edgePickerMaterial;
633+
634+
var mesh = BuildEdgeMesh(pb, map, ref index);
635+
GameObject go = InternalUtility.MeshGameObjectWithTransform(pb.name + " (Edge Billboards)", pb.transform, mesh,
636+
BuiltinMaterials.edgePickerMaterial, true);
637+
639638
pickerObjects[i] = go;
640639
}
641640

@@ -646,11 +645,11 @@ static void GenerateEdgePickingObjects(
646645
for (int i = 0; i < selectionCount; i++)
647646
{
648647
var pb = selection[i];
648+
649649
// copy the select gameobject just for z-write
650-
GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
651-
go.name = pb.name + " (Depth Mask)";
652-
go.AddComponent<MeshFilter>().sharedMesh = pb.mesh;
653-
go.AddComponent<MeshRenderer>().sharedMaterial = BuiltinMaterials.facePickerMaterial;
650+
GameObject go = InternalUtility.MeshGameObjectWithTransform(pb.name + " (Depth Mask)", pb.transform, pb.mesh,
651+
BuiltinMaterials.facePickerMaterial, true);
652+
654653
depthObjects[i] = go;
655654
}
656655
}

Tests/Editor/Picking/RectSelection.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,41 @@ Dictionary<ProBuilderMesh, HashSet<Face>> TestFacePick(PickerOptions options)
116116
}
117117
}
118118

119+
[Test]
120+
public void PickVertices_RotatedParent_DepthTestOn()
121+
{
122+
// Create a parent container with -90 degree rotation around Z
123+
var parent = new GameObject("Parent");
124+
parent.transform.position = new Vector3(0f, 0f, 0f);
125+
parent.transform.rotation = Quaternion.Euler(0f, 0f, -90f);
126+
127+
// Create a Cube such that when parented to the container has (6f, 0f, 0f) world position
128+
var cube = ShapeFactory.Instantiate<UnityEngine.ProBuilder.Shapes.Cube>();
129+
cube.transform.position = new Vector3(0f, 6f, 0f);
130+
cube.transform.SetParent(parent.transform, false);
131+
132+
// Create a camera and point it to (6f, 0f, 0) looking directly at one of the Cube's faces
133+
camera = new GameObject("Camera", typeof(Camera)).GetComponent<Camera>();
134+
camera.transform.position = new Vector3(6f, 0, -6f);
135+
camera.transform.forward = Vector3.forward;
136+
137+
selectables = new ProBuilderMesh[]
138+
{
139+
cube
140+
};
141+
142+
// Attempt full screen rect selection - this should select the 4 vertices of the quad that the camera's facing
143+
var vertices = TestVertexPick(new PickerOptions() { depthTest = true });
144+
var selection = vertices.FirstOrDefault();
145+
Assert.IsNotNull(selection);
146+
HashSet<int> selectedElements = selection.Value;
147+
Assert.That(selectedElements.Count, Is.EqualTo(4));
148+
149+
UObject.DestroyImmediate(cube.gameObject);
150+
UObject.DestroyImmediate(parent);
151+
UObject.DestroyImmediate(camera.gameObject);
152+
}
153+
119154
[Test]
120155
public void PickVertices_DepthTestOn()
121156
{

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "com.unity.probuilder",
33
"displayName": "ProBuilder",
4-
"version": "5.0.3",
4+
"version": "5.0.4",
55
"unity": "2019.4",
66
"description": "Build, edit, and texture custom geometry in Unity. Use ProBuilder for in-scene level design, prototyping, collision meshes, all with on-the-fly play-testing.\n\nAdvanced features include UV editing, vertex colors, parametric shapes, and texture blending. With ProBuilder's model export feature it's easy to tweak your levels in any external 3D modelling suite.\n\nIf you are using URP/HDRP, be careful to also import the corresponding sample project in the section below to get the proper materials.",
77
"keywords": [

validationExceptions.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Exceptions":
3+
[
4+
{
5+
"ValidationTest": "API Validation",
6+
"PackageVersion": "5.0.4"
7+
}
8+
]
9+
}

0 commit comments

Comments
 (0)