How to create a SceneKit SCNSkinner object in code? How to create a SceneKit SCNSkinner object in code? xcode xcode

How to create a SceneKit SCNSkinner object in code?


This three methods may help you to find the solution:

  1. SCNNode *hero = [SCNScene sceneNamed:@"Hero"].rootNode;SCNNode *hat = [SCNScene sceneNamed:@"FancyFedora"].rootNode;hat.skinner.skeleton = hero.skinner.skeleton;
  2. [Export ("initWithFrame:")]public UIView (System.Drawing.RectangleF frame) : base (NSObjectFlag.Empty){// Invoke the init method now.    var initWithFrame = new Selector ("initWithFrame:").Handle;    if (IsDirectBinding)        Handle = ObjCRuntime.Messaging.IntPtr_objc_msgSend_RectangleF (this.Handle, initWithFrame, frame);    else        Handle = ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper_RectangleF (this.SuperHandle, initWithFrame, frame);}
  3. See this link as well.


I don't specifically know what causes your code to crash but here is a way of generating a mesh, bones, and skinning that mesh -- all from code. Swift4 and iOS 12.

In the example, there is mesh representing the concatenation of two cylinders, with one of the cylinders branching off at a 45 degree angle, like so:

 \ |

The cylinders are just extruded triangles, i.e., radialSegmentCount = 3. (Note that there are 12 vertices, not 9, since the two cylinders aren't really conjoined. The triangles are ordered like this:

      v5      ^v3 /__|__\ v1   |  |  |   |  v4 |v2 |/___\| v0

There are 3 bones, corresponding to the heads and feet of the cylinders, where the middle bone corresponds to the head of the bottom cylinder and simultaneously the foot of the top cylinder. So for example, vertices v0, v2, and v4 correspond to bone0; v1, v3, v5 correspond to bone1, and so forth. That explains why boneIndices (see below) has the value that it does.

The resting positions of the bones corresponds to the resting positions of the cylinders in the geometry (bone2 sprouts off at a 45 degree angle from bone1, just like the cylinder geometry).

With that as context, the following code creates everything needed to skin the geometry:

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

Note: In most cases, you should use UInt16 not UInt8.