import UIKit
import SceneKit
import SpriteKit
import AVFoundation
class ViewController: UIViewController, SCNSceneRendererDelegate {
@IBOutlet weak var sceneView: SCNView!
override func viewDidLoad() {
super.viewDidLoad()
// A SpriteKit scene to contain the SpriteKit video node
let spriteKitScene = SKScene(size: CGSize(width: sceneView.frame.width, height: sceneView.frame.height))
spriteKitScene.scaleMode = .aspectFit
// Create a video player, which will be responsible for the playback of the video material
let videoUrl = Bundle.main.url(forResource: "videos/video", withExtension: "mp4")!
let videoPlayer = AVPlayer(url: videoUrl)
// To make the video loop
videoPlayer.actionAtItemEnd = .none
NotificationCenter.default.addObserver(
self,
selector: #selector(ViewController.playerItemDidReachEnd),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: videoPlayer.currentItem)
// Create the SpriteKit video node, containing the video player
let videoSpriteKitNode = SKVideoNode(avPlayer: videoPlayer)
videoSpriteKitNode.position = CGPoint(x: spriteKitScene.size.width / 2.0, y: spriteKitScene.size.height / 2.0)
videoSpriteKitNode.size = spriteKitScene.size
videoSpriteKitNode.yScale = -1.0
videoSpriteKitNode.play()
spriteKitScene.addChild(videoSpriteKitNode)
// Create the SceneKit scene
let scene = SCNScene()
sceneView.scene = scene
sceneView.delegate = self
sceneView.isPlaying = true
// Create a SceneKit plane and add the SpriteKit scene as its material
let background = SCNPlane(width: CGFloat(100), height: CGFloat(100))
background.firstMaterial?.diffuse.contents = spriteKitScene
let backgroundNode = SCNNode(geometry: background)
scene.rootNode.addChildNode(backgroundNode)
...
}
// This callback will restart the video when it has reach its end
func playerItemDidReachEnd(notification: NSNotification) {
if let playerItem: AVPlayerItem = notification.object as? AVPlayerItem {
playerItem.seek(to: kCMTimeZero)
}
}
...
}
let mat = SCNMaterial()
let videoUrl = Bundle.main.url(forResource: "YourVideo", withExtension: "mp4")!
let player = AVPlayer(url: videoUrl)
mat.diffuse.contents = player
player.actionAtItemEnd = .none
NotificationCenter.default.addObserver(self,
selector: #selector(playerItemDidReachEnd(notification:)),
name: .AVPlayerItemDidPlayToEndTime,
object: player.currentItem)
player.play()
Code for method in selector:
@objc private func playerItemDidReachEnd(notification: Notification) {
if let playerItem = notification.object as? AVPlayerItem {
playerItem.seek(to: .zero, completionHandler: nil)
}
}
Note: for ten years now you do NOT remove notifications that run a selector. (You only need to do so in the obscure case you're using a block.)
If you have time-travelled to before 2015: Don't forget to remove your notification observer when the object is deallocated! Something like NotificationCenter.default.removeObserver(self,name: .AVPlayerItemDidPlayToEndTime,object: player.currentItem)*
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
// Create a new scene
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// Set the scene to the view
sceneView.scene = scene
let movieFileURL = Bundle.main.url(forResource: "example", withExtension: "mov")!
let player = AVPlayer(url:movieFileURL)
scene.background.contents = player
sceneView.play(nil) //without this line the movie was not playing
player.play()
}
// make some mesh. whatever size you want.
let mesh = SCNPlane()
mesh.width = 1.77
mesh.height = 1
// put the mesh on your node
yourNode.geometry = mesh
// add the video to the mesh
plr = AVPlayer(url: "https .. .m4v")
yourNode.geometry?.firstMaterial?.diffuse.contents = plr
5条答案
按热度按时间m4pnthwp1#
可以在SceneKit中使用SpriteKit场景作为几何体的material来实现这一点。
下面的示例将创建一个SpriteKit场景,使用视频播放器向其中添加一个视频节点,使视频播放器循环,创建一个SceneKit场景,添加一个SceneKit平面,最后将SpriteKit场景添加为平面的漫反射材质。
tzdcorbm2#
Year 2019 solution:
Code for method in selector:
Note: for ten years now you do NOT remove notifications that run a selector. (You only need to do so in the obscure case you're using a block.)
NotificationCenter.default
.removeObserver(self,
name: .AVPlayerItemDidPlayToEndTime,
object: player.currentItem)
*juzqafwq3#
可以使用AVPlayer作为场景背景的内容。但是,直到我将.play(nil)发送到sceneView后,它才对我起作用。
1tuwyuhd4#
2022,现在在Scene Kit中做这个很简单。请参阅Apple文档。
请注意,Apple文档明确指出,现在可以只将视频放在SCNNode上。
注意,你可以在网格上放置任何你想要的东西。("几何"就是网格。)这很简单。例如,如果你只想要一个普通的颜色:
注意,这个问题问的是关于循环播放视频的问题。这是一个无关紧要的问题,与使用SceneKit无关。你可以看到上百万个关于循环播放视频的问题,很简单:
然后再
dsekswqp5#
雨燕5.7
1. SceneKit + SpriteKit的循环视频素材
...工作正常-视频无缝循环...
我在macOS Ventura 13.0.1上的Xcode 14.1模拟器(iOS 16.1)上测试了这个应用程序。对于视频纹理,我使用了带有H.264编解码器的QuickTime 1600x900
.mov
文件。SpriteKit场景能够播放
.mov
视频文件:SceneKit的材质用作SpriteKit视频的媒介:
最后,用于加载视频的方法包含一个
AVPlayerLooper
对象:2. Pure SceneKit的循环视频素材
...工作不正常-视频循环延迟...
您可以采取更短的路线来解决此任务,但问题是,该方法无法正常工作-视频循环播放的延迟等于整个视频的持续时间。
下面我们将
AVQueuePlayer
对象分配给材质的内容: