Using SCNMorpher creates unwanted flat polygons in SceneKit

I use SCNMorpher in iOS SceneKit to convert between different facial expressions in a 3D face model exported as a DAE file from Blender. Morphing itself works great.

Before I first call setWeight:forTargetAtIndex:in morpher, the model will be done smoothly, if desired.

But as soon as I make this call, all the edges of the polygon become visible, which is very unattractive. This is the same difference as the transition from "smooth" to "flat" rendering in Blender itself.

Images follow: first, smooth rendering, preliminary morphology, then flat rendering, post-morph.

Smooth rendering, pre-morphFlat rendering, post-morph

( ), litPerPixel .

, / SCNMorpher, -, . , - , .

, , . ( , , , , , , ).

:

faceNode.geometry = faces.rootNode.childNodeWithName("neutral", recursively: true)!.geometry
scene.rootNode.addChildNode(faceNode)

var morphs: [SCNGeometry] = []

let moods: [String] = "mood1 mood2".componentsSeparatedByString(" ")
for mood in moods {
  let moodFace = faces.rootNode.childNodeWithName(mood, recursively: true)!.geometry!
  morphs.append(moodFace)
}

let morpher = SCNMorpher()
morpher.targets = morphs

faceNode.morpher = morpher
morpher.setWeight(0.5, forTargetAtIndex: 0)
+4
3

. unirmNormals true morpher.

let morpher = SCNMorpher()
morpher.targets = morphs
morpher.unifiesNormals = true
faceNode.morpher = morpher
+2

, : .

, Accelerate/vDSP .

, , SCNMorpher - . ( 30 40 000 iPhone 6):

// .h

@property (nonatomic) size_t morphBufferSize;
@property (nonatomic) float* morphBuffer;

// .m (note: we assume floats not doubles by using vDSP_vintb rather than vDSP_vintbD)

- (SCNGeometry*)morphGeometry:(SCNGeometry*)g1 toGeometry:(SCNGeometry*)g2 withWeight:(float)weight {
  SCNGeometrySource* v1 = [g1 geometrySourcesForSemantic:SCNGeometrySourceSemanticVertex].firstObject;
  SCNGeometrySource* n1 = [g1 geometrySourcesForSemantic:SCNGeometrySourceSemanticNormal].firstObject;
  SCNGeometrySource* v2 = [g2 geometrySourcesForSemantic:SCNGeometrySourceSemanticVertex].firstObject;
  SCNGeometrySource* n2 = [g2 geometrySourcesForSemantic:SCNGeometrySourceSemanticNormal].firstObject;

  vDSP_Length len = v1.data.length;
  vDSP_Length numFloats = len / sizeof(float);

  if (_morphBufferSize < len) {
    _morphBuffer = realloc(_morphBuffer, len);
    _morphBufferSize = len;
  }

  vDSP_vintb(v1.data.bytes, 1,
             v2.data.bytes, 1,
             &weight,
             _morphBuffer, 1,
             numFloats);

  SCNGeometrySource* v3 = [SCNGeometrySource geometrySourceWithData:[NSData dataWithBytesNoCopy:_morphBuffer length:len freeWhenDone:NO]
                                                           semantic:SCNGeometrySourceSemanticVertex
                                                        vectorCount:v1.vectorCount
                                                    floatComponents:v1.floatComponents
                                                componentsPerVector:v1.componentsPerVector
                                                  bytesPerComponent:v1.bytesPerComponent
                                                         dataOffset:v1.dataOffset
                                                         dataStride:v1.dataStride];

  vDSP_vintb(n1.data.bytes, 1,
             n2.data.bytes, 1,
             &weight,
             _morphBuffer, 1,
             numFloats);

  SCNGeometrySource* n3  = [SCNGeometrySource geometrySourceWithData:[NSData dataWithBytesNoCopy:_morphBuffer length:len freeWhenDone:NO]
                                                            semantic:SCNGeometrySourceSemanticNormal
                                                         vectorCount:n1.vectorCount
                                                     floatComponents:n1.floatComponents
                                                 componentsPerVector:n1.componentsPerVector
                                                   bytesPerComponent:n1.bytesPerComponent
                                                          dataOffset:n1.dataOffset
                                                          dataStride:n1.dataStride];

  NSMutableArray* elements = [NSMutableArray arrayWithCapacity:g1.geometryElementCount];
  for (NSInteger i = 0, len = g1.geometryElementCount; i < len; i ++) [elements addObject:[g1 geometryElementAtIndex:i]];

  SCNGeometry* g3 = [SCNGeometry geometryWithSources:@[v3, n3] elements:elements];
  return g3;
}

- (void)dealloc {
    free(_morphBuffer);
}
0

, unifiesNormals , morpher .

. , , "".

, morpher ( ).

, .

morpher ModelI/O, .

SCNGeometry* soomthGeoUsingModelIO(SCNGeometry *geo){
    MDLMesh *mesh = [MDLMesh meshWithSCNGeometry:geo];
    MDLMesh *newMesh = [MDLMesh newSubdividedMesh:mesh submeshIndex:0 subdivisionLevels:0];
    //creaseThreshold is the cos value of MAX crease angle you can tolerate
    [newMesh addNormalsWithAttributeNamed:@"normals" creaseThreshold:0];
    SCNGeometry *flatGeo = [SCNGeometry geometryWithMDLMesh:newMesh];
    return flatGeo;
}
0

All Articles