Sam*_*Sam 5 android orientation kotlin arcore sceneform
我一直在努力将垂直放置的 3d 模型 GLB 格式正确放置在垂直表面上。
澄清一下,我不是指识别垂直表面的困难,这本身就是一个完全不同的问题。
删除设置的常见样板以最小化这篇文章。
我正在使用一个扩展 ARFragment 的片段。
class SceneFormARFragment: ArFragment() {
Run Code Online (Sandbox Code Playgroud)
当然,我已经提供了一些调整的配置。
override fun getSessionConfiguration(session: Session?): Config {
val config = super.getSessionConfiguration(session)
// By default we are not tracking and tracking is driven by startTracking()
config.planeFindingMode = Config.PlaneFindingMode.DISABLED
config.focusMode = Config.FocusMode.AUTO
return config
}
Run Code Online (Sandbox Code Playgroud)
为了开始和停止我的 AR 体验,我在片段中编写了几个方法,如下所示。
private fun startTracking() = viewScope.launchWhenResumed {
try {
arSceneView.session?.apply {
val changedConfig = config
changedConfig.planeFindingMode = Config.PlaneFindingMode.HORIZONTAL_AND_VERTICAL
configure(changedConfig)
}
logv("startTracking")
planeDiscoveryController.show()
arSceneView.planeRenderer.isVisible = true
arSceneView.cameraStreamRenderPriority = 7
} catch (ex: Exception) {
loge("error starting ar session: ${ex.message}")
}
}
private fun stopTracking() = viewScope.launchWhenResumed {
try {
arSceneView.session?.apply {
val changedConfig = config
changedConfig.planeFindingMode = Config.PlaneFindingMode.DISABLED
configure(changedConfig)
}
logv("stopTracking")
planeDiscoveryController.hide()
arSceneView.planeRenderer.isVisible = false
arSceneView.cameraStreamRenderPriority = 0
} catch (ex: Exception) {
loge("error stopping ar session: ${ex.message}")
}
}
Run Code Online (Sandbox Code Playgroud)
如果您想知道“启动和停止”AR 体验的原因是为了最大化此覆盖屏幕上繁重的其他 UX 交互的 GPU 周期,因此我们根据其他事物的当前实时数据状态等待启动或停止正在发生的事情。
好的继续。
让我们回顾一下 HitResult 处理:在这个方法中,我做了一些事情:
就是这样。水平放置效果很好,但垂直放置总是随机的。
OnTapArPlane 代码如下:
private fun onARSurfaceTapped() {
setOnTapArPlaneListener { hitResult, plane, _ ->
var isHorizontal = false
val renderable = when (plane.type) {
Plane.Type.HORIZONTAL_UPWARD_FACING -> {
isHorizontal = true
standmountTVRenderable
}
Plane.Type.VERTICAL -> wallmountTVRenderable
else -> {
activity?.toast("Do you want it to fall on your head really?")
return@setOnTapArPlaneListener
}
}
lastSelectedPlaneOrientation = plane.type
removeActive3DTVModel()
val anchorNode = AnchorNode(hitResult.createAnchor())
anchorNode.name = TV_ANCHOR_NAME
anchorNode.setParent(arSceneView.scene)
val tvNode = TransformableNode(this.transformationSystem)
tvNode.scaleController.isEnabled = false
tvNode.setParent(anchorNode)
tvNode.name = TV_NODE_NAME
tvNode.select()
// Set orientation towards camera
// Ref: https://github.com/google-ar/sceneform-android-sdk/issues/379
val cameraPosition = arSceneView.scene.camera.worldPosition
val tvPosition = anchorNode.worldPosition
val direction = Vector3.subtract(cameraPosition, tvPosition)
if(isHorizontal) {
tvNode.translationController.allowedPlaneTypes.clear()
tvNode.translationController.allowedPlaneTypes.add(Plane.Type.HORIZONTAL_UPWARD_FACING)
} else {
tvNode.translationController.allowedPlaneTypes.clear()
tvNode.translationController.allowedPlaneTypes.add(Plane.Type.VERTICAL)
}
val lookRotation = Quaternion.lookRotation(direction, Vector3.up())
anchorNode.worldRotation = lookRotation
tvNode.renderable = renderable
addVideoTo3DModel(renderable)
}
}
Run Code Online (Sandbox Code Playgroud)
忽略 addvideoTo3dModel 调用,因为它工作正常,我将其注释掉只是为了确保它不起作用。
我尝试过的事情。
所以我已经用尽了互联网。我剩下的就是询问社区,当然也可以向 Android 的 SceneForm 团队发送帮助,我也会这样做。
我最好的猜测是我需要做 Quaternion.axisRotation(Vector3, Float),但我猜测或尝试过的一切都没有奏效。我假设我需要使用手机的 xyz 的 worldPostion 值设置 localRotation 可能有助于识别重力。我真的只是不知道了,哈哈。
我知道 Sceneform 很新,而且文档很糟糕,而且可能因为缺少内容或文档标题而根本不存在。开发人员一定真的不希望人们使用它,但我猜:(。
我要说的最后一件事是,除了旋转的垂直放置之外,在我当前的实现中,一切都运行良好。只是为了避免在此讨论中出现兔子踪迹,我没有任何其他问题。
哦,还有我注意到的最后一条线索。电视几乎似乎围绕垂直平面的中心旋转,根据我点击的位置,底部几乎似乎指向平面的任意中心,如果这有助于任何人弄清楚的话。
哦,是的,我知道 GLB 中缺少我的纹理,我错误地打包它们并打算稍后修复它。
好吧,我终于明白了。我花了一段时间和一些认真的尝试和错误来旋转每个节点、轴、角度和旋转,然后才最终将其放置好。所以我会分享我的结果,以防其他人也需要这个。
当然,这对你如何握持手机以及它对周围环境的理解有一定的主观性,但在我所做的横向和纵向测试中,它现在总是非常接近水平,没有失败。
这就是我所学到的。
在anchorNode上设置worldRotation将有助于使用一点减法来保持3D模型面向相机视图。
val cameraPosition = arSceneView.scene.camera.worldPosition
val tvPosition = anchorNode.worldPosition
val direction = Vector3.subtract(cameraPosition, tvPosition)
val lookRotation = Quaternion.lookRotation(direction, Vector3.up())
anchorNode.worldRotation = lookRotation
Run Code Online (Sandbox Code Playgroud)
然而,这并没有解决垂直放置的方向问题。我发现如果我在外观旋转上进行 90 度的 X 旋转,它每次都会起作用。根据您的 3D 模型,它可能会有所不同,但我的锚点是中后部,所以我不确定它如何确定向上的方向。然而,我注意到每当我在 tvNode 上设置 worldRotation 时,它都会将电视置于水平位置,但会向前倾斜 90 度。经过各种轮换之后,我终于得到了答案。
val tvRotation = Quaternion.axisAngle(Vector3(1f, 0f, 0f), 90f)
tvNode.worldRotation = tvRotation
Run Code Online (Sandbox Code Playgroud)
这解决了我的问题。所以 onSurfaceTap 和放置的最终结果是这样的:
setOnTapArPlaneListener { hitResult, plane, _ ->
var isHorizontal = false
val renderable = when (plane.type) {
Plane.Type.HORIZONTAL_UPWARD_FACING -> {
isHorizontal = true
standmountTVRenderable
}
Plane.Type.VERTICAL -> wallmountTVRenderable
else -> {
activity?.toast("Do you want it to fall on your head really?")
return@setOnTapArPlaneListener
}
}
lastSelectedPlaneOrientation = plane.type
removeActive3DTVModel()
val anchorNode = AnchorNode(hitResult.createAnchor())
anchorNode.name = TV_ANCHOR_NAME
anchorNode.setParent(arSceneView.scene)
val tvNode = TransformableNode(this.transformationSystem)
tvNode.scaleController.isEnabled = false //disable scaling
tvNode.setParent(anchorNode)
tvNode.name = TV_NODE_NAME
tvNode.select()
val cameraPosition = arSceneView.scene.camera.worldPosition
val tvPosition = anchorNode.worldPosition
val direction = Vector3.subtract(cameraPosition, tvPosition)
//restrict moving node to active surface orientation
if (isHorizontal) {
tvNode.translationController.allowedPlaneTypes.clear()
tvNode.translationController.allowedPlaneTypes.add(Plane.Type.HORIZONTAL_UPWARD_FACING)
} else {
tvNode.translationController.allowedPlaneTypes.clear()
tvNode.translationController.allowedPlaneTypes.add(Plane.Type.VERTICAL)
//x 90 degree rotation to flat mount TV vertical with gravity
val tvRotation = Quaternion.axisAngle(Vector3(1f, 0f, 0f), 90f)
tvNode.worldRotation = tvRotation
}
//set anchor nodes world rotation to face the camera view and up
val lookRotation = Quaternion.lookRotation(direction, Vector3.up())
anchorNode.worldRotation = lookRotation
tvNode.renderable = renderable
viewModel.updateStateTo(AriaMainViewModel.ARFlowState.REPOSITIONING)
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,这已经在纵向和横向方面经过了相当彻底的测试,没有出现任何问题。我在使用 Sceneform 时仍然遇到其他问题,例如,即使存在有效表面,点也仅显示大约一半的时间,当然,如果墙上没有图片,当前的 SDK 无法在单色墙上进行垂直检测或者用来区分墙壁的东西。
另外,执行屏幕截图也不好,因为它不包含 3D 模型,因此需要自定义像素复制工作,而且我的屏幕截图有点慢,但至少它们可以工作,这不感谢 SDK。
所以他们还有很长的路要走,用他们的产品开辟道路是令人沮丧的,而且缺乏文档,而且肯定缺乏对客户服务以及 GitHub 记录的问题的响应,但嘿,至少我明白了,我希望这会有所帮助其他人。
快乐编码!
| 归档时间: |
|
| 查看次数: |
519 次 |
| 最近记录: |