在 iOS 上使用 Swift 用 SceneKit 画一条线:画线但不可见?
Draw a line with SceneKit using Swift on iOS: line drawn but not visible?
我在 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
// 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 'Analyse' 工具出现以下错误:
Draw call exceeded element array buffer bounds
Draw call exceeded array buffer bounds
在 glDrawElements(GL_LINES, 4, GL_UNSIGNED_INT, NULL)
中,这表明我的 SCNGeometryElement 构造有问题?
我还没有机会实时调试代码,但这些行很可能是您的问题:
let vertexData = NSData(bytes: &positions, length: positions.count)
// ...
let indexData = NSData(bytes: &indicies, length: indicies.count)
您的数据长度是条目数乘以每个条目的大小(以字节为单位)。 positions
中的每个元素都是一个SCNVector3
,也就是iOS上的三个Float
,所以每个位置都是3 * sizeof(Float)
也就是12个字节。 indicies
(原文如此)中的每个元素都是一个 CInt
,我认为它是一个 32 位整数。所以你的数据缓冲区比你的 SCNGeometrySource
和 SCNGeometryElement
构造函数声称的要短得多,这意味着在渲染时 SceneKit 要求 OpenGL 走很长的 walk 划出一个短码头缓冲区。
通常,如果您从数组构造 NSData
,您希望 length 参数是数组计数乘以 sizeof
数组的元素类型。
我在 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 // 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 'Analyse' 工具出现以下错误:
Draw call exceeded element array buffer bounds
Draw call exceeded array buffer bounds
在 glDrawElements(GL_LINES, 4, GL_UNSIGNED_INT, NULL)
中,这表明我的 SCNGeometryElement 构造有问题?
我还没有机会实时调试代码,但这些行很可能是您的问题:
let vertexData = NSData(bytes: &positions, length: positions.count)
// ...
let indexData = NSData(bytes: &indicies, length: indicies.count)
您的数据长度是条目数乘以每个条目的大小(以字节为单位)。 positions
中的每个元素都是一个SCNVector3
,也就是iOS上的三个Float
,所以每个位置都是3 * sizeof(Float)
也就是12个字节。 indicies
(原文如此)中的每个元素都是一个 CInt
,我认为它是一个 32 位整数。所以你的数据缓冲区比你的 SCNGeometrySource
和 SCNGeometryElement
构造函数声称的要短得多,这意味着在渲染时 SceneKit 要求 OpenGL 走很长的 walk 划出一个短码头缓冲区。
通常,如果您从数组构造 NSData
,您希望 length 参数是数组计数乘以 sizeof
数组的元素类型。