swift 设置UIBezierPath的线宽以在SceneKit中使用

6qftjkof  于 2023-01-19  发布在  Swift
关注(0)|答案(2)|浏览(155)

在SceneKit中使用UIBezierPath时,无法使lineWidthlineWidth属性工作。最终产品具有最小线宽(非常细),而我需要粗线。
该路径用于构造SCNShape,该SCNShape随后用于构造SCNNode
请看下面的代码:

let hugePath = UIBezierPath()
        
hugePath.lineWidth = 40.0 //Has no effect

hugePath.move(to: CGPoint(x: previousPathPosition.x, y: previousPathPosition.y))

hugePath.addLine(to: CGPoint(x: block.position.x, y: block.position.y))

let hugeShape = SCNShape(path: hugePath, extrusionDepth: 150.0)
let hugeMaterial = SCNMaterial()
hugeMaterial.diffuse.contents = UIColor.red
hugeShape.materials = [hugeMaterial, hugeMaterial, hugeMaterial, hugeMaterial, hugeMaterial, hugeMaterial]

let hugeNode = SCNNode(geometry: hugeShape)
hugeNode.position.x = 0.0 
hugeNode.position.z = 5.0
hugeNode.position.y = 0.0

scnView.scene?.rootNode.addChildNode(hugeNode)

有很多关于这个问题如何与UIBezierPathCAShapeLayer相关的问题,但是我没有看到它如何与SceneKit相关的问题。对于CAShapeLayer问题,solution显然是在实际层上设置lineWidth--而不是路径。但是这似乎不适用于SceneKit的情况。

    • 如何创建在SceneKit中使用的路径,该路径具有有效的lineWidth属性?**
      ***EDIT:***我尝试做的是用一条立体的3D路径连接一系列的点。感谢Andy的回答,我想我的思路是对的,但我还是有点卡住了。

所以,这就是我现在的处境:而不是试图通过 * 手动 * 绘制一堆2D矩形的每一边来创建一条线,然后拉伸这些矩形(我相信Andy的答案是这么建议的),我试图利用UIBezierPathapply(_ transform:)方法,所以,我画了一条连接点的直线(hugePath),然后制作该线的副本(hugePathTopPart),然后将副本变换为所需的"lineWidth",然后连接两条线以形成单个路径。
就像这样:

//Make a copy of the line:
let hugePathTopPart = hugePath.copy() as? UIBezierPath
//Move the copy upward. This is effectively the "lineWidth":
hugePathTopPart?.apply(CGAffineTransform(translationX: 0.0, y: 40.0))
//Combine the lines to (hopefully) create a single object:
hugePath.append(hugePathTopPart!)

现在的问题是,我有两条平行线,它们之间有一个很大的间隙,我需要填补这个间隙,这样它就只是一个实心的形状/线。

ulmd4ohb

ulmd4ohb1#

SCNScene只可视化3D可渲染表面,因此,由于UIBezierPath的对象不是可渲染表面(它只是一条2D线),因此其自身的宽度在SceneKit的3D场景中没有影响。
您需要拉伸一条3D线。解决方法如下:

override func viewDidLoad() {
    super.viewDidLoad()
    
    let sceneView = self.view as! SCNView
    sceneView.scene = SCNScene()
    sceneView.allowsCameraControl = true
    sceneView.backgroundColor = .black
    sceneView.scene?.rootNode.addChildNode(createLine(0.03, length: 10.0))
}

func createLine(_ lineWidth: Double, length: Double) -> SCNNode {
            
    let path = UIBezierPath()
    path.move(to: CGPoint(x: length, y: 0))
    path.addLine(to: CGPoint(x: length, y: lineWidth))
    path.addLine(to: CGPoint(x: 0, y: lineWidth))
    path.addLine(to: CGPoint(x: 0, y: 0))
    path.close()
    
    let shape = SCNShape(path: path, extrusionDepth: lineWidth)
    let material = SCNMaterial()
    material.lightingModel = .constant
    material.diffuse.contents = UIColor.systemRed
    shape.materials = [material]
    
    let lineNode = SCNNode(geometry: shape)
    return lineNode
}

67up9zun

67up9zun2#

来自苹果的文档:“SceneKit使用右手坐标系,其中(默认情况下)视图方向沿着负z轴...”

路径几何图元从XY平面开始,并在Z轴上拉伸。
因此,如果我们从一个(垂直)“线”路径开始并挤出它:

let path = UIBezierPath()
    path.move(to: .zero)
    path.addLine(to: .init(x: 0.0, y: 1.0))
    
    // extrude it to create the shape
    let shape = SCNShape(path: path, extrusionDepth: 10.0)

我们得到这个:

它有Y和Z尺寸,但没有X(宽度)。
因此,我们从矩形开始,而不是直线--宽0.1,高1.0:

// rectangle bezier path
    let path = UIBezierPath(rect: CGRect(x: 0.0, y: 0.0, width: 0.10, height: 1.0))

我们看到路径位于XY平面上...如果我们挤出它:

// rectangle bezier path
    let path = UIBezierPath(rect: CGRect(x: 0.0, y: 0.0, width: 0.10, height: 1.0))

    // extrude it to create the shape
    let shape = SCNShape(path: path, extrusionDepth: 10.0)

我们得到这个:

快速示例代码:

class WallViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let sceneView = SCNView(frame: self.view.frame)
        self.view.addSubview(sceneView)
        
        sceneView.allowsCameraControl = true
        sceneView.autoenablesDefaultLighting = true
        sceneView.backgroundColor = .black
        
        let scene = SCNScene()
        sceneView.scene = scene
        
        // rectangle bezier path
        let path = UIBezierPath(rect: CGRect(x: 0.0, y: 0.0, width: 0.10, height: 1.0))
        
        // extrude it to create the shape
        let shape = SCNShape(path: path, extrusionDepth: 10.0)
        
        let mat = SCNMaterial()
        mat.diffuse.contents = UIColor(white: 0.75, alpha: 1.0)
        mat.lightingModel = .physicallyBased
        shape.materials = [mat]
        
        // set shape node
        let shapeNode = SCNNode(geometry: shape)
        
        // add it to the scene
        scene.rootNode.addChildNode(shapeNode)
        
        // let's add a camera for the "starting view"
        let camera = SCNCamera()
        let cameraNode = SCNNode()
        cameraNode.camera = camera
        cameraNode.position = SCNVector3(x: 0.5, y: 2.0, z: 7.0)
        scene.rootNode.addChildNode(cameraNode)
        
        let constraint = SCNLookAtConstraint(target: shapeNode)
        constraint.isGimbalLockEnabled = true
        cameraNode.constraints = [constraint]
        
    }
    
}

相关问题