如何在Objective-C中从CGAffineTransform创建SCNMatrix4?
从CGAffineTransform创建SCNMatrix4的Objective-C实现方法
我无法在Objective-C中实现从CGAffineTransform创建SCNMatrix4的功能,以下是想要迁移到Objective-C的Swift代码:
let affineTransform = frame.displayTransform(for: .portrait, viewportSize: sceneView.bounds.size) let transform = SCNMatrix4(affineTransform) faceGeometry.setValue(SCNMatrix4Invert(transform), forKey: "displayTransform")
我已经实现了第一行和第三行代码,但找不到在Objective-C中从CGAffineTransform创建SCNMatrix4的方法:
CGAffineTransform affine = [self.sceneView.session.currentFrame displayTransformForOrientation:UIInterfaceOrientationPortrait viewportSize:self.sceneView.bounds.size]; SCNMatrix4 trans = ?? [f setValue:SCNMatrix4Invert(trans) forKey:@"displayTransform"];
不存在SCNMatrix4Make方法,尝试过simd_matrix4x4也无效。
背景说明
上述Swift代码来自苹果示例项目「ARKitFaceExample」,完整代码如下:
/* See LICENSE folder for this sample’s licensing information. Abstract: Demonstrates using video imagery to texture and modify the face mesh. */ import ARKit import SceneKit /// - Tag: VideoTexturedFace class VideoTexturedFace: TexturedFace { override func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? { guard let sceneView = renderer as? ARSCNView, let frame = sceneView.session.currentFrame, anchor is ARFaceAnchor else { return nil } #if targetEnvironment(simulator) #error("ARKit is not supported in iOS Simulator. Connect a physical iOS device and select it as your Xcode run destination, or select Generic iOS Device as a build-only destination.") #else // Show video texture as the diffuse material and disable lighting. let faceGeometry = ARSCNFaceGeometry(device: sceneView.device!, fillMesh: true)! let material = faceGeometry.firstMaterial! material.diffuse.contents = sceneView.scene.background.contents material.lightingModel = .constant guard let shaderURL = Bundle.main.url(forResource: "VideoTexturedFace", withExtension: "shader"), let modifier = try? String(contentsOf: shaderURL) else { fatalError("Can't load shader modifier from bundle.") } faceGeometry.shaderModifiers = [ .geometry: modifier] // Pass view-appropriate image transform to the shader modifier so // that the mapped video lines up correctly with the background video. let affineTransform = frame.displayTransform(for: .portrait, viewportSize: sceneView.bounds.size) let transform = SCNMatrix4(affineTransform) faceGeometry.setValue(SCNMatrix4Invert(transform), forKey: "displayTransform") contentNode = SCNNode(geometry: faceGeometry) #endif return contentNode } }
转换逻辑说明
Swift中通过扩展SCNMatrix4实现了转换逻辑,代码如下:
extension SCNMatrix4 { /** Create a 4x4 matrix from CGAffineTransform, which represents a 3x3 matrix but stores only the 6 elements needed for 2D affine transformations. [ a b 0 ] [ a b 0 0 ] [ c d 0 ] -> [ c d 0 0 ] [ tx ty 1 ] [ 0 0 1 0 ] . [ tx ty 0 1 ] Used for transforming texture coordinates in the shader modifier. (Needs to be SCNMatrix4, not SIMD float4x4, for passing to shader modifier via KVC.) */ init(_ affineTransform: CGAffineTransform) { self.init() m11 = Float(affineTransform.a) m12 = Float(affineTransform.b) m21 = Float(affineTransform.c) m22 = Float(affineTransform.d) m41 = Float(affineTransform.tx) m42 = Float(affineTransform.ty) m33 = 1 m44 = 1 } }
Objective-C实现方案
对应的Objective-C实现可通过自定义函数完成:
SCNMatrix4 SCNMatrix4FromCGAffineTransform(CGAffineTransform affineTransform) { SCNMatrix4 matrix = SCNMatrix4Identity; matrix.m11 = (float)affineTransform.a; matrix.m12 = (float)affineTransform.b; matrix.m21 = (float)affineTransform.c; matrix.m22 = (float)affineTransform.d; matrix.m41 = (float)affineTransform.tx; matrix.m42 = (float)affineTransform.ty; return matrix; }
使用时直接调用该函数即可:
CGAffineTransform affine = [self.sceneView.session.currentFrame displayTransformForOrientation:UIInterfaceOrientationPortrait viewportSize:self.sceneView.bounds.size]; SCNMatrix4 trans = SCNMatrix4FromCGAffineTransform(affine); [f setValue:SCNMatrix4Invert(trans) forKey:@"displayTransform"];
内容的提问来源于stack exchange,提问作者IamRob
相关产品推荐
相关产品推荐

