如何用 6 个三角形 SCNNode 制作一个六边形?

zak*_*ces 3 macos ios scenekit swift realitykit

我试图在不改变任何枢轴点的情况下制作一个带有三角形的六边形网格,但我似乎无法正确定位三角形以制作单个六边形。我正在SCNNodes创建UIBezierPaths三角形,然后旋转贝塞尔曲线路径。这似乎工作得很好,直到我尝试使用参数方程将三角形围绕圆定位以形成六边形,然后它们最终不会处于正确的位置。你能帮我找出我做错的地方吗?

class TrianglePlane: SCNNode {

    var size: CGFloat = 0.1
    var coords: SCNVector3 = SCNVector3Zero
    var innerCoords: Int = 0

    init(coords: SCNVector3, innerCoords: Int, identifier: Int) {
        super.init()

        self.coords = coords
        self.innerCoords = innerCoords
        setup()
    }

    init(identifier: Int) {
        super.init()
//        super.init(identifier: identifier)
        setup()
    }

    required init?(coder aDecoder: NSCoder) { 
        fatalError("init(coder:) has not been implemented") 
    }

    func setup() {
        let myPath = path()
        let geo = SCNShape(path: myPath, extrusionDepth: 0)
        geo.firstMaterial?.diffuse.contents = UIColor.red
        geo.firstMaterial?.blendMode = .multiply
        self.geometry = geo
    }

    func path() -> UIBezierPath {

        let max: CGFloat = self.size
        let min: CGFloat = 0

        let bPath = UIBezierPath()
        bPath.move(to: .zero)
        bPath.addLine(to: CGPoint(x: max / 2, 
                                  y: UIBezierPath.middlePeak(height: max)))
        bPath.addLine(to: CGPoint(x: max, y: min))
        bPath.close()
        return bPath
    }
}

extension TrianglePlane {

    static func generateHexagon() -> [TrianglePlane] {

        var myArr: [TrianglePlane] = []

        let colors = [UIColor.red, UIColor.green, 
                      UIColor.yellow, UIColor.systemTeal, 
                      UIColor.cyan, UIColor.magenta]


        for i in 0 ..< 6  {

            let tri = TrianglePlane(identifier: 0)
            tri.geometry?.firstMaterial?.diffuse.contents = colors[i]
            tri.position = SCNVector3( -0.05, 0, -0.5)

//          Rotate bezier path
            let angleInDegrees = (Float(i) + 1) * 180.0
            print(angleInDegrees)
            let angle = CGFloat(deg2rad(angleInDegrees))
            let geo = tri.geometry as! SCNShape
            let path = geo.path!
            path.rotateAroundCenter(angle: angle)
            geo.path = path

//          Position triangle in hexagon
            let radius = Float(tri.size)/2
            let deg: Float = Float(i) * 60
            let radians = deg2rad(-deg)

            let x1 = tri.position.x + radius * cos(radians)
            let y1 = tri.position.y + radius * sin(radians)
            tri.position.x = x1
            tri.position.y = y1

            myArr.append(tri)
        }

        return myArr
    }

    static func deg2rad(_ number: Float) -> Float {
        return number * Float.pi / 180
    }
}

extension UIBezierPath {

    func rotateAroundCenter(angle: CGFloat) {

        let center = self.bounds.center
        var transform = CGAffineTransform.identity
        transform = transform.translatedBy(x: center.x, y: center.y)
        transform = transform.rotated(by: angle)
        transform = transform.translatedBy(x: -center.x, y: -center.y)
        self.apply(transform)
    }

    static func middlePeak(height: CGFloat) -> CGFloat {
        return sqrt(3.0) / 2 * height
    }
}

extension CGRect {
    var center : CGPoint {
        return CGPoint(x:self.midX, y:self.midY)
    }
}
Run Code Online (Sandbox Code Playgroud)

目前的样子:

在此输入图像描述

它应该是什么样子:

在此输入图像描述

ARG*_*Geo 5

我创建了两个版本 \xe2\x80\x93 SceneKit 和 RealityKit。

\n
\n

SceneKit(macOS 版本)

\n

组成六边形的最简单方法是使用六个非均匀缩放SCNPyramids(平坦)的轴点。每个“三角形”必须以 60 度增量 (/3) 旋转.pi

\n
import SceneKit\n\nclass ViewController: NSViewController {\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        let sceneView = self.view as! SCNView\n        let scene = SCNScene()\n        sceneView.scene = scene\n        sceneView.allowsCameraControl = true\n        sceneView.backgroundColor = NSColor.white\n\n        let cameraNode = SCNNode()\n        cameraNode.camera = SCNCamera()\n        scene.rootNode.addChildNode(cameraNode)\n        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)\n        \n        for i in 1...6 {\n\n            let triangleNode = SCNNode(geometry: SCNPyramid(width: 1.15,\n                                                           height: 1,\n                                                           length: 1))\n\n            // the depth of the pyramid is almost zero\n            triangleNode.scale = SCNVector3(5, 5, 0.001)\n\n            // move a pivot point from pyramid its base to upper vertex\n            triangleNode.simdPivot.columns.3.y = 1     \n\n            triangleNode.geometry?.firstMaterial?.diffuse.contents = NSColor(\n                                                 calibratedHue: CGFloat(i)/6,\n                                                    saturation: 1.0, \n                                                    brightness: 1.0, \n                                                         alpha: 1.0)\n\n            triangleNode.rotation = SCNVector4(0, 0, 1, \n                                              -CGFloat.pi/3 * CGFloat(i))\n\n            scene.rootNode.addChildNode(triangleNode)\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n


\n

RealityKit(iOS 版)

\n

在这个项目中,我借助 MeshDescriptor 生成了一个三角形,并将其复制了 5 次。

\n
import UIKit\nimport RealityKit\n\nclass ViewController: UIViewController {\n\n    @IBOutlet var arView: ARView!\n    let anchor = AnchorEntity()\n    let camera = PointOfView()\n    let indices: [UInt32] = [0, 1, 2]\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        self.arView.environment.background = .color(.black)\n        self.arView.cameraMode = .nonAR\n        self.camera.position.z = 9\n\n        let positions: [simd_float3] = [[ 0.00, 0.00, 0.00],\n                                        [ 0.52, 0.90, 0.00],\n                                        [-0.52, 0.90, 0.00]]\n         \n        var descriptor = MeshDescriptor(name: "Hexagon\'s side")\n        descriptor.materials = .perFace(self.indices)\n        descriptor.primitives = .triangles(self.indices)\n        descriptor.positions = MeshBuffers.Positions(positions[0...2])\n        \n        var material = UnlitMaterial()\n        let mesh: MeshResource = try! .generate(from: [descriptor])\n        \n        let colors: [UIColor] = [.systemRed, .systemGreen, .yellow,\n                                 .systemTeal, .cyan, .magenta]\n        \n        for i in 0...5 {\n\n            material.color = .init(tint: colors[i], texture: nil)\n            let triangleModel = ModelEntity(mesh: mesh, \n                                       materials: [material])\n\n            let trianglePivot = Entity()    // made to control pivot point\n            trianglePivot.addChild(triangleModel)\n            \n            trianglePivot.orientation = simd_quatf(angle: -.pi/3 * Float(i),\n                                                    axis: [0,0,1])\n            self.anchor.addChild(trianglePivot)\n        }\n        \n        self.anchor.addChild(self.camera)\n        self.arView.scene.anchors.append(self.anchor)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在此输入图像描述

\n