如何在 SceneKit 中使用“带有 Alpha 通道的 HEVC”视频?

Ama*_*lin 6 ios scenekit swift

在 WWDC 2019 上,苹果宣布现在正在 iOS 中使用 Alpha 处理 HEVC,并声明它可以在 SceneKit 中使用。

\n\n

我已经尝试了几个小时来实现这一目标,但没有任何运气。

\n\n

我的目标是使用视频作为 SCNNode 平面上的纹理,并在视频透明的地方使该平面透明。

\n\n

我在这个 xcode 项目中使用 Apple 提供的带有 Alpha 视频的 HEVC (带有 2 个木偶的视频)。

\n\n

我正在使用 iOS 13.2 的真实设备上使用 XCode 11.2 进行开发。

\n\n

我尝试了不同的方法。

\n\n

方法 1. 使用 AVPlayer 作为 SCNNode 材质的漫反射 + 透明内容

\n\n
let videoURL = Bundle.main.url(forResource: \xe2\x80\x9cpuppets_with_alpha_hevc\xe2\x80\x9c, withExtension: "mov", subdirectory: "Assets.scnassets");\nlet player = AVPlayer(url: videoURL! as URL)\nlet material = SCNMaterial()\nmaterial.diffuse.contents = player\nmaterial.transparent.contents = player\nplane?.geometry?.materials = [material];\nplayer.play();\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:视频用黑色像素而不是透明像素渲染。

\n\n

方法2.将AVPlayer嵌入到SKVideoNode中,然后将SKVideoNode嵌入到SKScene中,并使用SKScene作为我的SCNNode材质的漫反射+材质内容

\n\n

这似乎是在 SceneKit 中将视频显示为素材的常见方式。此外,在苹果提供的有关如何使用 alpha\xe2\x80\x9d 渲染 \xe2\x80\x9cHEVC 视频的示例中,他们使用 SKVideoNode (但不在 SceneKit 上下文中)。

\n\n
let videoNode = SKVideoNode(avPlayer: player)\nlet spritescene = SKScene(size: CGSize(width: 360, height: 480))\nlet spriteKitScene = SKScene(size: CGSize(width: 360.0 / 2.0, height: 480.0 / 2.0))\nspriteKitScene.scaleMode = .aspectFit\nvideoNode.position = CGPoint(x: spriteKitScene.size.width / 2.0, y: spriteKitScene.size.height / 2.0)\nvideoNode.size = spriteKitScene.size\nspriteKitScene.addChild(videoNode)\nlet material = SCNMaterial()\nmaterial.diffuse.contents = spriteKitScene\nmaterial.transparent.contents = spriteKitScene\nplane?.geometry?.materials = [material];\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:出现此崩溃:

\n\n
\n

validateFunctionArguments:3577: 断言失败 `Fragment\n Function(FastSingle_FragFunc): 缺少 u_texture_sampler[0] 在索引 0 处的采样器绑定。\'

\n
\n\n

注意:当我使用没有 Alpha 通道的常规 HEVC 视频时,我不会\xe2\x80\x99 出现此错误。

\n\n

方法 3. 使用材质着色器将 alpha 值从视频复制到材质的透明贴图。

\n\n
let material = SCNMaterial()\nmaterial.diffuse.contents = player\nmaterial.shaderModifiers = [\n    SCNShaderModifierEntryPoint.surface :  "_surface.transparent.a = _surface.diffuse.a;"\n];\nplane?.geometry?.materials = [material];\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果:视频用黑色像素而不是透明像素渲染。alpha信息似乎不在_surface.diffuse.a中

\n\n

方法 4. 使用 SKScene 的着色器而不是 AVPlayer

\n\n

结果 :与方法 2 的错误相同。

\n\n

有谁知道如何进行这项工作?

\n\n

更新:2020 年 1 月 7 日,星期二

\n\n

我在 iOS 13.3 和 XCode 11.3 上尝试了不同的方法。\n=> 相同的结果。

\n\n

我刚刚向 Apple 报告了该错误,感谢@mnuages 提供的链接。

\n\n

更新:2020 年 3 月 24 日,星期二

\n\n

iOS 13.4 的发布解决了该问题。

\n\n

SceneKit 会立即考虑具有透明度的 HEVC 视频,而无需干扰材质的透明内容或着色器。

\n

mnu*_*ges 1

第一个代码片段应该可以工作(无需设置transparent材质属性)。如果您在 macOS SceneKit 游戏模板中进行以下更改,您将获得正确的结果,但它不适用于 iOS SceneKit 游戏模板。

// retrieve the ship node
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
let videoURL = Bundle.main.url(forResource: "puppets_with_alpha_hevc", withExtension: "mov", subdirectory: "art.scnassets");
let player = AVPlayer(url: videoURL! as URL)
let material = SCNMaterial()
material.diffuse.contents = player
player.play();
ship.enumerateHierarchy { (node, _) in
    if let geometry = node.geometry {
        geometry.materials = [material];
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,人们可能想要提交一个错误来修复 iOS 版本。