我正在创建一个 iOS 应用程序,我打算在 AR 中显示逼真/高质量的渲染。在试验这 3 个选项的同时,我仍然不确定我应该继续开发我的应用程序框架中的哪一个:SceneKit、RealityKit和Metal。
我读过 SceneKit 是建立在 Metal 之上的,但我不确定是否值得花时间/精力对任何自定义着色器进行编程,而不是使用 SceneKit 默认提供的功能。关于 RealityKit,我不需要它提供的任何动画或特殊效果,只需要照片级渲染方面。
三者中哪一个最适合开发 AR 和高质量模型渲染?
如" 金属着色语言指南"中所述:
片段函数不允许写入缓冲区或纹理.
我明白这是事实,但我很好奇为什么.能够从片段着色器中写入缓冲区是非常有用的 ; 我知道在硬件端可能更复杂的是不提前知道特定线程的内存写入的结束位置,这对于原始缓冲区写入并不总是知道,但这是在Metal计算中公开的一种能力着色器,为什么不在片段着色器中呢?
我应该澄清为什么我认为来自片段函数的缓冲区写入是有用的.在光栅化管道的最常见用例中,三角形被栅格化和着色(根据片段着色器)并写入预定义的存储器位置,在每个片段着色器调用之前已知,并由来自规范化设备坐标和帧的预定义映射确定缓冲.这适用于大多数使用情况,因为大多数情况下您只想将三角形直接渲染到缓冲区或屏幕.
在其他情况下,您可能希望在片段着色器中进行延迟写入,其末端位置基于片段属性而不是片段的确切位置; 有效地,光栅化与副作用.例如,大多数基于GPU的体素化通过从一些期望的角度渲染具有正交投影的场景,然后写入3D纹理,将片段的XY坐标及其相关联的深度值映射到3D纹理中的位置来工作.这在这里描述.
其他用途包括某些形式的与订单无关的透明度(透明度,其中绘制顺序不重要,允许重叠透明对象).一种解决方案是使用多层帧缓冲区,然后在单独的传递中基于它们的深度值对片段进行排序和混合.由于没有硬件支持这样做(在大多数GPU上,我相信英特尔有硬件加速),你必须维护每个像素的原子计数器和手动纹理/缓冲区写入,以协调写入分层帧缓冲区.
另一个例子可能是通过光栅化提取GI的虚拟点光源(即在光栅化时为相关片段写出点光源).在所有这些用例中,都需要来自片段着色器的缓冲区写入,因为ROP仅为每个像素存储一个结果片段.在没有这个特征的情况下获得相同结果的唯一方法是通过某种深度剥离方式,这对于高深度复杂度的场景来说非常慢.
现在我意识到我给出的例子并不是特别关于缓冲区写入,而是更广泛地关于从片段着色器进行动态内存写入的想法,理想情况下是对原子性的支持.缓冲区写入似乎只是一个简单的问题,它们的包含将大大改善这种情况.
由于我在这里没有得到任何答案,我最终在Apple的开发者论坛上发布了这个问题.我在那里得到了更多的反馈,但仍然没有真正的答案.除非我遗漏了某些内容,否则几乎所有官方支持Metal的OS X设备都支持此功能.据我所知,这个功能最初在2009年左右开始出现在GPU中.这是当前DirectX和OpenGL(甚至不考虑DX12或Vulkan)的常见功能,因此Metal将是唯一缺乏它的"尖端"API .
我意识到PowerVR硬件可能不支持此功能,但Apple没有通过功能集区分金属着色语言的问题.例如,iOS上的Metal允许片段着色器内的"自由"帧缓冲器提取,这由高速缓存的PowerVR架构直接支持在硬件中.此功能直接在Metal Shading Language中显示,因为它允许您使用[[color(m)]]
iOS着色器的属性限定符声明片段函数输入.可以说,允许使用device
存储空间限定符声明缓冲区,或者使用纹理access::write
作为片段着色器的输入,对语言的语义更改不会比Apple为优化iOS所做的更多.因此,就我而言,PowerVR缺乏支持并不能解释我在OS X上缺少的功能.
我分配输入和输出MTLBuffer
使用posix_memalign
根据共享GPU/CPU文档由memkite提供.
除此之外:使用最新的API比使用muck更容易 posix_memalign
let metalBuffer = self.metalDevice.newBufferWithLength(byteCount, options: .StorageModeShared)
Run Code Online (Sandbox Code Playgroud)
我的内核函数在大约1600万个复杂值结构上运行,并向内存写出相同数量的复数值结构.
我已经完成了一些实验,我的Metal内核'复杂数学部分'在0.003秒内执行(是!),但是将结果写入缓冲区需要> 0.05(No!)秒.在我的实验中,我注释掉了数学部分并将零分配给内存,它需要0.05秒,注释掉分配并添加数学,0.003秒.
在这种情况下,共享内存是否很慢,或者我可能会尝试其他一些提示或技巧?
对着色器的每次更新都会在结构中以一对float
类型的形式接收大约50000个复数.
struct ComplexNumber {
float real;
float imaginary;
};
Run Code Online (Sandbox Code Playgroud)
kernel void processChannelData(const device Parameters *parameters [[ buffer(0) ]],
const device ComplexNumber *inputSampleData [[ buffer(1) ]],
const device ComplexNumber *partAs [[ buffer(2) ]],
const device float *partBs [[ buffer(3) ]],
const device int *lookups [[ buffer(4) ]], …
Run Code Online (Sandbox Code Playgroud) 我想要capture
一个真实世界的纹理,并将其应用于在激光雷达扫描仪的帮助下生成的 3D 网格。我想应该使用 Projection-View-Model 矩阵。纹理必须从固定的视点制作,例如,从房间的中心。但是,如果我们可以应用environmentTexturing
作为cube-map
场景中的纹理收集的数据,这将是一个理想的解决方案。
看看3D 扫描仪应用程序。这是一个参考应用程序,允许我们导出带有纹理的模型。
我需要通过一次迭代来捕获纹理。我不需要实时更新它。我意识到改变 PoV 会导致错误的纹理感知,换句话说,纹理失真。我也意识到 RealityKit 中有一个动态细分,并且有一个自动纹理 mipmapping(纹理的分辨率取决于它捕获的距离)。
import RealityKit
import ARKit
import MetalKit
import ModelIO
class ViewController: UIViewController, ARSessionDelegate {
@IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
arView.session.delegate = self
arView.debugOptions.insert(.showSceneUnderstanding)
let config = ARWorldTrackingConfiguration()
config.sceneReconstruction = .mesh
config.environmentTexturing = .manual
arView.session.run(config)
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试从新的Metal API for iOS中查看新的样本.当我下载代码时,在XCode 6 Beta中打开它我收到以下错误消息:
QuartzCore/CAMetalLayer.h file not found
Run Code Online (Sandbox Code Playgroud)
我需要添加一些其他文件还是我错过了其他的东西?Metal API应该在OSX 10.9.3中提供.
是否需要升级到Yosemite 10.10 Beta来运行这些示例?
我正在研究Swift/Cocoa/Xcode应用程序.
此应用程序包含SceneKit视图.渲染API设置为Default(我认为这是Metal).
如果我snapshot()
在这个SceneKit视图对象上运行,我收到此错误消息.我想要做的是从相机中捕获场景的UIImage
Texture PixelFormat MTLPixelFormatBGRA8Unorm does not match Resolve PixelFormat MTLPixelFormatRGBA8Unorm
Run Code Online (Sandbox Code Playgroud)
如果我将渲染API设置为OpenGL
,我没有错误,一切正常.
我在iOS应用程序上尝试过相同的东西,它适用于两种情况(Metal或OpenGL).
我不明白为什么我会收到这个错误,我应该怎么做以避免它.
这是示例代码:
import SceneKit
import Cocoa
class ViewController: NSViewController {
@IBOutlet weak var vue_scene: SCNView!
@IBOutlet weak var img_snapshot: NSImageView!
let camera_node = SCNNode()
var box_node:SCNNode = SCNNode()
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene()
vue_scene.scene = scene
vue_scene.backgroundColor = NSColor.clear
vue_scene.showsStatistics = false
vue_scene.allowsCameraControl = false
vue_scene.autoenablesDefaultLighting = true
camera_node.camera = SCNCamera()
camera_node.camera?.zNear = 0.01
camera_node.camera?.zFar = 1000000.0
vue_scene.pointOfView …
Run Code Online (Sandbox Code Playgroud) 是否有任何公开文档明确说明了CoreML's
在 macOS 上运行推理模型时 GPU 设备放置的策略?它如何决定是否应在集成、离散或 CPU 上运行?可以可靠地“强制”一条路径吗?对于像配备多个独立 GPU 和多个 eGPU 的新款 Mac Pro 这样的系统来说,这种情况有何变化?
我对 rMBP 的测试表明答案是否定的 - 温度、电池、插入电源、自动图形设置和应用程序支持,甚至可能还有一些 MLModel 架构启发式方法都在设备放置中发挥着作用。
结合上下文更长:
我很好奇是否有任何关于 CoreML 的设备选择启发式的公开文档。通过添加 10.15 的 CoreML preferredMetalDevice
API MLModelConfig
,我想可以强制MTLDevice
/ MLModel
Vision 请求运行。
在我使用 Vega 20 的 2018 rMBP 上对集成、分立和 eGPU 进行的测试中,似乎只有 eGPU 在请求时始终运行 CoreML 模型。
我的 CoreML 模型是一个管道模型,由具有多个输出的 MobileNet 分类器(附加到自定义特征提取器的多头分类器)组成。
我很想了解设备选择偏好,原因如下:
a) 我想确保我的MLModel
输入图像CIImages
由MTLTextures
本地设备推理支持,以限制 PCI 传输并继续在单个 GPU 设备上进行处理
b) 我的模型实际上是输入视频帧,WWDC '19 / 10.15 引入了 VideoToolbox 和 …
import UIKit
import Metal
import QuartzCore
class ViewController: UIViewController {
var device: MTLDevice! = nil
var metalLayer: CAMetalLayer! = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
device = MTLCreateSystemDefaultDevice()
metalLayer = CAMetalLayer() // 1
metalLayer.device = device // 2
metalLayer.pixelFormat = .BGRA8Unorm // 3
metalLayer.framebufferOnly = true // 4
metalLayer.frame = view.layer.frame // 5
view.layer.addSublayer(metalLayer) // 6
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources …
Run Code Online (Sandbox Code Playgroud) 我正在创建一个MTLTexture
来自CVImageBuffer
s(来自相机和玩家)使用CVMetalTextureCacheCreateTextureFromImage
来获得a CVMetalTexture
然后CVMetalTextureGetTexture
获得MTLTexture
.
我看到的问题是,当我稍后使用Metal渲染纹理时,我偶尔会看到无序渲染的视频帧(视觉上它在时间上来回断断续续),可能是因为CoreVideo正在修改底层CVImageBuffer
存储而且MTLTexture
只是指向那里.
有没有办法让CoreVideo不触及该缓冲区并使用其池中的另一个缓冲区直到我释放该MTLTexture
对象?
我当前的解决方法是使用a MTLBlitCommandEncoder
来对纹理进行blitting,但是因为我只需要保持纹理约30毫秒,这似乎是不必要的.
我想将一个MTLTexture
对象设置为一个场景的环境贴图,因为根据文档似乎是可能的.我可以UIImage
使用以下代码将环境贴图设置为a :
let roomImage = UIImage(named: "room")
scene.lightingEnvironment.contents = roomImage
Run Code Online (Sandbox Code Playgroud)
这很有效,我看到了金属物体上图像的反射.我尝试将图像转换为a MTLTexture
并使用以下代码将其设置为环境贴图:
let roomImage = UIImage(named: "room")
let loader = MTKTextureLoader(device: MTLCreateSystemDefaultDevice()!)
let envMap = try? loader.newTexture(cgImage: (roomImage?.cgImage)!, options: nil)
scene.lightingEnvironment.contents = envMap
Run Code Online (Sandbox Code Playgroud)
然而,这不起作用,我最终得到一个空白的环境贴图,没有反射我的对象.
另外,我没有设置options
as nil
,而是尝试MTKTextureLoader.Option.textureUsage
使用它可以获得的每个可能值来设置密钥,但这也不起作用.
编辑:您可以查看此仓库中的示例项目,并使用它来重现此用例.