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

如何在RealityKit中绘制可灵活调整尺寸的3D圆环?

在RealityKit中生成可自定义参数的矩形截面3D圆环

方案一:手动构建自定义网格(推荐,完全可控)

这种方式直接在RealityKit中生成顶点数据构建网格,能完全适配从数米到百米的尺寸范围,且参数调整灵活,不会出现缩放失真问题。

核心思路

通过计算矩形截面沿环形路径扫掠后的顶点、法线和索引数据,生成自定义MeshResource,再封装为ModelEntity加入场景。可调整的核心参数包括:

  • circleRadius:圆环中心到矩形截面中心的距离
  • sectionWidth:矩形截面的径向宽度
  • sectionHeight:矩形截面的轴向高度
  • segmentCount:圆环分段数(数值越大,模型越平滑)

代码实现

import RealityKit

func createRectangularTorus(circleRadius: Float, 
                           sectionWidth: Float, 
                           sectionHeight: Float, 
                           segmentCount: Int) -> MeshResource {
    var vertices: [MeshResource.Position] = []
    var normals: [MeshResource.Normal] = []
    var indices: [UInt32] = []
    
    let halfWidth = sectionWidth / 2
    let halfHeight = sectionHeight / 2
    let angleStep = 2 * Float.pi / Float(segmentCount)
    
    // 遍历每个分段生成顶点与法线
    for i in 0..<segmentCount {
        let angle = Float(i) * angleStep
        let nextAngle = Float(i + 1) * angleStep
        
        // 当前分段的8个顶点(顶面4个+底面4个)
        let p0 = SIMD3<Float>((circleRadius + halfWidth) * cos(angle), halfHeight, (circleRadius + halfWidth) * sin(angle))
        let p1 = SIMD3<Float>((circleRadius - halfWidth) * cos(angle), halfHeight, (circleRadius - halfWidth) * sin(angle))
        let p2 = SIMD3<Float>((circleRadius - halfWidth) * cos(nextAngle), halfHeight, (circleRadius - halfWidth) * sin(nextAngle))
        let p3 = SIMD3<Float>((circleRadius + halfWidth) * cos(nextAngle), halfHeight, (circleRadius + halfWidth) * sin(nextAngle))
        
        let p4 = SIMD3<Float>(p0.x, -halfHeight, p0.z)
        let p5 = SIMD3<Float>(p1.x, -halfHeight, p1.z)
        let p6 = SIMD3<Float>(p2.x, -halfHeight, p2.z)
        let p7 = SIMD3<Float>(p3.x, -halfHeight, p3.z)
        
        vertices.append(contentsOf: [p0, p1, p2, p3, p4, p5, p6, p7])
        
        // 生成法线(径向、顶面、底面)
        let radialNormal0 = normalize(SIMD3<Float>(p0.x, 0, p0.z))
        let radialNormal1 = normalize(SIMD3<Float>(p1.x, 0, p1.z))
        let topNormal = SIMD3<Float>(0, 1, 0)
        let bottomNormal = SIMD3<Float>(0, -1, 0)
        
        normals.append(contentsOf: [
            radialNormal0, radialNormal1, radialNormal1, radialNormal0,
            topNormal, topNormal, topNormal, topNormal,
            bottomNormal, bottomNormal, bottomNormal, bottomNormal,
            radialNormal0, radialNormal1, radialNormal1, radialNormal0
        ])
        
        // 生成三角面索引
        let baseIndex = UInt32(i * 8)
        
        // 顶面三角面
        indices.append(contentsOf: [baseIndex, baseIndex+1, baseIndex+2, baseIndex+2, baseIndex+3, baseIndex])
        // 底面三角面
        indices.append(contentsOf: [baseIndex+4, baseIndex+7, baseIndex+6, baseIndex+6, baseIndex+5, baseIndex+4])
        // 外侧三角面
        indices.append(contentsOf: [baseIndex, baseIndex+3, baseIndex+7, baseIndex+7, baseIndex+4, baseIndex])
        // 内侧三角面
        indices.append(contentsOf: [baseIndex+1, baseIndex+5, baseIndex+6, baseIndex+6, baseIndex+2, baseIndex+1])
    }
    
    // 构建MeshDescriptor并生成MeshResource
    let descriptor = MeshDescriptor()
    descriptor.positions = MeshBuffers.Positions(vertices)
    descriptor.normals = MeshBuffers.Normals(normals)
    descriptor.primitives = .triangles(indices)
    
    return try! MeshResource.generate(from: [descriptor])
}

使用示例

// 创建圆环实体
let torusMesh = createRectangularTorus(
    circleRadius: 50.0,    // 50米半径的圆环
    sectionWidth: 3.0,     // 3米宽的截面
    sectionHeight: 1.5,    // 1.5米高的截面
    segmentCount: 64       // 64分段保证平滑度
)
let torusEntity = ModelEntity(mesh: torusMesh, materials: [SimpleMaterial(color: .darkGray, isMetallic: true)])

// 添加到RealityKit场景(与现有USDZ模型共存)
arView.scene.addAnchor(torusEntity)

方案二:SceneKit网格转RealityKit(备选)

若你熟悉SceneKit的路径拉伸逻辑,可先通过SCNGeometry生成模型,再转换为RealityKit兼容的MeshResource,适合快速原型开发。

代码实现

import SceneKit
import RealityKit

// 1. 用SceneKit生成矩形截面环形网格
let profilePath = UIBezierPath(rect: CGRect(x: -1.5, y: -0.75, width: 3, height: 1.5)) // 3x1.5米的矩形截面
let sweepPath = UIBezierPath(arcCenter: .zero, radius: 50, startAngle: 0, endAngle: 2 * .pi, clockwise: true) // 50米半径的环形路径
let scnGeometry = SCNGeometry(path: sweepPath, profile: profilePath)

// 2. 转换为RealityKit的MeshResource
guard let scnData = scnGeometry.data() else {
    fatalError("Failed to extract SCNGeometry data")
}
let realityMesh = try! MeshResource(data: scnData, options: nil)

// 3. 创建实体并加入场景
let torusEntity = ModelEntity(mesh: realityMesh, materials: [SimpleMaterial(color: .blue, isMetallic: false)])
arView.scene.addAnchor(torusEntity)

注意事项

  • 转换后的网格性能略低于手动生成的自定义网格,频繁调整参数时推荐用方案一
  • 若需要碰撞检测,可给ModelEntity添加CollisionComponent,直接使用生成的MeshResource作为碰撞形状

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 09:00:17