Skip to content

Commit

Permalink
Merge pull request #395 from Unity-Technologies/v5.0/5.0.4
Browse files Browse the repository at this point in the history
V5.0/5.0.4
  • Loading branch information
lopezt-unity authored Jun 17, 2021
2 parents 6a81f04 + fcb74be commit 22982e2
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 93 deletions.
77 changes: 20 additions & 57 deletions Addons/Fbx.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// todo Once we drop support for 2018.3, use optional assembly definitions
using System;
#if FBX_EXPORTER

using UnityEditor;
using System.Reflection;
using System.Linq;
using UnityEditor.Formats.Fbx.Exporter;
using UnityEditor.ProBuilder;
using UnityEditor.ProBuilder.Actions;

namespace UnityEngine.ProBuilder.Addons.FBX
{
Expand All @@ -26,29 +28,7 @@ class FbxOptions
[InitializeOnLoad]
static class Fbx
{
private static Assembly FbxExporterAssembly
{
get
{
try
{
return Assembly.Load("Unity.Formats.Fbx.Editor");
}
catch (System.IO.FileNotFoundException)
{
return null;
}
}
}

static readonly Type[] k_ProBuilderTypes = new Type[]
{
typeof(BezierShape),
typeof(PolyShape),
typeof(Entity)
};

static FbxOptions m_FbxOptions = new FbxOptions() {
static FbxOptions s_FbxOptions = new FbxOptions() {
quads = true
};

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

static void TryLoadFbxSupport()
{
if (FbxExporterAssembly == null)
{
return;
}

var modelExporter = FbxExporterAssembly.GetType("UnityEditor.Formats.Fbx.Exporter.ModelExporter");
var registerMeshCallback = modelExporter.GetMethods(BindingFlags.NonPublic | BindingFlags.Static).Where(x => x.Name == "RegisterMeshCallback").First(x => x.ContainsGenericParameters);
registerMeshCallback = registerMeshCallback.MakeGenericMethod(typeof(ProBuilderMesh));

var getMeshForComponent = FbxExporterAssembly.GetTypes()
.Where(t => t.BaseType == typeof(MulticastDelegate) && t.Name.StartsWith("GetMeshForComponent"))
.First(t => t.ContainsGenericParameters);

getMeshForComponent = getMeshForComponent.MakeGenericType(typeof(ProBuilderMesh));
var meshDelegate = Delegate.CreateDelegate(getMeshForComponent, typeof(Fbx).GetMethod("GetMeshForComponent", BindingFlags.NonPublic | BindingFlags.Static));

registerMeshCallback.Invoke(null, new object[] { meshDelegate, true });

m_FbxOptions.quads = ProBuilderSettings.Get<bool>("Export::m_FbxQuads", SettingsScope.User, true);
ModelExporter.RegisterMeshCallback<ProBuilderMesh>(GetMeshForPBComponent, true);
s_FbxOptions.quads = ProBuilderSettings.Get<bool>("Export::m_FbxQuads", SettingsScope.User, true);
}

static bool GetMeshForComponent(object exporter, ProBuilderMesh pmesh, object node)
static bool GetMeshForPBComponent(ModelExporter exporter, ProBuilderMesh pmesh, Autodesk.Fbx.FbxNode node)
{
Mesh mesh = new Mesh();
MeshUtility.Compile(pmesh, mesh, m_FbxOptions.quads ? MeshTopology.Quads : MeshTopology.Triangles);
MeshUtility.Compile(pmesh, mesh, s_FbxOptions.quads ? MeshTopology.Quads : MeshTopology.Triangles);

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

exporter.ExportMesh(mesh, node, sharedMaterials);

Object.DestroyImmediate(mesh);

// probuilder can't handle mesh assets that may be externally reloaded, just strip pb stuff for now.
foreach (var type in k_ProBuilderTypes)
//Need to have ExportOptions accessible to remove this reflection
var exporterType = exporter.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.First(x => x.Name == "get_ExportOptions").Invoke(exporter, null).GetType();

if(exporterType == typeof(ConvertToPrefabSettingsSerialize))
{
var component = pmesh.GetComponent(type);
if (component != null)
Object.DestroyImmediate(component);
// probuilder can't handle mesh assets that may be externally reloaded, just strip pb stuff for now.
StripProBuilderScripts.DoStrip(pmesh);
}

pmesh.preserveMeshAssetOnDestroy = true;
Object.DestroyImmediate(pmesh);

return true;
}
}
}

#endif
19 changes: 15 additions & 4 deletions Addons/Unity.ProBuilder.AddOns.Editor.asmdef
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
{
"name": "Unity.ProBuilder.AddOns.Editor",
"rootNamespace": "",
"references": [
"Unity.ProBuilder",
"Unity.ProBuilder.Editor"
"Unity.ProBuilder.Editor",
"Unity.Formats.Fbx.Editor",
"Autodesk.Fbx"
],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true
}
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.formats.fbx",
"expression": "4.0.0",
"define": "FBX_EXPORTER"
}
],
"noEngineReferences": false
}
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [5.0.4] - 2021-06-08

### Bug Fixes

- [case: 1334017] Fixed errors while exporting a PBShape using FBX Exporter and cleaning export.
- [case: 1332226] Fixed issue where some Gizmos menu items would be missing in projects that have ProBuilder package installed.
- [case: 1324374] Fixed incorrect vertex/edge/face rect selection when mesh's parent is rotated and/or scaled.

## [5.0.3] - 2021-04-01

### Bug Fixes
Expand Down
20 changes: 12 additions & 8 deletions Editor/EditorCore/HierarchyListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,7 @@ static class HierarchyListener
{
static HierarchyListener()
{
// The inspector icon for ProBuilderMesh is set in the component metadata. However, this also serves as the
// scene view gizmo icon, which we do not want. To avoid drawing an icon for every mesh in the Scene View,
// we simply tell the AnnotationManager to not render the icon. This _does_ put ProBuilderMesh in the
// "Recently Changed" list, but only when it is modified the first time.
// The alternative method of setting an icon is to place it in a folder named "Editor Default Resources/Icons",
// however that requires that the resources directory be in "Assets", which we do not want to do.
EditorUtility.SetGizmoIconEnabled(typeof(ProBuilderMesh), false);

AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload;
// When a prefab is updated, this is raised. For some reason it's
// called twice?
EditorApplication.hierarchyChanged += HierarchyWindowChanged;
Expand All @@ -29,6 +22,17 @@ static HierarchyListener()
PrefabUtility.prefabInstanceUpdated += PrefabInstanceUpdated;
}

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

static void PrefabInstanceUpdated(GameObject go)
{
if (EditorApplication.isPlayingOrWillChangePlaymode)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ mesh.Optimize();

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

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

## Contributing

Expand Down
16 changes: 15 additions & 1 deletion Runtime/Core/InternalUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static T[] GetComponents<T>(this IEnumerable<Transform> transforms) where
public static GameObject EmptyGameObjectWithTransform(Transform t)
{
GameObject go = new GameObject();
go.transform.position = t.position;
go.transform.localPosition = t.localPosition;
go.transform.localRotation = t.localRotation;
go.transform.localScale = t.localScale;

Expand All @@ -50,6 +50,20 @@ public static GameObject EmptyGameObjectWithTransform(Transform t)
return go;
}

public static GameObject MeshGameObjectWithTransform(string name, Transform t, Mesh mesh, Material mat, bool inheritParent)
{
GameObject go = InternalUtility.EmptyGameObjectWithTransform(t);
go.name = name;
go.AddComponent<MeshFilter>().sharedMesh = mesh;
go.AddComponent<MeshRenderer>().sharedMaterial = mat;
go.hideFlags = HideFlags.HideAndDontSave;

if (inheritParent)
go.transform.SetParent(t.parent, false);

return go;
}

public static T NextEnumValue<T>(this T current) where T : IConvertible
{
Assert.IsTrue(current is Enum);
Expand Down
41 changes: 20 additions & 21 deletions Runtime/Core/SelectionPickerRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -540,9 +540,6 @@ static GameObject[] GenerateFacePickingObjects(
{
var pb = selection[i];

GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
go.name = pb.name + " (Face Depth Test)";

Mesh m = new Mesh();
m.vertices = pb.positionsInternal;
m.triangles = pb.facesInternal.SelectMany(x => x.indexesInternal).ToArray();
Expand All @@ -559,8 +556,8 @@ static GameObject[] GenerateFacePickingObjects(

m.colors32 = colors;

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

pickerObjects[i] = go;
}
Expand All @@ -587,10 +584,11 @@ static void GenerateVertexPickingObjects(
{
// build vertex billboards
var pb = selection[i];
GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
go.name = pb.name + " (Vertex Billboards)";
go.AddComponent<MeshFilter>().sharedMesh = BuildVertexMesh(pb, map, ref index);
go.AddComponent<MeshRenderer>().sharedMaterial = BuiltinMaterials.vertexPickerMaterial;

var mesh = BuildVertexMesh(pb, map, ref index);
GameObject go = InternalUtility.MeshGameObjectWithTransform(pb.name + " (Vertex Billboards)", pb.transform, mesh,
BuiltinMaterials.vertexPickerMaterial, true);

pickerObjects[i] = go;
}

Expand All @@ -602,10 +600,10 @@ static void GenerateVertexPickingObjects(
for (int i = 0; i < selectionCount; i++)
{
var pb = selection[i];
GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
go.name = pb.name + " (Depth Mask)";
go.AddComponent<MeshFilter>().sharedMesh = pb.mesh;
go.AddComponent<MeshRenderer>().sharedMaterial = BuiltinMaterials.facePickerMaterial;

GameObject go = InternalUtility.MeshGameObjectWithTransform(pb.name + " (Depth Mask)", pb.transform, pb.mesh,
BuiltinMaterials.facePickerMaterial, true);

depthObjects[i] = go;
}
}
Expand All @@ -632,10 +630,11 @@ static void GenerateEdgePickingObjects(
{
// build edge billboards
var pb = selection[i];
GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
go.name = pb.name + " (Edge Billboards)";
go.AddComponent<MeshFilter>().sharedMesh = BuildEdgeMesh(pb, map, ref index);
go.AddComponent<MeshRenderer>().sharedMaterial = BuiltinMaterials.edgePickerMaterial;

var mesh = BuildEdgeMesh(pb, map, ref index);
GameObject go = InternalUtility.MeshGameObjectWithTransform(pb.name + " (Edge Billboards)", pb.transform, mesh,
BuiltinMaterials.edgePickerMaterial, true);

pickerObjects[i] = go;
}

Expand All @@ -646,11 +645,11 @@ static void GenerateEdgePickingObjects(
for (int i = 0; i < selectionCount; i++)
{
var pb = selection[i];

// copy the select gameobject just for z-write
GameObject go = InternalUtility.EmptyGameObjectWithTransform(pb.transform);
go.name = pb.name + " (Depth Mask)";
go.AddComponent<MeshFilter>().sharedMesh = pb.mesh;
go.AddComponent<MeshRenderer>().sharedMaterial = BuiltinMaterials.facePickerMaterial;
GameObject go = InternalUtility.MeshGameObjectWithTransform(pb.name + " (Depth Mask)", pb.transform, pb.mesh,
BuiltinMaterials.facePickerMaterial, true);

depthObjects[i] = go;
}
}
Expand Down
35 changes: 35 additions & 0 deletions Tests/Editor/Picking/RectSelection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,41 @@ Dictionary<ProBuilderMesh, HashSet<Face>> TestFacePick(PickerOptions options)
}
}

[Test]
public void PickVertices_RotatedParent_DepthTestOn()
{
// Create a parent container with -90 degree rotation around Z
var parent = new GameObject("Parent");
parent.transform.position = new Vector3(0f, 0f, 0f);
parent.transform.rotation = Quaternion.Euler(0f, 0f, -90f);

// Create a Cube such that when parented to the container has (6f, 0f, 0f) world position
var cube = ShapeFactory.Instantiate<UnityEngine.ProBuilder.Shapes.Cube>();
cube.transform.position = new Vector3(0f, 6f, 0f);
cube.transform.SetParent(parent.transform, false);

// Create a camera and point it to (6f, 0f, 0) looking directly at one of the Cube's faces
camera = new GameObject("Camera", typeof(Camera)).GetComponent<Camera>();
camera.transform.position = new Vector3(6f, 0, -6f);
camera.transform.forward = Vector3.forward;

selectables = new ProBuilderMesh[]
{
cube
};

// Attempt full screen rect selection - this should select the 4 vertices of the quad that the camera's facing
var vertices = TestVertexPick(new PickerOptions() { depthTest = true });
var selection = vertices.FirstOrDefault();
Assert.IsNotNull(selection);
HashSet<int> selectedElements = selection.Value;
Assert.That(selectedElements.Count, Is.EqualTo(4));

UObject.DestroyImmediate(cube.gameObject);
UObject.DestroyImmediate(parent);
UObject.DestroyImmediate(camera.gameObject);
}

[Test]
public void PickVertices_DepthTestOn()
{
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "com.unity.probuilder",
"displayName": "ProBuilder",
"version": "5.0.3",
"version": "5.0.4",
"unity": "2019.4",
"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.",
"keywords": [
Expand Down
9 changes: 9 additions & 0 deletions validationExceptions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Exceptions":
[
{
"ValidationTest": "API Validation",
"PackageVersion": "5.0.4"
}
]
}
7 changes: 7 additions & 0 deletions validationExceptions.json.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 22982e2

Please sign in to comment.