public static SurfaceIntersection FindSurfaceIntersection(Vector2 position) { try { CSGTreeBrushIntersection brushIntersection; if (!PickFirstGameObject(position, out brushIntersection)) { return(null); } var brush = brushIntersection.brush; var node = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(brush.UserID); if (!node) { return(null); } var surface = node.FindSurfaceReference(brush, brushIntersection.surfaceID); if (surface == null) { return(null); } return(new SurfaceIntersection { surface = surface, intersection = brushIntersection.surfaceIntersection }); } catch (Exception ex) { Debug.LogException(ex); return(null); } }
public static bool FindBrushMaterials(Vector2 position, out ChiselBrushMaterial[] brushMaterials, out ChiselBrushContainerAsset[] brushContainerAssets, bool selectAllSurfaces) { brushMaterials = null; brushContainerAssets = null; try { CSGTreeBrushIntersection intersection; if (!PickFirstGameObject(Event.current.mousePosition, out intersection)) { return(false); } var brush = intersection.brush; var node = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(brush.UserID); if (!node) { return(false); } if (selectAllSurfaces) { brushContainerAssets = node.GetUsedGeneratedBrushes(); if (brushContainerAssets == null) { return(false); } brushMaterials = node.GetAllBrushMaterials(brush); return(true); } else { var surface = node.FindBrushMaterial(brush, intersection.surfaceID); if (surface == null) { return(false); } brushContainerAssets = node.GetUsedGeneratedBrushes(); if (brushContainerAssets == null) { return(false); } brushMaterials = new ChiselBrushMaterial[] { surface }; return(true); } } catch (Exception ex) { Debug.LogException(ex); return(false); } }
public static PlaneIntersection GetPlaneIntersection(Vector2 mousePosition) { CSGTreeBrushIntersection brushIntersection; var intersectionObject = ChiselClickSelectionManager.PickClosestGameObject(mousePosition, out brushIntersection); if (intersectionObject && intersectionObject.activeInHierarchy) { if (brushIntersection.brushUserID != -1) { var brush = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(brushIntersection.brush.UserID); var model = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(brushIntersection.tree.UserID) as ChiselModel; return(new PlaneIntersection(brushIntersection, brush, model)); } var meshFilter = intersectionObject.GetComponent <MeshFilter>(); if (meshFilter) { var mesh = meshFilter.sharedMesh; var mouseRay = UnityEditor.HandleUtility.GUIPointToWorldRay(mousePosition); RaycastHit hit; if (ChiselClickSelectionManager.IntersectRayMesh(mouseRay, mesh, intersectionObject.transform.localToWorldMatrix, out hit)) { var meshRenderer = intersectionObject.GetComponent <MeshRenderer>(); if (meshRenderer.enabled) { return(new PlaneIntersection(hit.point, hit.normal)); } } } } else { var gridPlane = UnitySceneExtensions.Grid.ActiveGrid.PlaneXZ; var mouseRay = UnityEditor.HandleUtility.GUIPointToWorldRay(mousePosition); var dist = 0.0f; if (gridPlane.SignedRaycast(mouseRay, out dist)) { return(new PlaneIntersection(mouseRay.GetPoint(dist), gridPlane)); } } return(null); }
static ChiselIntersection Convert(CSGTreeBrushIntersection intersection) { var node = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(intersection.brush.UserID); var model = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(intersection.tree.UserID) as ChiselModel; var treeLocalToWorldMatrix = model.transform.localToWorldMatrix; var worldPlaneIntersection = treeLocalToWorldMatrix.MultiplyPoint(intersection.surfaceIntersection.treePlaneIntersection); var worldPlane = treeLocalToWorldMatrix.TransformPlane(intersection.surfaceIntersection.treePlane); return(new ChiselIntersection() { treeNode = node, model = model, worldPlane = worldPlane, worldPlaneIntersection = worldPlaneIntersection, brushIntersection = intersection }); }
public static SurfaceReference[] FindSurfaceReference(Vector2 position, bool selectAllSurfaces, out CSGTreeBrushIntersection intersection, out SurfaceReference surfaceReference) { intersection = CSGTreeBrushIntersection.None; surfaceReference = null; try { if (!PickFirstGameObject(position, out intersection)) { return(null); } var brush = intersection.brush; var node = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(brush.UserID); if (!node) { return(null); } surfaceReference = node.FindSurfaceReference(brush, intersection.surfaceID); if (selectAllSurfaces) { return(node.GetAllSurfaceReferences(brush)); } if (surfaceReference == null) { return(null); } return(new SurfaceReference[] { surfaceReference }); } catch (Exception ex) { Debug.LogException(ex); return(null); } }
internal static GameObject PickNodeOrGameObject(Camera camera, Vector2 pickposition, int layers, ref GameObject[] ignore, ref GameObject[] filter, out ChiselModel model, out ChiselNode node, out CSGTreeBrushIntersection intersection) { TryNextSelection: intersection = new CSGTreeBrushIntersection { surfaceID = -1, brushUserID = -1 }; model = null; node = null; Material sharedMaterial; var gameObject = PickModel(camera, pickposition, layers, ref ignore, ref filter, out model, out sharedMaterial); if (object.Equals(gameObject, null)) { return(null); } if (model) { int filterLayerParameter0 = (sharedMaterial) ? sharedMaterial.GetInstanceID() : 0; { var worldRay = camera.ScreenPointToRay(pickposition); var worldRayStart = worldRay.origin; var worldRayVector = (worldRay.direction * (camera.farClipPlane - camera.nearClipPlane)); var worldRayEnd = worldRayStart + worldRayVector; CSGTreeBrushIntersection tempIntersection; if (ChiselSceneQuery.FindFirstWorldIntersection(model, worldRayStart, worldRayEnd, filterLayerParameter0, layers, ignore, filter, out tempIntersection)) { var clickedBrush = tempIntersection.brush; node = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(clickedBrush.UserID); if (node) { if (ignore != null && ignore.Contains(node.gameObject)) { node = null; return(null); } intersection = tempIntersection; return(node.gameObject); } else { node = null; } } } if (ignore == null) { return(null); } ArrayUtility.Add(ref ignore, gameObject); goto TryNextSelection; } if (object.Equals(gameObject, null)) { return(null); } if (ignore != null && ignore.Contains(gameObject)) { return(null); } return(gameObject); }
static void FindClosestSnapPointsToPlane(GameObject[] selection, Vector3 startWorldPoint, Vector3 currentWorldPoint, Grid worldSlideGrid, float maxSnapDistance, List <SurfaceSnap> allSurfaceSnapEvents, List <EdgeSnap> allEdgeSnapEvents, List <VertexSnap> allVertexSnapEvents) { if (selection == null || selection.Length == 0) { return; } if (allSurfaceSnapEvents == null && allEdgeSnapEvents == null && allVertexSnapEvents == null) { return; } var worldSlidePlane = worldSlideGrid.PlaneXZ; var gridSnapping = Snapping.GridSnappingActive; if (gridSnapping) { var vectorX = worldSlideGrid.Right * maxSnapDistance; var vectorZ = worldSlideGrid.Forward * maxSnapDistance; var snappedWorldPoint = Snapping.SnapPoint(currentWorldPoint, worldSlideGrid); FindSnapPointsAlongRay(selection, snappedWorldPoint, vectorX, allSurfaceSnapEvents, allEdgeSnapEvents, allVertexSnapEvents); FindSnapPointsAlongRay(selection, snappedWorldPoint, vectorZ, allSurfaceSnapEvents, allEdgeSnapEvents, allVertexSnapEvents); snappedWorldPoint = Snapping.SnapPoint(startWorldPoint, worldSlideGrid); FindSnapPointsAlongRay(selection, snappedWorldPoint, vectorX, allSurfaceSnapEvents, allEdgeSnapEvents, allVertexSnapEvents); FindSnapPointsAlongRay(selection, snappedWorldPoint, vectorZ, allSurfaceSnapEvents, allEdgeSnapEvents, allVertexSnapEvents); } worldSlidePlane = new Plane(worldSlidePlane.normal, currentWorldPoint); s_SelectedBrushes.Clear(); foreach (var go in selection) { if (!go) { continue; } var node = go.GetComponent <ChiselNode>(); if (!node) { continue; } s_SelectedNodes.Clear(); node.CollectCSGTreeNodes(s_SelectedNodes); foreach (var child in s_SelectedNodes) { if (!child.Valid || child.Type != CSGNodeType.Brush) { continue; } s_SelectedBrushes.Add((CSGTreeBrush)child); } } if (s_SelectedBrushes.Count == 0) { return; } var snapDistanceSqr = maxSnapDistance * maxSnapDistance; EdgeSnap[] foundEdges = new EdgeSnap[2]; int foundEdgeCount; foreach (var csgBrush in s_SelectedBrushes) { var csgTree = csgBrush.Tree; var brushMesh = BrushMeshManager.GetBrushMesh(csgBrush.BrushMesh); var polygons = brushMesh.polygons; var halfEdges = brushMesh.halfEdges; var vertices = brushMesh.vertices; var planes = brushMesh.planes; var halfEdgePolygonIndices = brushMesh.halfEdgePolygonIndices; // TODO: store this information with brush var model = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(csgTree.UserID) as ChiselModel; var worldToNode = csgBrush.TreeToNodeSpaceMatrix * model.hierarchyItem.WorldToLocalMatrix; var nodeToWorld = model.hierarchyItem.LocalToWorldMatrix * csgBrush.NodeToTreeSpaceMatrix; var brushPoint = worldToNode.MultiplyPoint(currentWorldPoint); var brushPlane = worldToNode.TransformPlane(worldSlidePlane); if (allVertexSnapEvents != null) { if (gridSnapping) { for (int i = 0; i < vertices.Length; i++) { var vertex = vertices[i]; var dist0 = brushPlane.GetDistanceToPoint(vertex); if (math.abs(dist0) > snapDistanceSqr) { continue; } allVertexSnapEvents.Add(new VertexSnap { brush = csgBrush, vertexIndex = i, intersection = nodeToWorld.MultiplyPoint(vertex) }); } } else { for (int i = 0; i < vertices.Length; i++) { var vertex = vertices[i]; if (math.lengthsq(vertex - (float3)brushPoint) > snapDistanceSqr) { continue; } var dist0 = brushPlane.GetDistanceToPoint(vertex); if (math.abs(dist0) > snapDistanceSqr) { continue; } allVertexSnapEvents.Add(new VertexSnap { brush = csgBrush, vertexIndex = i, intersection = nodeToWorld.MultiplyPoint(vertex) }); } } } if (allSurfaceSnapEvents == null && allEdgeSnapEvents == null) { continue; } for (int surfaceIndex = 0; surfaceIndex < polygons.Length; surfaceIndex++) { var polygon = polygons[surfaceIndex]; var firstEdge = polygon.firstEdge; var lastEdge = firstEdge + polygon.edgeCount; // TODO: If point is ON plane, ignore. We don't want to "snap" to every point on that surface b/c then we won't be snapping at all foundEdgeCount = 0; for (int e0 = lastEdge - 1, e1 = firstEdge; e1 < lastEdge; e0 = e1, e1++) { var i0 = halfEdges[e0].vertexIndex; var i1 = halfEdges[e1].vertexIndex; var vertex0 = vertices[i0]; var vertex1 = vertices[i1]; var distance0 = brushPlane.GetDistanceToPoint(vertex0); var distance1 = brushPlane.GetDistanceToPoint(vertex1); // Edge is plane aligned if (math.abs(distance0) < kPlaneDistanceEpsilon && math.abs(distance1) < kPlaneDistanceEpsilon) { if (i0 < i1 && // skip duplicate edges allEdgeSnapEvents != null) { if (gridSnapping) { } else { if (ClosestPointToLine(brushPoint, vertex0, vertex1, out Vector3 newVertex)) { allEdgeSnapEvents.Add(new EdgeSnap { brush = csgBrush, surfaceIndex0 = surfaceIndex, surfaceIndex1 = halfEdgePolygonIndices[halfEdges[e1].twinIndex], vertexIndex0 = i0, vertexIndex1 = i1, intersection = nodeToWorld.MultiplyPoint(newVertex), from = nodeToWorld.MultiplyPoint(vertex0), to = nodeToWorld.MultiplyPoint(vertex1) }); } } } continue; } { if ((distance0 < -snapDistanceSqr && distance1 < -snapDistanceSqr) || (distance0 > snapDistanceSqr && distance1 > snapDistanceSqr)) { continue; } // TODO: Find intersection between plane and edge var vector = vertex0 - vertex1; var length = distance0 - distance1; var delta = distance0 / length; if (float.IsNaN(delta) || float.IsInfinity(delta)) { continue; } var newVertex = (Vector3)(vertex0 - (vector * delta)); var distanceN = brushPlane.GetDistanceToPoint(newVertex); if ((distanceN <= distance0 && distanceN <= distance1) || (distanceN >= distance0 && distanceN >= distance1)) { continue; } if ((newVertex - brushPoint).sqrMagnitude > snapDistanceSqr) { continue; } foundEdges[foundEdgeCount] = new EdgeSnap { brush = csgBrush, surfaceIndex0 = surfaceIndex, surfaceIndex1 = halfEdgePolygonIndices[halfEdges[e1].twinIndex], vertexIndex0 = i0, vertexIndex1 = i1, intersection = nodeToWorld.MultiplyPoint(newVertex), from = nodeToWorld.MultiplyPoint(vertex0), to = nodeToWorld.MultiplyPoint(vertex1) }; if (i0 < i1 && // skip duplicate edges allEdgeSnapEvents != null) { allEdgeSnapEvents.Add(foundEdges[foundEdgeCount]); } foundEdgeCount++; if (foundEdgeCount == 2) { break; } } } if (allSurfaceSnapEvents != null && foundEdgeCount > 0 && !gridSnapping) { if (foundEdgeCount == 2) { var plane = planes[surfaceIndex]; var unityPlane = new Plane(plane.xyz, plane.w); var vertex0 = foundEdges[0].intersection; var vertex1 = foundEdges[1].intersection; if (ClosestPointToLine(currentWorldPoint, vertex0, vertex1, out Vector3 closestWorldPoint)) { allSurfaceSnapEvents.Add(new SurfaceSnap { brush = csgBrush, surfaceIndex = surfaceIndex, intersection = closestWorldPoint, normal = nodeToWorld.MultiplyVector(unityPlane.normal), }); } } } } } }
// For each brush // 1D: // Find surfaces that intersect with ray // Find edges on that surface, if intersection is close enough to edge, find closest point on edge static void FindSnapPointsAlongRay(GameObject[] selection, Vector3 worldRayStart, Vector3 worldRayDirection, List <SurfaceSnap> allSurfaceSnapEvents, List <EdgeSnap> allEdgeSnapEvents, List <VertexSnap> allVertexSnapEvents) { if (selection == null || selection.Length == 0) { return; } if (allSurfaceSnapEvents == null && allEdgeSnapEvents == null && allVertexSnapEvents == null) { return; } s_FoundIntersections.Clear(); if (ChiselSceneQuery.FindFirstWorldIntersection(s_FoundIntersections, worldRayStart - worldRayDirection, worldRayStart + worldRayDirection, filter: selection)) { if (allSurfaceSnapEvents != null) { for (int i = 0; i < s_FoundIntersections.Count; i++) { var intersection = s_FoundIntersections[i]; allSurfaceSnapEvents.Add(new SurfaceSnap { brush = intersection.brushIntersection.brush, surfaceIndex = intersection.brushIntersection.surfaceIndex, intersection = intersection.worldPlaneIntersection, normal = intersection.worldPlane.normal, }); } } } if (allEdgeSnapEvents == null && allVertexSnapEvents == null) { return; } foreach (var intersection in s_FoundIntersections) { var csgBrush = intersection.brushIntersection.brush; var csgTree = intersection.brushIntersection.tree; var brushMesh = BrushMeshManager.GetBrushMesh(csgBrush.BrushMesh); var polygons = brushMesh.polygons; var halfEdges = brushMesh.halfEdges; var vertices = brushMesh.vertices; var halfEdgePolygonIndices = brushMesh.halfEdgePolygonIndices; var model = ChiselNodeHierarchyManager.FindChiselNodeByInstanceID(csgTree.UserID) as ChiselModel; var worldToNode = csgBrush.TreeToNodeSpaceMatrix * model.hierarchyItem.WorldToLocalMatrix; var nodeToWorld = model.hierarchyItem.LocalToWorldMatrix * csgBrush.NodeToTreeSpaceMatrix; var brushRayStart = worldToNode.MultiplyPoint(worldRayStart); var brushRayDirection = worldToNode.MultiplyVector(worldRayDirection).normalized; var surfaceIndex = intersection.brushIntersection.surfaceIndex; var polygon = polygons[surfaceIndex]; var firstEdge = polygon.firstEdge; var lastEdge = firstEdge + polygon.edgeCount; for (int e0 = lastEdge - 1, e1 = firstEdge; e1 < lastEdge; e0 = e1, e1++) { var i0 = halfEdges[e0].vertexIndex; var i1 = halfEdges[e1].vertexIndex; var v0 = vertices[i0]; var v1 = vertices[i1]; var result = ClosestPointsBetweenTwoLines(brushRayStart, brushRayDirection, v0, v1, out Vector3 A, out Vector3 B); if (result == ClosestLineResult.None) { continue; } if (result == ClosestLineResult.Aligned) { // TODO: draw edge as being intersecting if we're on the edge right now continue; } var dist = (A - B).magnitude; if (dist > kEdgeDistanceEpsilon) { continue; } if (allVertexSnapEvents != null) { var vertDist = ((Vector3)v0 - B).magnitude; if (vertDist < kVertexDistanceEpsilon) { allVertexSnapEvents.Add(new VertexSnap { brush = csgBrush, surfaceIndex = surfaceIndex, vertexIndex = i0, intersection = nodeToWorld.MultiplyPoint(v0) }); } vertDist = ((Vector3)v1 - B).magnitude; if (vertDist < kVertexDistanceEpsilon) { allVertexSnapEvents.Add(new VertexSnap { brush = csgBrush, surfaceIndex = surfaceIndex, vertexIndex = i1, intersection = nodeToWorld.MultiplyPoint(v1) }); } } if (allEdgeSnapEvents != null) { allEdgeSnapEvents.Add(new EdgeSnap { brush = csgBrush, surfaceIndex0 = surfaceIndex, surfaceIndex1 = halfEdgePolygonIndices[halfEdges[e1].twinIndex], vertexIndex0 = i0, vertexIndex1 = i1, intersection = nodeToWorld.MultiplyPoint(B), from = nodeToWorld.MultiplyPoint(v0), to = nodeToWorld.MultiplyPoint(v1) }); } } } }