You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARKit/SpriteKit:为SKVideoNode设置pixelBufferAttributes或实现视频抠像

在ARKit中实现SKVideoNode的视频像素透明(色度键抠像)

嘿,很高兴看到你已经搞定了用ARKit在真实场景里播放视频的基础功能!要给视频加上透明背景(也就是色度键抠像,把绿幕/蓝幕去掉),这里有两种实用的方案,我结合实践给你拆解下:

方法一:用CoreImage滤镜实时抠像(最通用)

如果你的视频是带绿幕/蓝幕的普通视频,这个方法最靠谱——通过CoreImage的CIColorKeyFilter把指定颜色的背景抠掉,再把处理后的帧渲染到SKNode上。

步骤&代码示例:

  1. 替换SKVideoNode为自定义SpriteNode:因为要手动处理每一帧,所以改用SKSpriteNode承载纹理。
  2. 设置AVPlayerItem的视频输出:捕获视频的原始像素缓冲区,方便后续处理。
  3. 实时处理每一帧:用CoreImage滤镜抠像,再更新SpriteNode的纹理。
// 先在视图控制器里定义变量
var videoOutput: AVPlayerItemVideoOutput!
var player: AVPlayer!
var videoSprite: SKSpriteNode!

// 在nodeFor anchor方法里初始化视频和SpriteNode
func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
    guard let urlString = Bundle.main.path(forResource: "resourceName", ofType: "mp4") else { return nil }
    let url = URL(fileURLWithPath: urlString)
    let asset = AVAsset(url: url)
    let playerItem = AVPlayerItem(asset: asset)
    
    // 设置视频输出的像素格式(必须支持带alpha的BGRA格式)
    let pixelBufferAttrs = [
        kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA,
        kCVPixelBufferAlphaChannelIsOpaqueKey as String: false
    ]
    videoOutput = AVPlayerItemVideoOutput(pixelBufferAttributes: pixelBufferAttrs)
    playerItem.add(videoOutput)
    
    player = AVPlayer(playerItem: playerItem)
    player.play()
    
    // 创建用来显示处理后视频的SpriteNode
    videoSprite = SKSpriteNode()
    videoSprite.size = CGSize(width: 150, height: 300) // 按你的视频比例调整尺寸
    
    // 启动CADisplayLink实时处理帧(比定时器更精准)
    let displayLink = CADisplayLink(target: self, selector: #selector(processVideoFrame))
    displayLink.add(to: .main, forMode: .common)
    
    return videoSprite
}

// 处理每一帧的方法
@objc func processVideoFrame() {
    let currentTime = player.currentTime()
    // 获取当前帧的像素缓冲区
    guard let pixelBuffer = videoOutput.copyPixelBuffer(forItemTime: currentTime, itemTimeForDisplay: nil) else { return }
    
    // 初始化CoreImage滤镜
    let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
    guard let colorKeyFilter = CIFilter(name: "CIColorKeyFilter") else { return }
    
    colorKeyFilter.setValue(ciImage, forKey: kCIInputImageKey)
    // 设置要抠掉的背景色(这里是纯绿色,你可以根据你的视频调整RGB值)
    colorKeyFilter.setValue(CIColor(red: 0.0, green: 1.0, blue: 0.0), forKey: kCIInputColorKey)
    // 调整容差(Threshold)和柔化(Softness),让抠像边缘更自然
    colorKeyFilter.setValue(0.15, forKey: kCIInputThresholdKey)
    colorKeyFilter.setValue(0.1, forKey: kCIInputSoftnessKey)
    
    // 获取处理后的带透明通道的图像
    guard let outputImage = colorKeyFilter.outputImage else { return }
    
    // 把CIImage转换成SKTexture(用GPU加速)
    let ciContext = CIContext(options: [.useSoftwareRenderer: false])
    guard let cgImage = ciContext.createCGImage(outputImage, from: outputImage.extent) else { return }
    let texture = SKTexture(cgImage: cgImage)
    
    // 更新SpriteNode的纹理
    videoSprite.texture = texture
}

方法二:使用自带Alpha通道的视频(更高效)

如果你的视频本身已经导出了带透明通道的格式(比如ProRes 4444、PNG序列转的视频),那可以直接给SKVideoNode设置像素属性,让它支持透明:

func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
    guard let urlString = Bundle.main.path(forResource: "resourceName", ofType: "mov") else { return nil }
    let url = URL(fileURLWithPath: urlString)
    let asset = AVAsset(url: url)
    let playerItem = AVPlayerItem(asset: asset)
    let player = AVPlayer(playerItem: playerItem)
    
    let videoNode = SKVideoNode(avPlayer: player)
    // 设置像素属性,指定支持alpha的格式
    videoNode.pixelBufferAttributes = [
        kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA,
        kCVPixelBufferAlphaChannelIsOpaqueKey as String: false
    ]
    videoNode.size = CGSize(width: 150, height: 300)
    player.play()
    
    return videoNode
}

实用提示:

  • 调整CIColorKeyFilter的Threshold和Softness参数是关键,多试几个值,避免把角色的边缘颜色也抠掉,或者留下背景色残留。
  • 如果遇到性能问题,可以降低视频的分辨率,或者把CoreImage的处理移到Metal后台队列里。
  • 在ARSKView中,记得给SKNode设置合适的zPosition,确保角色显示在真实场景的前面。

内容的提问来源于stack exchange,提问作者2shy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:30:57