Android 如何在不点击屏幕的情况下放置对象
我正在尝试使用ARCore在屏幕上显示一个对象,而不点击屏幕。在谷歌提供的ARCore Sceneform基本示例中,您需要在屏幕检测到曲面后点击屏幕 我想实现这一点,AR显示对象而不点击屏幕Android 如何在不点击屏幕的情况下放置对象,android,arcore,Android,Arcore,我正在尝试使用ARCore在屏幕上显示一个对象,而不点击屏幕。在谷歌提供的ARCore Sceneform基本示例中,您需要在屏幕检测到曲面后点击屏幕 我想实现这一点,AR显示对象而不点击屏幕 Anchor newAnchor; for (Plane plane : mSession.getAllTrackables(Plane.class)) { if (plane.getType() == Plane.Type.HORIZONTAL_UPWARD_FACING
Anchor newAnchor;
for (Plane plane : mSession.getAllTrackables(Plane.class)) {
if (plane.getType() == Plane.Type.HORIZONTAL_UPWARD_FACING
&& plane.getTrackingState() == TrackingState.TRACKING)
{
newAnchor = plane.createAnchor(plane.getCenterPose());
break;
}
}
我试着在没有点击屏幕的情况下进行显示
如果有人知道怎么做,请帮助我。提前感谢尽管我建议您在用户点击时放置对象&他/她在屏幕上点击的位置,但您的要求可以像这样实现。(本例以Kotlin为例) 在开始放置对象之前,需要创建一个
ModelRenderable
。全局声明一个@Nullable
private var modelRenderable: ModelRenderable? = null
//Create the football renderable
ModelRenderable.builder()
//get the context of the ARFragment and pass the name of your .sfb file
.setSource(fragment.context, Uri.parse("FootBall.sfb"))
.build()
//I accepted the CompletableFuture using Async since I created my model on creation of the activity. You could simply use .thenAccept too.
//Use the returned modelRenderable and save it to a global variable of the same name
.thenAcceptAsync { modelRenderable -> this@MainActivity.modelRenderable = modelRenderable }
编程的主要部分必须在帧的onUpdate
方法上完成。因此,为帧更新附加一个侦听器,如下所示
fragment.arSceneView.scene.addOnUpdateListener(this@MainActivity) //You can do this anywhere. I do it on activity creation post inflating the fragment
现在,您可以在侦听器上添加对象
override fun onUpdate(frameTime: FrameTime?) {
//get the frame from the scene for shorthand
val frame = fragment.arSceneView.arFrame
if (frame != null) {
//get the trackables to ensure planes are detected
val var3 = frame.getUpdatedTrackables(Plane::class.java).iterator()
while(var3.hasNext()) {
val plane = var3.next() as Plane
//If a plane has been detected & is being tracked by ARCore
if (plane.trackingState == TrackingState.TRACKING) {
//Hide the plane discovery helper animation
fragment.planeDiscoveryController.hide()
//Get all added anchors to the frame
val iterableAnchor = frame.updatedAnchors.iterator()
//place the first object only if no previous anchors were added
if(!iterableAnchor.hasNext()) {
//Perform a hit test at the center of the screen to place an object without tapping
val hitTest = frame.hitTest(frame.screenCenter().x, frame.screenCenter().y)
//iterate through all hits
val hitTestIterator = hitTest.iterator()
while(hitTestIterator.hasNext()) {
val hitResult = hitTestIterator.next()
//Create an anchor at the plane hit
val modelAnchor = plane.createAnchor(hitResult.hitPose)
//Attach a node to this anchor with the scene as the parent
val anchorNode = AnchorNode(modelAnchor)
anchorNode.setParent(fragment.arSceneView.scene)
//create a new TranformableNode that will carry our object
val transformableNode = TransformableNode(fragment.transformationSystem)
transformableNode.setParent(anchorNode)
transformableNode.renderable = this@MainActivity.modelRenderable
//Alter the real world position to ensure object renders on the table top. Not somewhere inside.
transformableNode.worldPosition = Vector3(modelAnchor.pose.tx(),
modelAnchor.pose.compose(Pose.makeTranslation(0f, 0.05f, 0f)).ty(),
modelAnchor.pose.tz())
}
}
}
}
}
}
我使用了一种扩展方法
//A method to find the screen center. This is used while placing objects in the scene
private fun Frame.screenCenter(): Vector3 {
val vw = findViewById<View>(android.R.id.content)
return Vector3(vw.width / 2f, vw.height / 2f, 0f)
}
//查找屏幕中心的方法。这是在场景中放置对象时使用的
private fun Frame.screenCenter():Vector3{
val vw=findviewbyd(android.R.id.content)
返回向量3(vw.width/2f、vw.height/2f、0f)
}
这是最终的结果
如果您不想使用
点击测试
或按钮动作
方法在真实环境中放置对象,您可以使用(例如)相机姿势进行自动放置(请记住,您必须在ARCamera前面添加一个ARAnchor
、其相应的节点
和一个可渲染的
,即沿-Z
方向):
希望这能有所帮助。如果您只想放置一个对象,请看下面的代码片段。。谢谢@clinkz
override fun onUpdate(frameTime: FrameTime?) {
arFragment?.let { fragment ->
fragment.arSceneView?.let { sceneView ->
sceneView.arFrame?.let { frame ->
if (!placed) {
val trackable = frame.getUpdatedTrackables(Plane::class.java).iterator()
if (trackable.hasNext()) {
val plane = trackable.next() as Plane
if (plane.trackingState == TrackingState.TRACKING) {
fragment.planeDiscoveryController?.hide()
val hitTest =
frame.hitTest(frame.screenCenter().x, frame.screenCenter().y)
val hitTestIterator = hitTest.iterator()
if (hitTestIterator.hasNext()) {
val hitResult = hitTestIterator.next()
val modelAnchor = plane.createAnchor(hitResult.hitPose)
val anchorNode = AnchorNode(modelAnchor)
anchorNode.setParent(sceneView.scene)
val transformableNode =
TransformableNode(fragment.transformationSystem)
transformableNode.setParent(anchorNode)
transformableNode.renderable = this@ARActivity.modelRenderable
transformableNode.worldPosition = Vector3(
modelAnchor.pose.tx(),
modelAnchor.pose.compose(
Pose.makeTranslation(
0f,
0.05f,
0f
)
).ty(),
modelAnchor.pose.tz()
)
placed = true
}
}
}
}
}
}
}
}
private fun Frame.screenCenter(): Vector3 {
val vw = findViewById<View>(android.R.id.content)
return Vector3(vw.width / 2f, vw.height / 2f, 0f)
}
覆盖乐趣更新(帧时间:帧时间?){
arFragment?.let{fragment->
fragment.arSceneView?.let{sceneView->
sceneView.arFrame?让{frame->
如果(!放置){
val trackable=frame.getUpdatedTrackables(Plane::class.java).iterator()
if(trackable.hasNext()){
val plane=可跟踪。next()作为平面
if(plane.trackingState==trackingState.TRACKING){
fragment.planeDiscoveryController?.hide()
瓦尔·希特斯特=
frame.hitTest(frame.screenCenter().x,frame.screenCenter().y)
val hittestimerator=hitTest.iterator()
if(HITTestimerator.hasNext()){
val hitResult=hitTesterator.next()
val modelAnchor=plane.createAnchor(hitResult.hitPose)
val anchorNode=anchorNode(模型锚定)
anchorNode.setParent(sceneView.scene)
val可变换节点=
TransformableNode(fragment.transformationSystem)
transformableNode.setParent(anchorNode)
transformableNode.renderable=this@ARActivity.modelRenderable
transformableNode.worldPosition=Vector3(
modelAnchor.pose.tx(),
modelsanchor.pose.compose(
Pose.makeTranslation(
0f,
0.05华氏度,
0f
)
).ty(),
modelAnchor.pose.tz()
)
放置=真
}
}
}
}
}
}
}
}
private fun Frame.screenCenter():Vector3{
val vw=findviewbyd(android.R.id.content)
返回向量3(vw.width/2f、vw.height/2f、0f)
}
谢谢您的帮助,我想要GIF中显示的输出。但是您能帮我弄清楚这句话吗fragment.arSceneView.arFrame
fragment.arSceneView.arFrame
调用java方法getArFrame()
在ArSceneView
类中。它用于从摄影机提要中检索最新的帧,用于执行命中测试或其他任何操作。Java等价物为.getArSceneView().getArFrame()
我这样做只是为了展示。不再有了。OK,但当我尝试添加此fragment.arSceneView.scene.addOnUpdateListener时(this@MainActivity)
asfragment.getArSceneView().getArFrame().addOnUpdateListener(MainActivity.this)
它不起作用,我在kotlinHi@Clinkz中也尝试过这个,我尝试过你的例子,效果很好。除非多次添加3d模型(我猜每次检测平面时)。因此,我在onUpdate方法的开头添加了一个条件,以便在放置第一个模型时只调用一次。唯一的问题是,当我这样做时,屏幕上有时会出现黑色平面。我看起来是这样的:你能帮我吗?@ARGeo请不要在问题中添加不相关的标记。这与Kotlin无关,标记是su预设用于与问题相关的语言和工具,而不是已知的支持标记的平台,或者只是因为答案使用了它。标记问题,而不是答案或背景上下文OK@Zoe。我这样做是为了方便Java和Kotlin代码的可读性。@ARGeo Android标记将自动呈现添加到两者中。显式突出显示可以如果自动系统出现故障(或作为故障保护),则在代码块前面使用
(/lang java
,如果使用代码围栏,则在开头三个反勾号之后)完成
override fun onUpdate(frameTime: FrameTime?) {
arFragment?.let { fragment ->
fragment.arSceneView?.let { sceneView ->
sceneView.arFrame?.let { frame ->
if (!placed) {
val trackable = frame.getUpdatedTrackables(Plane::class.java).iterator()
if (trackable.hasNext()) {
val plane = trackable.next() as Plane
if (plane.trackingState == TrackingState.TRACKING) {
fragment.planeDiscoveryController?.hide()
val hitTest =
frame.hitTest(frame.screenCenter().x, frame.screenCenter().y)
val hitTestIterator = hitTest.iterator()
if (hitTestIterator.hasNext()) {
val hitResult = hitTestIterator.next()
val modelAnchor = plane.createAnchor(hitResult.hitPose)
val anchorNode = AnchorNode(modelAnchor)
anchorNode.setParent(sceneView.scene)
val transformableNode =
TransformableNode(fragment.transformationSystem)
transformableNode.setParent(anchorNode)
transformableNode.renderable = this@ARActivity.modelRenderable
transformableNode.worldPosition = Vector3(
modelAnchor.pose.tx(),
modelAnchor.pose.compose(
Pose.makeTranslation(
0f,
0.05f,
0f
)
).ty(),
modelAnchor.pose.tz()
)
placed = true
}
}
}
}
}
}
}
}
private fun Frame.screenCenter(): Vector3 {
val vw = findViewById<View>(android.R.id.content)
return Vector3(vw.width / 2f, vw.height / 2f, 0f)
}