Skip to content

Commit 29f96cb

Browse files
authored
Merge pull request #391 from Unity-Technologies/bugfix/1324374-rotated-parent-incorrect-rect-select
Rect Selection incorrectly selects child GameObject mesh's parts when the parent GameObject is rotated or scaled
2 parents 68cd619 + 71def9f commit 29f96cb

4 files changed

Lines changed: 71 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ 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-
98
## [Unreleased]
109

1110
### Bug Fixes
1211

1312
- [case: 1332226] Fixed issue where some Gizmos menu items would be missing in projects that have ProBuilder package installed.
13+
- [case: 1324374] Fixed incorrect vertex/edge/face rect selection when mesh's parent is rotated and/or scaled.
1414

1515
## [5.0.3] - 2021-04-01
1616

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
{

0 commit comments

Comments
 (0)