Search code examples
iosswift3dscenekit

SceneKit. How to create box with rounded edges and with different radiuses?


I've started learning SceneKit. And I've tried SCNBox. And it has chamferRadius. But the radius is applied for all the edges. But I want to achieve something similar to the one on the screenshot belowenter image description here


Solution

  • You can do this by extruding a UIBezierPath:

        // rounded rect bezier path
        let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 1.0, height: 1.0), cornerRadius: 0.1)
        
        path.flatness = 0
        
        // extrude the path
        let shape = SCNShape(path: path, extrusionDepth: 0.05)
        
        let mat = SCNMaterial()
        mat.diffuse.contents = UIColor(white: 0.9, alpha: 1.0)
        shape.materials = [mat]
        
        let shapeNode = SCNNode(geometry: shape)
    

    Result:

    enter image description here

    Here's a full example (note: I have only glanced at SceneKit, so I used this tutorial as a starting point Introduction to SceneKit):

    import UIKit
    import SceneKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let sceneView = SCNView(frame: self.view.frame)
            self.view.addSubview(sceneView)
    
            let scene = SCNScene()
            sceneView.scene = scene
            
            let camera = SCNCamera()
            let cameraNode = SCNNode()
            cameraNode.camera = camera
            cameraNode.position = SCNVector3(x: 3.0, y: 2.0, z: 1.5)
            
            let ambientLight = SCNLight()
            ambientLight.type = .ambient
            ambientLight.color = UIColor(white: 0.9, alpha: 1.0)
            cameraNode.light = ambientLight
    
            let light = SCNLight()
            light.type = SCNLight.LightType.spot
            light.spotInnerAngle = 30.0
            light.spotOuterAngle = 80.0
            light.castsShadow = true
            let lightNode = SCNNode()
            lightNode.light = light
            lightNode.position = SCNVector3(x: 1.5, y: 1.5, z: 1.5)
    
            
            // rounded rect bezier path
            let path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 1.0, height: 1.0), cornerRadius: 0.1)
            
            path.flatness = 0
            
            // extrude the path
            let shape = SCNShape(path: path, extrusionDepth: 0.05)
            
            let mat = SCNMaterial()
            mat.diffuse.contents = UIColor(white: 0.9, alpha: 1.0)
            shape.materials = [mat]
            
            let shapeNode = SCNNode(geometry: shape)
            
            
            let planeGeometry = SCNPlane(width: 50.0, height: 50.0)
            let planeNode = SCNNode(geometry: planeGeometry)
            planeNode.eulerAngles = SCNVector3(x: GLKMathDegreesToRadians(-90), y: 0, z: 0)
            planeNode.position = SCNVector3(x: 0, y: 0.0, z: 0)
    
            let floorMaterial = SCNMaterial()
            floorMaterial.diffuse.contents = UIColor.lightGray
            planeGeometry.materials = [floorMaterial]
            
            scene.rootNode.addChildNode(lightNode)
            scene.rootNode.addChildNode(cameraNode)
            scene.rootNode.addChildNode(shapeNode)
            scene.rootNode.addChildNode(planeNode)
            
            let constraint = SCNLookAtConstraint(target: shapeNode)
            constraint.isGimbalLockEnabled = true
            cameraNode.constraints = [constraint]
            lightNode.constraints = [constraint]
    
        }
    
    
    }