Swift 如何在代码中创建SceneKit SCNSkinner对象?
我有一个使用SceneKit的iOS 8 Swift应用程序。我从包含由骨架控制的网格的.dae文件加载场景。 在运行时,我需要修改纹理坐标。使用变换不是一个选项——我需要为网格中的每个顶点计算一个不同的、全新的UV 我知道几何体在SceneKit中是不可变的,我读到建议的方法是手动复制。我正试图这样做,但当我试图在代码中重新创建Swift 如何在代码中创建SceneKit SCNSkinner对象?,swift,xcode,ios8,scenekit,Swift,Xcode,Ios8,Scenekit,我有一个使用SceneKit的iOS 8 Swift应用程序。我从包含由骨架控制的网格的.dae文件加载场景。 在运行时,我需要修改纹理坐标。使用变换不是一个选项——我需要为网格中的每个顶点计算一个不同的、全新的UV 我知道几何体在SceneKit中是不可变的,我读到建议的方法是手动复制。我正试图这样做,但当我试图在代码中重新创建SCNSkinner时,总是会失败。崩溃是C3DSourceAccessorGetMutableValuePtrAtIndex内部的EXC\u坏访问。不幸的是,没有这方
SCNSkinner
时,总是会失败。崩溃是C3DSourceAccessorGetMutableValuePtrAtIndex
内部的EXC\u坏访问。不幸的是,没有这方面的源代码,所以我不知道为什么它会崩溃。我已经将其缩小到附加到网格节点的SCNSkinner
对象。如果我没有设置,我就不会崩溃,事情似乎正在运行
编辑:以下是更完整的崩溃调用堆栈:
C3DSourceAccessorGetMutableValuePtrAtIndex
C3DSkinPrepareMeshForGPUIfNeeded
C3DSkinnerMakeCurrentMesh
C3DSkinnerUpdateCurrentMesh
__CFSetApplyFunction_block_invoke
CFBasicHashApply
CFSetApplyFunction
C3DAppleEngineRenderScene
...
我还没有找到任何关于如何手动创建SCNSkinner
对象的文档或示例代码。因为我只是基于以前的工作网格创建它,所以应该不会太难。我正在根据Swift文档创建SCNSkinner
,将所有正确的内容传递到init中。但是,SCNSkinner
中有一个骨架属性,我不知道如何设置。我将其设置为我复制的网格的原始SCNSkinner
上的骨架,我认为
应该有用。。。但事实并非如此。设置骨架特性时,该特性似乎未指定。在赋值后立即检查它,它仍然为零。作为测试,我尝试将原始网格的骨架属性设置为其他属性,在指定之后,它也保持不变
有人能解释发生了什么事吗?或者如何正确地手动创建和设置SCNSkinner
对象
下面是我用来手动克隆网格并替换为新网格的代码(我没有修改这里的任何源数据——我只是想确保此时可以创建一个副本):
这三种方法可以帮助您找到解决方案:
我也看到了
我不知道是什么导致代码崩溃,但这里有一种生成网格、骨骼和蒙皮网格的方法——所有这些都来自代码。Swift4和iOS 12
在该示例中,有一个网格表示两个圆柱体的连接,其中一个圆柱体以45度角分叉,如下所示:
\
|
圆柱体只是拉伸的三角形,即,radialSegmentCount=3。
(请注意,有12个顶点,而不是9个,因为两个圆柱体并非真正连接在一起。三角形的顺序如下:
v5
^
v3 /__|__\ v1
| | |
| v4 |
v2 |/___\| v0
有3块骨头,对应于圆柱体的头和脚,中间的骨头对应于底部圆柱体的头,同时对应于顶部圆柱体的脚。例如,顶点v0
,v2
,和v4
对应于bone0
;v1
,v3
,v5
对应于bone1
,依此类推。这就解释了boneIndicates
(见下文)为什么具有它所具有的值
骨骼的静止位置对应于几何体中圆柱体的静止位置(bone2
与bone1
呈45度角延伸,就像圆柱体几何体一样)
将此作为上下文,以下代码将创建几何体蒙皮所需的所有内容:
let vertices = [float3(0.17841241, 0.0, 0.0), float3(0.17841241, 1.0, 0.0), float3(-0.089206174, 0.0, 0.1545097), float3(-0.089206174, 1.0, 0.1545097), float3(-0.089206256, 0.0, -0.15450965), float3(-0.089206256, 1.0, -0.15450965), float3(0.12615661, 1.1261566, 0.0), float3(-0.58094996, 1.8332633, 0.0), float3(-0.063078284, 0.9369217, 0.1545097), float3(-0.7701849, 1.6440284, 0.1545097), float3(-0.063078344, 0.93692166, -0.15450965), float3(-0.77018493, 1.6440284, -0.15450965)]
let indices: [UInt8] = [0, 1, 2, 3, 4, 5, 0, 1, 1, 6, 6, 7, 8, 9, 10, 11, 6, 7]
let geometrySource = SCNGeometrySource(vertices: vertices.map { SCNVector3($0) })
let geometryElement = SCNGeometryElement(indices: indices, primitiveType: .triangleStrip)
let geometry = SCNGeometry(sources: [geometrySource], elements: [geometryElement])
let bone0 = SCNNode()
bone0.simdPosition = float3(0,0,0)
let bone1 = SCNNode()
bone1.simdPosition = float3(0,1,0)
let bone2 = SCNNode()
bone2.simdPosition = float3(0,1,0) + normalize(float3(-1,1,0))
let bones = [bone0, bone1, bone2]
let boneInverseBindTransforms: [NSValue]? = bones.map { NSValue(scnMatrix4: SCNMatrix4Invert($0.transform)) }
var boneWeights: [Float] = vertices.map { _ in 1.0 }
var boneIndices: [UInt8] = [
0, 1, 0, 1, 0, 1,
1, 2, 1, 2, 1, 2,
]
let boneWeightsData = Data(bytesNoCopy: &boneWeights, count: boneWeights.count * MemoryLayout<Float>.size, deallocator: .none)
let boneIndicesData = Data(bytesNoCopy: &boneIndices, count: boneWeights.count * MemoryLayout<UInt8>.size, deallocator: .none)
let boneWeightsGeometrySource = SCNGeometrySource(data: boneWeightsData, semantic: .boneWeights, vectorCount: boneWeights.count, usesFloatComponents: true, componentsPerVector: 1, bytesPerComponent: MemoryLayout<Float>.size, dataOffset: 0, dataStride: MemoryLayout<Float>.size)
let boneIndicesGeometrySource = SCNGeometrySource(data: boneIndicesData, semantic: .boneIndices, vectorCount: boneIndices.count, usesFloatComponents: false, componentsPerVector: 1, bytesPerComponent: MemoryLayout<UInt8>.size, dataOffset: 0, dataStride: MemoryLayout<UInt8>.size)
let skinner = SCNSkinner(baseGeometry: geometry, bones: bones, boneInverseBindTransforms: boneInverseBindTransforms, boneWeights: boneWeightsGeometrySource, boneIndices: boneIndicesGeometrySource)
let node = SCNNode(geometry: geometry)
node.skinner = skinner
让顶点=[float3(0.17841241,0.0,0.0),float3(0.17841241,1.0,0.0),float3(-0.089206174,0.0,0.1545097),float3(-0.089206174,1.0,0.1545097),float3(-0.089206256,0.0,-0.15450965),float3(-0.089206206,1.0.0,-.0.15450965),float3(-0.12615661,1.1261566),float833(-0.993),float630(-0.063078284,0.9369217,0.1545097),浮动3(-0.7701849,1.6440284,0.1545097),浮动3(-0.063078344,0.93692166,-0.15450965),浮动3(-0.77018493,1.6440284,-0.15450965)]
let索引:[UInt8]=[0,1,2,3,4,5,0,1,1,6,6,7,8,9,10,11,6,7]
设geometrySource=SCNGeometrySource(顶点:顶点.map{SCInvector3($0)})
设geometryElement=SCNGeometryElement(索引:索引,原语类型:.triangleStrip)
let geometry=SCNGeometry(源:[geometrySource],元素:[geometryElement])
设bone0=SCNNode()
bone0.simdPosition=float3(0,0,0)
设bone1=SCNNode()
bone1.simdPosition=float3(0,1,0)
让bone2=SCNNode()
bone2.simdPosition=float3(0,1,0)+规格化(float3(-1,1,0))
let bones=[bone0,bone1,bone2]
让boneInverseBindTransforms:[NSValue]?=bones.map{NSValue(scnMatrix4:SCNMatrix4Invert($0.transform))}
var boneWeights:[Float]=vertices.map{1.0}
var boneIndices:[UInt8]=[
0, 1, 0, 1, 0, 1,
1, 2, 1, 2, 1, 2,
]
让boneWeightsData=Data(bytesnopy:&boneWeights,count:boneWeights.count*MemoryLayout.size,deallocator:.none)
让boneIndicesData=Data(bytesNoCopy:&boneIndices,count:boneWeights.count*MemoryLayout.size,deallocator:.none)
让boneWeightsGeometrySource=SCNGeometrySource(数据:boneWeightsData,语义:.boneWeights,向量计数:boneWeights.count,usesFloatComponents:true,ComponentServiceComponent:1,bytesPerComponent:MemoryLayout.size,数据偏移量:0,数据列:MemoryLayout.size)
让boneIndicesGeometrySource=SCNGeometrySource(数据:boneIndicesData,语义:。boneIndices,vectorCount:boneIndices.count,usesFloatComponents:false,ComponentServiceComponent:1,bytesPerComponent:MemoryLayout.size,dataOffset:0,dataStride:MemoryLayout.size)
让skinner=SCNSkinner(基本几何体:几何体,骨骼:骨骼,boneInverseBindTransforms:boneInverseBindTransforms,boneWeights:boneWeightsGeometrySource,boneIndices:BoneInverseGeometrySource)
let node=SCNNode(几何体
\
|
v5
^
v3 /__|__\ v1
| | |
| v4 |
v2 |/___\| v0
let vertices = [float3(0.17841241, 0.0, 0.0), float3(0.17841241, 1.0, 0.0), float3(-0.089206174, 0.0, 0.1545097), float3(-0.089206174, 1.0, 0.1545097), float3(-0.089206256, 0.0, -0.15450965), float3(-0.089206256, 1.0, -0.15450965), float3(0.12615661, 1.1261566, 0.0), float3(-0.58094996, 1.8332633, 0.0), float3(-0.063078284, 0.9369217, 0.1545097), float3(-0.7701849, 1.6440284, 0.1545097), float3(-0.063078344, 0.93692166, -0.15450965), float3(-0.77018493, 1.6440284, -0.15450965)]
let indices: [UInt8] = [0, 1, 2, 3, 4, 5, 0, 1, 1, 6, 6, 7, 8, 9, 10, 11, 6, 7]
let geometrySource = SCNGeometrySource(vertices: vertices.map { SCNVector3($0) })
let geometryElement = SCNGeometryElement(indices: indices, primitiveType: .triangleStrip)
let geometry = SCNGeometry(sources: [geometrySource], elements: [geometryElement])
let bone0 = SCNNode()
bone0.simdPosition = float3(0,0,0)
let bone1 = SCNNode()
bone1.simdPosition = float3(0,1,0)
let bone2 = SCNNode()
bone2.simdPosition = float3(0,1,0) + normalize(float3(-1,1,0))
let bones = [bone0, bone1, bone2]
let boneInverseBindTransforms: [NSValue]? = bones.map { NSValue(scnMatrix4: SCNMatrix4Invert($0.transform)) }
var boneWeights: [Float] = vertices.map { _ in 1.0 }
var boneIndices: [UInt8] = [
0, 1, 0, 1, 0, 1,
1, 2, 1, 2, 1, 2,
]
let boneWeightsData = Data(bytesNoCopy: &boneWeights, count: boneWeights.count * MemoryLayout<Float>.size, deallocator: .none)
let boneIndicesData = Data(bytesNoCopy: &boneIndices, count: boneWeights.count * MemoryLayout<UInt8>.size, deallocator: .none)
let boneWeightsGeometrySource = SCNGeometrySource(data: boneWeightsData, semantic: .boneWeights, vectorCount: boneWeights.count, usesFloatComponents: true, componentsPerVector: 1, bytesPerComponent: MemoryLayout<Float>.size, dataOffset: 0, dataStride: MemoryLayout<Float>.size)
let boneIndicesGeometrySource = SCNGeometrySource(data: boneIndicesData, semantic: .boneIndices, vectorCount: boneIndices.count, usesFloatComponents: false, componentsPerVector: 1, bytesPerComponent: MemoryLayout<UInt8>.size, dataOffset: 0, dataStride: MemoryLayout<UInt8>.size)
let skinner = SCNSkinner(baseGeometry: geometry, bones: bones, boneInverseBindTransforms: boneInverseBindTransforms, boneWeights: boneWeightsGeometrySource, boneIndices: boneIndicesGeometrySource)
let node = SCNNode(geometry: geometry)
node.skinner = skinner