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);
        }
Example #4
0
        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);
        }
Example #7
0
        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),
                                });
                            }
                        }
                    }
                }
            }
        }
Example #8
0
        // 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)
                        });
                    }
                }
            }
        }