ARKit 3D空间中UIBezierPath创建平面图形异常问题排查
Hey there, let's figure out why your ARKit app is having shape distortion and position issues when creating a second wall or rotating the device. The core problem here is incorrect coordinate space handling—you're mixing 3D world coordinates with 2D path coordinates without proper conversion. Let's break down the fixes step by step:
1. The Root Cause
When you create UIBezierPath for SCNShape, the path uses local coordinate space relative to the node it's attached to (your windowNode). But right now, you're using worldCoordinates directly, which are global to the AR scene. When you rotate the device or create a new windowNode with a different transform, these world coordinates don't map correctly to the local space of the new wall, causing the shape to warp or shift.
2. Step-by-Step Fixes
A. Convert World Coordinates to Window Node's Local Space
Instead of using raw world coordinates for your path points, convert them to the local space of the windowNode you're drawing on. This ensures your path points are relative to the wall's position and orientation.
Replace your point conversion code with this:
if firstHit.node == windowNode { // Convert world hit position to windowNode's local coordinate space let localHitPosition = windowNode.convertPosition(firstHit.worldCoordinates, from: nil) // Map 3D local position to 2D CGPoint (use X and Y since we're drawing on the SCNPlane) let pointCoordinates = CGPoint(x: CGFloat(localHitPosition.x), y: CGFloat(localHitPosition.y)) // Rest of your sphere creation code stays the same... let sphere = SCNSphere(radius: 0.02) sphere.firstMaterial?.diffuse.contents = UIColor.white sphere.firstMaterial?.lightingModel = .constant let sphereNode = SCNNode(geometry: sphere) sceneView.scene.rootNode.addChildNode(sphereNode) sphereNode.worldPosition = firstHit.worldCoordinates if points.isEmpty { windowPath.move(to: pointCoordinates) } else { windowPath.addLine(to: pointCoordinates) } points.append(sphereNode) if undoButton.alpha == 0 { undoButton.alpha = 1 } }
B. Attach the Shape Node to the Window Node
When creating your final SCNShape node, add it as a child of windowNode instead of setting its world position directly. This inherits the wall's transform, so the shape stays aligned even if the wall is rotated or moved relative to the world.
Modify the shape creation code:
else if firstHit.node == points.first { windowPath.close() // Use a tiny extrusion depth (0 might cause rendering issues) let windowShape = SCNShape(path: windowPath, extrusionDepth: 0.001) windowShape.firstMaterial?.diffuse.contents = UIColor.white windowShape.firstMaterial?.lightingModel = .constant let tintedWindow = SCNNode(geometry: windowShape) // Add as child of windowNode instead of setting worldPosition windowNode.addChildNode(tintedWindow) // Set local position to (0,0,0) since the path is already relative to windowNode's space tintedWindow.position = SCNVector3Zero // Cleanup: Remove spheres and reset path for next use points.forEach { $0.removeFromParentNode() } points.removeAll() windowPath.removeAllPoints() }
C. Reset Path and Points for New Walls
Make sure you reset your windowPath and points array every time you create a new transparent wall. This prevents leftover points from the previous wall messing up the new shape:
Add these lines when creating a new windowNode:
// After initializing windowNode... sceneView.scene.rootNode.addChildNode(windowNode) windowNode.simdTransform = currentFrame.camera.transform windowNode.opacity = 0.1 // Reset path and points for the new wall windowPath = UIBezierPath() points.removeAll()
3. Why This Works
- Local Coordinate Conversion: By converting hit positions to
windowNode's local space, yourUIBezierPathpoints are always relative to the wall's surface, regardless of the device's orientation or the wall's position in the world. - Child Node Attachment: Adding the shape as a child of
windowNodeensures it inherits all the wall's transformations (rotation, position, scale), so it stays perfectly aligned with the wall at all times. - Clean State for New Walls: Resetting the path and points ensures each wall's shape starts fresh, no cross-contamination from previous sessions.
Give these changes a try—your shapes should stay aligned correctly even when rotating the device or creating multiple walls!
内容的提问来源于stack exchange,提问作者YoanGJ

