nicklockwood / Euclid

A Swift library for creating and manipulating 3D geometry
MIT License
644 stars 53 forks source link

Crash in Mesh.subtract #50

Closed mgrider closed 3 years ago

mgrider commented 3 years ago

Here's what I'm trying to do: Use Euclid in a ARKit app.

Here's what I did:

  1. Create a new “Augmented Reality” project in Xcode. (12.5.)
    1. You’ll need to select SceneKit in the “Content Technology” dropdown.
  2. Add the Euclid as a Swift Package Manager dependency.
    1. Go to: File > Swift Packages > Add Package Dependency
    2. Add https://github.com/nicklockwood/ShapeScript.git
  3. Open ViewController.swift

    1. add import Euclid at the top of the file.
    2. Comment out (or delete) the line of code that creates a new scene from ship.scn
    3. Added the following lines in its place (these are from the EuclidExample project):

      // Create a new scene
      let scene = SCNScene()
      
      // create some geometry using Euclid
      let start = CFAbsoluteTimeGetCurrent()
      let cube = Mesh.cube(size: 0.8, material: UIColor.red)
      let sphere = Mesh.sphere(slices: 120, material: UIColor.blue)
      let mesh = cube.subtract(sphere)
      print("Time:", CFAbsoluteTimeGetCurrent() - start)
      print("Polys:", mesh.polygons.count)
      
      // create SCNNode
      let geometry = SCNGeometry(mesh)
      let node = SCNNode(geometry: geometry)
      scene.rootNode.addChildNode(node)
  4. Provisioning bs...
  5. Build and run on my device. (iPhone 12 Pro Max)

I get this crash:

Screen Shot 2021-06-17 at 11 51 33 AM

Interestingly observations:

  1. I have had mixed results trying to build and run the project in the simulator. I have had it crashe with the same error as on device, but I have also had it run successfully. I have also at least once seen the following errors in the logs:
2021-06-17 11:53:03.035867-0500 EuclidSKAR[9123:636030] Metal GPU Frame Capture Enabled
2021-06-17 11:53:03.036055-0500 EuclidSKAR[9123:636030] Metal API Validation Enabled
Time: 12.664151072502136
Polys: 3574
2021-06-17 11:53:16.680852-0500 EuclidSKAR[9123:639525] fopen failed for data file: errno = 2 (No such file or directory)
2021-06-17 11:53:16.680957-0500 EuclidSKAR[9123:639525] Errors found! Invalidating cache...
2021-06-17 11:53:16.943133-0500 EuclidSKAR[9123:639525] fopen failed for data file: errno = 2 (No such file or directory)
2021-06-17 11:53:16.943270-0500 EuclidSKAR[9123:639525] Errors found! Invalidating cache...
  1. The example project does build and run just fine on my phone (after changing provisioning, of course).
  2. I get the same error when running on device even if I add all the code above in a background thread.
  3. I originally created this issue on the ShapeScript repo, sorry about that. I wasn't even trying to use ShapeScript.
nicklockwood commented 3 years ago

@mgrider hi, just to let you know I was able to recreate the crash (only on device, not on the simulator). I've no idea yet what's causing it.

nicklockwood commented 3 years ago

@mgrider reducing the number of slices down from 120 to 110 fixes the problem, so I strongly suspect it's a stack overflow.

nicklockwood commented 3 years ago

@mgrider CSG operations are highly recursive, so they can cause the stack to overflow if you have very complex meshes. You can solve this one of two ways, either reduce the mesh complexity, or increase the stack size.

You can increase the stack size by creating a new Thread and then setting the desired size, as follows:

// Create a new scene
let scene = SCNScene()

let thread = Thread {
    // create some geometry using Euclid
    let start = CFAbsoluteTimeGetCurrent()
    let cube = Mesh.cube(size: 0.8, material: UIColor.red)
    let sphere = Mesh.sphere(slices: 120, material: UIColor.blue)
    let mesh = cube.subtract(sphere)
    print("Time:", CFAbsoluteTimeGetCurrent() - start)
    print("Polys:", mesh.polygons.count)

    // create SCNNode
    DispatchQueue.main.async {
        let geometry = SCNGeometry(mesh)
        let node = SCNNode(geometry: geometry)
        scene.rootNode.addChildNode(node)
    }
}
thread.stackSize = 4 * 1024 * 1024 * 1024 // set stack to 4GB
thread.start()
nicklockwood commented 3 years ago

@mgrider I've pushed a new version of Euclid (0.4.5) that changes the CSG implementation so these stack overflows won't occur. That means you'll no longer need to increase the thread stack size.

mgrider commented 3 years ago

That's awesome, thank you so much! This project is fantastic, btw. I don't really think I'm going to have time to build it, but my idea was an AR enabled 3D modeling program so you can position the geometry over the thing you are trying to model. Just adding and subtracting primitives would be pretty huge, I think. Another cool use case would be to clean up meshes created by 3D scanning with Lidar enabled devices.

nicklockwood commented 3 years ago

@mgrider sounds like a cool idea, hopefully you get a chance to work on it 👍