【问题标题】:Draw a line with SceneKit using Swift on iOS: line drawn but not visible?在 iOS 上使用 Swift 使用 SceneKit 画一条线:画线但不可见?
【发布时间】:2015-03-14 07:01:02
【问题描述】:

在此处跟进我之前在 Objective-C 中提出的问题(具体来说,我正在尝试将我使用 Objective-C 提供的答案翻译成 Swift):

Drawing a line between two points using SceneKit

问题:SceneKit 统计数据显示正在绘制线条,但它没有出现在屏幕上。

小例子:

  • 使用 Swift 和 SceneKit 在 Xcode 中启动一个新的游戏项目。
  • 删除样板:
    • let scene = SCNScene() 而不是 SCNScene(named: "art.scnassets/ship.dae")!
    • 注释掉let ship = ...ship.runAction(...)
  • scnView.backgroundColor = UIColor.blackColor()更改为scnView.backgroundColor = UIColor.grayColor()(我原本以为线条可能只是黑色背景上的黑色,所以相应地更改了背景颜色)
  • 添加以下代码:

    var positions: [SCNVector3] = [SCNVector3Make(0.0,0.0,0.0),SCNVector3Make(10.0,10.0,10.0)]
    
    // using Swift's Int gives an error with unsupported "SceneKit: error, C3DRendererContextBindMeshElement unsupported byte per index (8)"
    // when constructing element: SCNGeometryElement below, so switched to CInt
    var indicies: [CInt] = [0,1]
    
    // for whatever reason, the following doesn't work on iOS:
    // let vertexSource = SCNGeometrySource(vertices: &positions, count: positions.count)
    // see https://stackoverflow.com/questions/26890739/how-to-solve-scenekit-double-not-supported-error
    // so using more complex SCNGeometrySource() initializer instead
    
    let vertexData = NSData(bytes: &positions, length: positions.count)
    let vertexSource = SCNGeometrySource(data: vertexData, semantic: SCNGeometrySourceSemanticVertex,
    vectorCount: positions.count, floatComponents: true, componentsPerVector: 3,
    bytesPerComponent: sizeof(Float), dataOffset: 0, dataStride: sizeof(SCNVector3))
    
    let indexData = NSData(bytes: &indicies, length: indicies.count)
    let element = SCNGeometryElement(data: indexData, primitiveType: SCNGeometryPrimitiveType.Line,
    primitiveCount: indicies.count, bytesPerIndex: sizeof(CInt))
    
    let lines = SCNGeometry(sources: [vertexSource], elements: [element])
    
    let cellNode = SCNNode(geometry: lines)
    scene.rootNode.addChildNode(cellNode)
    

如前所述,SceneKit 统计数据表明正在绘制线 ,但它似乎没有出现,并且没有编译或运行时错误,这使得追踪起来有点棘手.

编辑:在调试导航器中使用 GPU“分析”工具出现以下错误:

Draw call exceeded element array buffer bounds

Draw call exceeded array buffer bounds

glDrawElements(GL_LINES, 4, GL_UNSIGNED_INT, NULL) 中,这表明我的 SCNGeometryElement 构造有问题?

【问题讨论】:

    标签: ios swift scenekit


    【解决方案1】:

    我没有机会实时调试代码,但很可能这些行是您的问题:

    let vertexData = NSData(bytes: &positions, length: positions.count)
    // ...
    let indexData = NSData(bytes: &indicies, length: indicies.count)
    

    数据的长度是条目数乘以每个条目的大小(以字节为单位)。 positions中的每个元素都是一个SCNVector3,在iOS上是三个Floats,所以每个位置都是3 * sizeof(Float)或者12个字节。 indicies(原文如此)中的每个元素都是一个 CInt,我相信它是一个 32 位整数。因此,您的数据缓冲区比您的 SCNGeometrySourceSCNGeometryElement 构造函数声称的要短得多,这意味着在渲染时 SceneKit 要求 OpenGL 进行较长的 walk 画出一个短的 码头缓冲区。

    通常,如果您从数组构造NSData,您希望length 参数为数组计数乘以sizeof 数组的元素类型。

    【讨论】:

    • 啊,我很快就谈到了 IntCInt。这条线用indices: [Int]let indexData = NSData(bytes: &indices, length: sizeof(Int)*indices.count) 绘制,但仅当 let element = SCNGeometryElement(...) 线有bytesPerIndex: sizeof(CInt) 并且它不起作用bytesPerIndex: sizeof(Int)。由于我认为保持一致会更好,因此我将在我的代码中坚持使用 indices: [CInt],即使 indices: [Int] 现在在技术上有效......
    • NSData 需要指定一个明确的长度,因为你要给它一个任意的字节包,它需要知道那个包有多大。在 Swift 中,NSData 理论上可以从你给它的数组的大小推断出长度(因为 Swift 数组知道它们自己的大小)......但目前 NSData 的 Swift 初始化程序只是从ObjC 版本,需要告知长度,因为 C 数组不知道自己的大小。
    • 在 C 中,sizeof 是一个编译器指令,可以采用类型名称或值。在 Swift 中,sizeof 接受一个类型,sizeofValue 接受一个值……然而,sizeofValue 只是在你给它一个数组时返回指针的大小,所以如果你愿意,你应该传递 sizeof(MyType) * arrayOfMyType.count数组数据的总长度。
    • 另外,根据indices 数组的大小,您可能需要考虑较小的整数类型。您真的在该缓冲区中填充 2^31 个索引吗?我不知道 SceneKit 是否会在将其发送到 GPU 之前为您优化。
    • 至于 Swift Int 的问题,我猜这是因为它实际上是我设备上的 Int64,但 SCNGeometryElement 不支持 8 bytesPerIndex。如果我给bytesPerIndex: sizeof(CInt)它在技术上“有效”,但我想它从indexData: Int读取不正确的整数,因为它期望读取Int32s而我实际上是错误地给它Int64s...我现在在任何地方都明确地使用Int8,它工作正常。
    猜你喜欢
    • 2012-12-31
    • 2013-09-21
    • 1970-01-01
    • 1970-01-01
    • 2017-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多