Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
45fed34
Fix for rect selection incorrectly selecting elements if mesh's paren…
modrimkus-unity Apr 26, 2021
3939510
Fix adjustment and accompanying test
modrimkus-unity Apr 26, 2021
5d29a22
Refactoring. Updated change log
modrimkus-unity Apr 27, 2021
e7ab2a4
Merge branch 'v5.0/master' into bugfix/1324374-rotated-parent-incorre…
modrimkus-unity Apr 27, 2021
0f5b0dd
Changelog fix
modrimkus-unity Apr 27, 2021
587eab3
Adding a validationExceptions.json to pass Package Validation Suite's…
modrimkus-unity Apr 28, 2021
904d224
Fix for missing Gizmos menu items in projects where ProBuilder packag…
modrimkus-unity Apr 29, 2021
6e4f320
Changelog update
modrimkus-unity Apr 29, 2021
d9f8ae0
Adding a validationExceptions.json to pass Package Validation Suite's…
modrimkus-unity Apr 28, 2021
68cd619
Merge pull request #392 from Unity-Technologies/bugfix/1332226-missin…
modrimkus Apr 30, 2021
71def9f
Merge branch 'master' into bugfix/1324374-rotated-parent-incorrect-re…
modrimkus Apr 30, 2021
29f96cb
Merge pull request #391 from Unity-Technologies/bugfix/1324374-rotate…
modrimkus Apr 30, 2021
e07e23f
Fixing PBShape export using FBX Exporter
lopezt-unity May 19, 2021
6788fc7
moving to optional dependency for FBX Export
lopezt-unity May 19, 2021
9fd4331
Merge pull request #394 from Unity-Technologies/bugfix/1334017-pbshap…
lopezt-unity Jun 8, 2021
4ef06e6
update package to 5.0.4
lopezt-unity Jun 8, 2021
be9f5b2
removing validation exceptions file
lopezt-unity Jun 15, 2021
fcb74be
Updating validation exception for tests
lopezt-unity Jun 16, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.