我要 capture
真实世界的纹理,并将其应用于借助LiDAR扫描仪生成的3D网格。我想应该使用Projection-View-Model矩阵。必须从固定的视点(例如从房间中心)制作纹理。但是,如果我们可以应用场景中以environmentTexturing
纹理收集的cube-map
数据,那将是一个理想的解决方案。
查看3D Scanner App。这是一个参考应用程序,允许我们导出带有纹理的模型。
我需要一次迭代捕获一个纹理。我不需要实时更新。我意识到改变PoV会导致错误的纹理感知,换句话说,会导致纹理变形。我还意识到RealityKit中存在动态镶嵌,并且存在自动纹理贴图(纹理的分辨率取决于其捕获的距离)。
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)
}
}
答案 0 :(得分:8)
这是一个初步的解决方案(不是最终解决方案):
import MetalKit
import ARKit
/* Color model YCbCr */
var capturedTextureChannelY: CVMetalTexture? /* Luma */
var capturedTextureChannelCbCr: CVMetalTexture? /* Chroma difference */
lazy var rgbUniforms: RGBUniforms = {
var uniforms = RGBUniforms()
uniforms.radius = rgbRadius
uniforms.viewToCamera.copy(from: viewToCamera)
uniforms.viewRatio = Float(viewportSize.width / viewportSize.height)
return uniforms
}()
func updateTextures(frame: ARFrame) {
let pixelBuffer = frame.capturedImage
guard CVPixelBufferGetPlaneCount(pixelBuffer) >= 2 else { return }
capturedTextureChannelY = makeTexture(fromPixelBuffer: pixelBuffer,
pixelFormat: .r8Unorm,
planeIndex: 0)
capturedTextureChannelCbCr = makeTexture(fromPixelBuffer: pixelBuffer,
pixelFormat: .rg8Unorm,
planeIndex: 1)
}
func makeTexture(fromPixelBuffer pixelBuffer: CVPixelBuffer,
pixelFormat: MTLPixelFormat,
planeIndex: Int) -> CVMetalTexture? {
let width = CVPixelBufferGetWidthOfPlane(pixelBuffer, planeIndex)
let height = CVPixelBufferGetHeightOfPlane(pixelBuffer, planeIndex)
var texture: CVMetalTexture? = nil
let status = CVMetalTextureCacheCreateTextureFromImage(nil,
textureCache,
pixelBuffer,
nil,
pixelFormat,
width,
height,
planeIndex,
&texture)
if status != kCVReturnSuccess {
texture = nil
}
return texture
}
func draw() {
guard let currentFrame = session.currentFrame,
let commandBuffer = commandQueue.makeCommandBuffer(),
let renderDescriptor = renderDestination.currentRenderPassDescriptor,
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderDescriptor)
else { return }
self.updateTextures(frame: currentFrame)
if rgbUniforms.radius > 0 {
var retainingTextures = [capturedTextureChannelY,
capturedTextureChannelCbCr]
commandBuffer.addCompletedHandler { buffer in
retainingTextures.removeAll()
}
renderEncoder.setFragmentTexture(CVMetalTextureGetTexture(capturedTextureChannelY!),
index: Int(kTextureY.rawValue))
renderEncoder.setFragmentTexture(CVMetalTextureGetTexture(capturedTextureChannelCbCr!),
index: Int(kTextureCbCr.rawValue))
renderEncoder.drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4)
}
}
P.S。
我在Apple Developer Forum上找到了名为LiDAR equipped for 3D modelling的帖子。它说:
问题:
Camera和LiDAR传感器可以一起工作以获得具有纹理的3D模型吗?
答案:
是的(部分)可行。您可以将锚的任何几何体投影回相机图像中,以推断出纹理。但是,这需要多个观点和某种形式的高级逻辑,才能通过投影来决定将其应用于几何的哪一部分。
Frameworks工程师
答案 1 :(得分:3)
如何在Unity中完成
我想与一些来自LiDAR的网格分享有关 Unity的AR Foundation 的有趣信息。目前-2020年11月1日-情况荒唐。这与以下事实有关:本机ARKit开发人员无法使用标准的高级RealityKit工具捕获扫描对象的纹理,但是Unity的AR Foundation用户(创建ARKit应用程序)可以使用ARMeshManager
脚本执行此操作。我不知道此脚本是由AR Foundation团队开发的,还是仅由一家小型创意创业公司的开发人员开发(然后购买),但事实仍然存在。
要将ARKit网格与AR Foundation一起使用,只需将ARMeshManager组件添加到场景中。如您在图片上看到的,这些功能包括Texture Coordinates
,Color
和Mesh Density
。
如果有人对必须如何在Unity中配置或编写脚本有更详细的信息,请在此线程中发布有关此信息。