J'essaie d'écrire une application de réalité augmentée à l'aide de SceneKit, et j'ai besoin de points 3D précis à partir de l'image rendue actuelle, étant donné un pixel 2D et une profondeur à l'aide de la fonction UnprojectPoint de SCNSceneRenderer méthode. Cela nécessite un x, un y et un z, où le x et le y sont des coordonnées de pixel et où le z est normalement une valeur lue dans le tampon de profondeur de cette image.
Le délégué du SCNView dispose de cette méthode pour rendre le cadre de profondeur :
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()
}
Ça marche. J'obtiens des valeurs de profondeur entre 0 et 1. Le problème est que je ne peux pas les utiliser dans l'unprojectPoint parce qu'elles ne semblent pas être mises à l'échelle de la même manière que la passe initiale, malgré l'utilisation des mêmes SCNScene et SCNCamera.
Mes questions :
-
Existe-t-il un moyen d'obtenir les valeurs de profondeur directement à partir de la passe principale de SceneKit SCNView sans avoir à effectuer une passe supplémentaire avec un SCNRenderer séparé ?
-
Pourquoi les valeurs de profondeur dans mon passage ne correspondent-elles pas aux valeurs que j'obtiens en effectuant un test d'impact puis en déprojetant ? Les valeurs de profondeur de ma passe vont de 0,78 à 0,94. Les valeurs de profondeur du test d'impact vont de 0,89 à 0,97, ce qui, curieusement, correspond aux valeurs de profondeur OpenGL de la scène lorsque je l'ai rendue en Python.
Je pense que c'est une différence entre les fenêtres d'affichage et que SceneKit fait quelque chose pour mettre à l'échelle les valeurs de profondeur de -1 à 1, tout comme OpenGL.
EDIT : Et au cas où vous vous poseriez la question, je ne peux pas utiliser directement la méthode hitTest. C'est trop lent pour ce que j'essaie de faire.