You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SceneKit中如何调整节点对齐 实现3D柱状图从底部向上生长

运行环境
  • Swift 5.5
  • iOS 14
问题说明

开发简易3D柱状图时遇到SceneKit节点对齐问题:默认生成的SCNBox柱体以自身几何中心为定位基准居中放置,无法实现柱体从基底位置向上生长的效果。
初始实现代码如下:

var virgin = true

for i in stride(from: 0, to: 6, by: 0.5) {

    let rnd = CGFloat.random(in: 1.0...4.0)
    let targetGeometry = SCNBox(width: 0.5, 
                               height: rnd, 
                               length: 0.5, 
                        chamferRadius: 0.2)
    targetGeometry.firstMaterial?.fillMode = .lines
    targetGeometry.firstMaterial?.diffuse.contents = UIColor.blue
    let box = SCNNode(geometry: targetGeometry)
    
    box.simdPosition = SIMD3(x: 0, y: 0, z: 0)
    coreNode.addChildNode(box)
}

最初尝试通过手动计算偏移量修改simdPosition实现对齐,代码如下,但效果不符合需求:

box.simdPosition = SIMD3(x: Float(i) - 3, 
                         y: Float(rnd * 0.5), 
                         z: 0)
实现方案

通过调整节点的simdPivot属性修改对齐基准,无需手动计算位置偏移即可实现柱体底部对齐基底、向上生长的效果,核心对齐代码如下:

box.simdPosition = SIMD3(x:box.simdPosition.x, y:0, z:0)
box.simdPivot.columns.3.y = box.boundingBox.max.y - Float(rnd * 0.5)

在上述对齐逻辑基础上,补充SCNMorpher变形动画,即可实现动态更新的3D柱状图效果,完整实现代码如下:

changer = changeling.sink(receiveValue: { [self] _ in
    var rnds:[CGFloat] = []
    for i in 0..<12 {
        let rnd = CGFloat.random(in: 1.0...2.0)
        let targetGeometry = SCNBox(width: 0.45, height: rnd, length: 0.45, chamferRadius: 0.01)
        let newNode = SCNNode(geometry: targetGeometry)
                
        sourceNodes[i].simdPivot.columns.3.y = newNode.boundingBox.min.y
        sourceNodes[i].simdPosition = SIMD3(x: sourceNodes[i].simdPosition.x, y: 0, z: 0)
        rnds.append(rnd)
    }
              
    for k in 0..<12 {
        if virgin {
            coreNode.addChildNode(sourceNodes[k])
        }
        let targetGeometry = SCNBox(width: 0.45, height: rnds[k], length: 0.45, chamferRadius: 0.01)
        targetGeometry.firstMaterial?.fillMode = .lines
        targetGeometry.firstMaterial?.diffuse.contents = UIColor.blue
                            
        let morpher = SCNMorpher()
        morpher.targets = [targetGeometry]
        sourceNodes[k].morpher = morpher
                            
        let animation = CABasicAnimation(keyPath: "morpher.weights[0]")
        animation.toValue = 1.0
        animation.repeatCount = 0.0
        animation.duration = 1.0
        animation.fillMode = .forwards
        animation.isRemovedOnCompletion = false                     
        sourceNodes[k].addAnimation(animation, forKey: nil)
    }          
    virgin = false
})

内容的提问来源于stack exchange,提问作者user3069232

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 13:12:23