WeAre - AR相簿
ARKit
線上地址 https://itunes.apple.com/cn/app/weare/id1304227680?mt=8
開源地址 https://github.com/SherlockQi/HeavenMemoirs 歡迎(跪求)Star!
WeAre
技術點
AR初始化 在新建專案時可以直接建立 AR 專案, xcode 會創造一個 AR 專案的模板.
也可以建立普通的專案,在需要實現 AR 功能的控制器中實現如下程式碼進行初始化.
import ARKit
let sceneView = ARSCNView()
override func viewDidLoad() {
super.viewDidLoad()
sceneView.frame = view.bounds
view.addSubview(sceneView)
sceneView.delegate = self
sceneView.showsStatistics = true
// 建立一個場景,系統預設是沒有的
let scene = SCNScene()
sceneView.scene = scene
//不允許使用者操作攝像機
sceneView.allowsCameraControl = false
//抗鋸齒
sceneView.antialiasingMode = .multisampling4X
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let configuration = ARWorldTrackingConfiguration()
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
sceneView.session.pause()
}
複製程式碼
新增節點
//我使用的是 SCNPlane 來充當相框,也可以使用"厚度"很小的 SCNBox
let photo = SCNPlane(width: 1, height: 1)
//photo.cornerRadius = 0.01
let image = UIImage(named: "0")
//紋路可以使圖片,也可以是顏色
photo.firstMaterial?.diffuse.contents = image
//photo.firstMaterial?.diffuse.contents = UIColor.red
let photoNode = SCNNode(geometry: photo)
//節點的位置
let vector3 = SCNVector3Make(-1, -1, -1)
photoNode.position = vector3
sceneView.scene.rootNode.addChildNode(photoNode)
複製程式碼
let text = SCNText(string: "文字", extrusionDepth: 0.1)
text.font = UIFont.systemFont(ofSize: 0.4)
let textNode = SCNNode(geometry: text)
textNode.position = SCNVector3Make(0,0, -1)
//文字的圖片/顏色
text.firstMaterial?.diffuse.contents = UIImage(named: color)
sceneView.scene.rootNode.addChildNode(textNode)
複製程式碼
可供選擇的幾何圖形
SCNText 文字
SCNPlane 平面
SCNBox 盒子
SCNPyramid 錐形
SCNSphere 球
SCNCylinder 圓柱
SCNCone 圓錐
SCNTube 圓筒
SCNCapsule 膠囊
SCNTorus 圓環
SCNFloor 地板
SCNShape 自定義
複製程式碼
全景圖實現
想象自己站在一個球的球心處,球的內表面塗著壁畫,那麼是不是就實現了全景圖.
所以用一個Sphere 節點包裹著相機節點(也就是0位置節點),再設定Sphere節點的內表面紋理,就實現了功能.
let sphere = SCNSphere(radius: 15)
let sphereNode = SCNNode(geometry: sphere)
sphere.firstMaterial?.isDoubleSided = true
sphere.firstMaterial?.diffuse.contents = image
sphereNode.position = SCNVector3Zero
scene.rootNode.addChildNode(sphereNode)
複製程式碼
播放視訊
let height:CGFloat = CGFloat(width) * videoSize.height/videoSize.width
let box = SCNBox(width: width, height: height, length: 0.3, chamferRadius: 0)
boxNode.geometry = box;
boxNode.geometry?.firstMaterial?.isDoubleSided = true
boxNode.position = SCNVector3Make(0, 0, -5);
box.firstMaterial?.diffuse.contents = UIColor.red
self.scene.rootNode.addChildNode(boxNode);
let avplayer = AVPlayer(url: url)
avplayer.volume = rescoucceConfiguration.video_isSilence ? 0.0 : 3.0
videoPlayer = avplayer
let videoNode = SKVideoNode(avPlayer: avplayer)
NotificationCenter.default.addObserver(self, selector: #selector(playEnd(notify:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
videoNode.size = CGSize(width: 1600, height: 900)
videoNode.position = CGPoint(x: videoNode.size.width/2, y: videoNode.size.height/2)
videoNode.zRotation = CGFloat(Float.pi)
let skScene = SKScene()
skScene.addChild(videoNode)
skScene.size = videoNode.size
box.firstMaterial?.diffuse.contents = skScene
videoNode.play()
複製程式碼
粒子效果
/*
particleName = "bokeh.scnp"
particleName = "rain.scnp"
particleName = "confetti.scnp"
**/
particleSytem = SCNParticleSystem(named: particleName, inDirectory: nil){
particleNode.addParticleSystem(particleSytem)
particleNode.position = SCNVector3Make(0, Y, 0)
self.scene.rootNode.addChildNode(particleNode)
複製程式碼
節點點選事件
//給 場景檢視sceneView 新增點選事件
let tap = UITapGestureRecognizer(target: self, action: #selector(tapHandle(gesture:)))
sceneView.addGestureRecognizer(tap)
複製程式碼
@objc func tapHandle(gesture:UITapGestureRecognizer){
let results:[SCNHitTestResult] = (self.sceneView?.hitTest(gesture.location(ofTouch: 0, in: self.sceneView), options: nil))!
guard let firstNode = results.first else{
return
}
// 這就是點選到的節點 可以對他做一些事情 或者根據這個節點的某些屬性執行不同的方法
let node = firstNode.node.copy() as! SCNNode
if firstNode.node == self.selectNode {
...推遠照片...
}else{
...拉近照片...
selectNode = node
}
}
複製程式碼
節點動畫 我的另一篇文章中有詳細記錄ARKit-動畫 //拉近(推遠)照片
//這只是其中一種方法
let newPosition = SCNVector3Make(firstNode.node.worldPosition.x*2, firstNode.node.worldPosition.y*2, firstNode.node.worldPosition.z*2)
let comeOut = SCNAction.move(to: newPosition, duration: 1.2)
firstNode.node.runAction(comeOut)
複製程式碼
自傳/公轉
//自轉
let box = SCNBox(width: boxW, height: boxW, length: boxW, chamferRadius: 0)
let boxNode = SCNNode(geometry: box)
boxNode.position = vector3
let emptyNode = SCNNode()
emptyNode.position = SCNVector3Zero
emptyNode.rotation = SCNVector4Make(0, 1, 0, Float.pi/Float(L/2) * Float(index))
emptyNode.addChildNode(boxNode)
photoRingNode.addChildNode(emptyNode)
let ringAction = SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: right, z: 0, duration: 2))
boxNode.runAction(ringAction)
//公轉 把節點加到一個正在自傳的節點上就可以了
複製程式碼
錄屏 錄屏是使用ReplayKit完成的 開始錄屏
協議
RPScreenRecorderDelegate,RPPreviewViewControllerDelegate
RPScreenRecorder.shared().startRecording(handler: nil)
RPScreenRecorder.shared().delegate = self
複製程式碼
錄製代理
func screenRecorder(_ screenRecorder: RPScreenRecorder, didStopRecordingWith previewViewController: RPPreviewViewController?, error: Error?) {
print(error ?? "error")
if error != nil{
print("error:", error ?? "")
DispatchQueue.main.async {
let string = error?.localizedDescription
ITTPromptView .showMessage(string, andFrameY: 0)
print(string ?? "")
//錄製期間失敗
self.showFailReplay()
}
}else{
print("else")
}
print("start recording handler")
}
//錄製失敗
func showFailReplay(){
let sb = UIStoryboard(name: "Main", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "HKExplainViewController")
self.navigationController?.pushViewController(vc, animated: true)
self.replayButtonRight.constant = 85;
for button in self.smailButtons {
button.alpha = 1
}
self.mainButton.alpha = 1
UIView.animate(withDuration: 2.5) {
self.stopReplayButton.alpha = 0
self.view.layoutIfNeeded()
}
}
複製程式碼
結束並彈出預覽控制器
RPScreenRecorder.shared().stopRecording { (vc, erroe) in
vc?.previewControllerDelegate = self
vc?.title = "We Are"
self.present(vc!, animated: true, completion: nil)
}
複製程式碼
預覽控制器的代理
func previewController(_ previewController: RPPreviewViewController, didFinishWithActivityTypes activityTypes: Set<String>) {
print(activityTypes)
//取消
if activityTypes.count == 0 {
previewController.dismiss(animated: true, completion: nil)
}
//儲存
if activityTypes.contains("com.apple.UIKit.activity.SaveToCameraRoll"){
ITTPromptView .showMessage("視訊已儲存在相簿", andFrameY: 0)
previewController.dismiss(animated: true, completion: nil)
//檢測到您剛剛儲存了視訊 是否想要分享
let delay = DispatchTime.now() + .seconds(2)
DispatchQueue.main.asyncAfter(deadline: delay) {
self.outputVideo()
}
}
}
複製程式碼
歡迎(跪求)Star!