public void Init() { CompactHierarchyManager.Clear(); BrushMeshFactory.CreateBox(Vector3.one, 0, out var brushMesh); var surfaceDefinition = new ChiselSurfaceDefinition(); surfaceDefinition.EnsureSize(6); var brushMeshHash = BrushMeshManager.RegisterBrushMesh(brushMesh, surfaceDefinition); dummyBrushMeshInstance = new BrushMeshInstance { brushMeshHash = brushMeshHash }; }
// 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 brushMeshBlob = BrushMeshManager.GetBrushMeshBlob(csgBrush.BrushMesh); if (!brushMeshBlob.IsCreated) { continue; } ref var brushMesh = ref brushMeshBlob.Value; ref var polygons = ref brushMesh.polygons;
static bool GetAllMaterials(CSGTreeBrush brush, CSGTreeBrush findBrush, List <ChiselBrushMaterial> brushMaterials) { if (findBrush != brush) { return(false); } var brushMeshBlob = BrushMeshManager.GetBrushMeshBlob(brush.BrushMesh.BrushMeshID); if (!brushMeshBlob.IsCreated) { return(true); } ref var brushMesh = ref brushMeshBlob.Value;
static bool FindSurfaceReference(ChiselNode chiselNode, CSGTreeBrush brush, CSGTreeBrush findBrush, int surfaceID, out SurfaceReference surfaceReference) { surfaceReference = null; if (findBrush != brush) { return(false); } var brushMeshBlob = BrushMeshManager.GetBrushMeshBlob(findBrush.BrushMesh.BrushMeshID); if (!brushMeshBlob.IsCreated) { return(true); } ref var brushMesh = ref brushMeshBlob.Value;
static bool GetAllSurfaces(ChiselNode chiselNode, CSGTreeBrush brush, CSGTreeBrush?findBrush, List <SurfaceReference> surfaces) { if (!brush.Valid) { return(false); } if (findBrush.HasValue && findBrush.Value != brush) { return(true); } var brushMeshBlob = BrushMeshManager.GetBrushMeshBlob(brush.BrushMesh.BrushMeshID); if (!brushMeshBlob.IsCreated) { return(true); } ref var brushMesh = ref brushMeshBlob.Value;
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) }); } } } }