SceneKitを使用して拡張現実感アプリを作成しようとしていますが、SCNSceneRenderer's unprojectPointメソッドを使用して2Dピクセルとデプスが与えられていると、現在のレンダリングフレームから正確な3Dポイントが必要です。これにはx、y、zが必要です。ここで、xとyはピクセル座標で、通常zはそのフレームでデプスバッファから読み取られた値です。この作品SceneKitメタルデプスバッファ
func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
renderDepthFrame()
}
func renderDepthFrame(){
// setup our viewport
let viewport: CGRect = CGRect(x: 0, y: 0, width: Double(SettingsModel.model.width), height: Double(SettingsModel.model.height))
// depth pass descriptor
let renderPassDescriptor = MTLRenderPassDescriptor()
let depthDescriptor: MTLTextureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: MTLPixelFormat.depth32Float, width: Int(SettingsModel.model.width), height: Int(SettingsModel.model.height), mipmapped: false)
let depthTex = scnView!.device!.makeTexture(descriptor: depthDescriptor)
depthTex.label = "Depth Texture"
renderPassDescriptor.depthAttachment.texture = depthTex
renderPassDescriptor.depthAttachment.loadAction = .clear
renderPassDescriptor.depthAttachment.clearDepth = 1.0
renderPassDescriptor.depthAttachment.storeAction = .store
let commandBuffer = commandQueue.makeCommandBuffer()
scnRenderer.scene = scene
scnRenderer.pointOfView = scnView.pointOfView!
scnRenderer!.render(atTime: 0, viewport: viewport, commandBuffer: commandBuffer, passDescriptor: renderPassDescriptor)
// setup our depth buffer so the cpu can access it
let depthImageBuffer: MTLBuffer = scnView!.device!.makeBuffer(length: depthTex.width * depthTex.height*4, options: .storageModeShared)
depthImageBuffer.label = "Depth Buffer"
let blitCommandEncoder: MTLBlitCommandEncoder = commandBuffer.makeBlitCommandEncoder()
blitCommandEncoder.copy(from: renderPassDescriptor.depthAttachment.texture!, sourceSlice: 0, sourceLevel: 0, sourceOrigin: MTLOriginMake(0, 0, 0), sourceSize: MTLSizeMake(Int(SettingsModel.model.width), Int(SettingsModel.model.height), 1), to: depthImageBuffer, destinationOffset: 0, destinationBytesPerRow: 4*Int(SettingsModel.model.width), destinationBytesPerImage: 4*Int(SettingsModel.model.width)*Int(SettingsModel.model.height))
blitCommandEncoder.endEncoding()
commandBuffer.addCompletedHandler({(buffer) -> Void in
let rawPointer: UnsafeMutableRawPointer = UnsafeMutableRawPointer(mutating: depthImageBuffer.contents())
let typedPointer: UnsafeMutablePointer<Float> = rawPointer.assumingMemoryBound(to: Float.self)
self.currentMap = Array(UnsafeBufferPointer(start: typedPointer, count: Int(SettingsModel.model.width)*Int(SettingsModel.model.height)))
})
commandBuffer.commit()
}
:
SCNViewのデリゲートは、奥行きフレームをレンダリングするために、このメソッドを持っています。私は0と1の間の深さの値を取得します。問題は、同じSCNSceneとSCNCameraを使用しているにもかかわらず、最初のパスと同じ縮尺で表示されないため、unprojectPointで使用できないということです。
私の質問:
別々SCNRendererと、余分なパスを行うことなく、SceneKit SCNViewのメインパスから直接、深度値を取得する方法はありますか?
なぜ私のパスの深度の値はヒットテストをしてから投げ出しても得られない値なのですか?私のパスからの深さの値は0.78から0.94になります。ヒットテストの深度値は0.89から0.97までの範囲で、奇妙なことに、PythonでレンダリングしたときのシーンのOpenGLデプス値と一致します。
これはビューポートの違いで、SceneKitはOpenGLのように-1から1までの奥行き値をスケーリングする何かをしています。
EDIT:あなたが疑問に思っている場合は、直接hitTestメソッドを使用することはできません。私が達成しようとしているものは遅すぎます。