Android 如何在没有ARcore碎片的平面上绘制锚之间的线

Android 如何在没有ARcore碎片的平面上绘制锚之间的线,android,arcore,Android,Arcore,我正在基于此构建我的应用程序 此应用程序将捕获用户的点击,并检查是否在场景中找到任何平面。如果是,请在该点创建一个锚点 我想在各种锚之间画一条线 我在网上找到的所有东西都使用sceneForm和arFragment 目前,我已经成功地在没有arFragment的情况下实现了sceneForm,但是这行代码没有显示出来,可能是因为 我不知道如何在没有arFragment的情况下替换这个方法:nodeToAdd.setParent(arFragment.getArSceneView().getSce

我正在基于此构建我的应用程序

此应用程序将捕获用户的点击,并检查是否在场景中找到任何平面。如果是,请在该点创建一个锚点

我想在各种锚之间画一条线

我在网上找到的所有东西都使用sceneForm和arFragment

目前,我已经成功地在没有arFragment的情况下实现了sceneForm,但是这行代码没有显示出来,可能是因为 我不知道如何在没有arFragment的情况下替换这个方法:
nodeToAdd.setParent(arFragment.getArSceneView().getScene())

为了在我的项目中实现sceneform,我从这个项目中得到了启示 有没有其他不使用sceneform的方法

这就是我的工作方式:

public void onDrawFrame(GL10 gl) {
    // Clear screen to notify driver it should not load any pixels from previous frame.
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    if (mSession == null) {
        return;
    }
    // Notify ARCore session that the view size changed so that the perspective matrix and
    // the video background can be properly adjusted.
    mDisplayRotationHelper.updateSessionIfNeeded(mSession);

    try {
        // Obtain the current frame from ARSession. When the configuration is set to
        // UpdateMode.BLOCKING (it is by default), this will throttle the rendering to the
        // camera framerate.
        Frame frame = mSession.update();
        Camera camera = frame.getCamera();

        // Handle taps. Handling only one tap per frame, as taps are usually low frequency
        // compared to frame rate.
        MotionEvent tap = queuedSingleTaps.poll();
        if (tap != null && camera.getTrackingState() == TrackingState.TRACKING) {
            for (HitResult hit : frame.hitTest(tap)) {
                // Check if any plane was hit, and if it was hit inside the plane polygon
                Trackable trackable = hit.getTrackable();
                // Creates an anchor if a plane or an oriented point was hit.
                if ((trackable instanceof Plane && ((Plane) trackable).isPoseInPolygon(hit.getHitPose()))
                        || (trackable instanceof Point
                        && ((Point) trackable).getOrientationMode()
                        == Point.OrientationMode.ESTIMATED_SURFACE_NORMAL)) {
                    // Hits are sorted by depth. Consider only closest hit on a plane or oriented point.
                    // Cap the number of objects created. This avoids overloading both the
                    // rendering system and ARCore.
                    if (anchors.size() >= 250) {
                        anchors.get(0).detach();
                        anchors.remove(0);
                    }
                    // Adding an Anchor tells ARCore that it should track this position in
                    // space. This anchor is created on the Plane to place the 3D model
                    // in the correct position relative both to the world and to the plane.
                    anchors.add(hit.createAnchor());
                    break;
                }
            }
        }

        // Draw background.
        mBackgroundRenderer.draw(frame);

        // If not tracking, don't draw 3d objects.
        if (camera.getTrackingState() == TrackingState.PAUSED) {
            return;
        }

        // Get projection matrix.
        float[] projmtx = new float[16];
        camera.getProjectionMatrix(projmtx, 0, 0.1f, 100.0f);

        // Get camera matrix and draw.
        float[] viewmtx = new float[16];
        camera.getViewMatrix(viewmtx, 0);

        // Compute lighting from average intensity of the image.
        final float lightIntensity = frame.getLightEstimate().getPixelIntensity();

        if (isShowPointCloud()) {
            // Visualize tracked points.
            PointCloud pointCloud = frame.acquirePointCloud();
            mPointCloud.update(pointCloud);
            mPointCloud.draw(viewmtx, projmtx);

            // Application is responsible for releasing the point cloud resources after
            // using it.
            pointCloud.release();
        }

        // Check if we detected at least one plane. If so, hide the loading message.
        if (mMessageSnackbar != null) {
            for (Plane plane : mSession.getAllTrackables(Plane.class)) {
                if (plane.getType() == Plane.Type.HORIZONTAL_UPWARD_FACING
                        && plane.getTrackingState() == TrackingState.TRACKING) {
                    hideLoadingMessage();
                    break;
                }
            }
        }

        if (isShowPlane()) {
            // Visualize planes.
            mPlaneRenderer.drawPlanes(
                    mSession.getAllTrackables(Plane.class), camera.getDisplayOrientedPose(), projmtx);
        }

        // Visualize anchors created by touch.
        float scaleFactor = 1.0f;

        for (Anchor anchor : anchors) {
            if (anchor.getTrackingState() != TrackingState.TRACKING) {
                continue;
            }
            // Get the current pose of an Anchor in world space. The Anchor pose is updated
            // during calls to session.update() as ARCore refines its estimate of the world.
            anchor.getPose().toMatrix(mAnchorMatrix, 0);


            // Update and draw the model and its shadow.
            mVirtualObject.updateModelMatrix(mAnchorMatrix, mScaleFactor);
            mVirtualObjectShadow.updateModelMatrix(mAnchorMatrix, scaleFactor);
            mVirtualObject.draw(viewmtx, projmtx, lightIntensity);
            mVirtualObjectShadow.draw(viewmtx, projmtx, lightIntensity);
        }

        sendARViewMessage();
    } catch (Throwable t) {
        // Avoid crashing the application due to unhandled exceptions.
        Log.e(TAG, "Exception on the OpenGL thread", t);
    }
}
然后:

这里的节点是真实存在的。我没有发现任何错误,也没有显示行:

private void drawLine(AnchorNode node1, AnchorNode node2) {
    //Here the knots exist and are real. I don't find any errors, and the lines don't show
    runOnUiThread(new Runnable() {

        @Override
        public void run() {

            Vector3 point1, point2;
            point1 = node1.getWorldPosition();
            point2 = node2.getWorldPosition();

            //First, find the vector extending between the two points and define a look rotation
            //in terms of this Vector.
            final Vector3 difference = Vector3.subtract(point1, point2);
            final Vector3 directionFromTopToBottom = difference.normalized();
            final Quaternion rotationFromAToB =
                    Quaternion.lookRotation(directionFromTopToBottom, Vector3.up());
            MaterialFactory.makeOpaqueWithColor(getApplicationContext(), new Color(0, 255, 244))
                    .thenAccept(
                            material -> {
                        /* Then, create a rectangular prism, using ShapeFactory.makeCube() and use the difference vector
                               to extend to the necessary length.  */
                                Log.d(TAG,"drawLine insie .thenAccept");
                                ModelRenderable model = ShapeFactory.makeCube(
                                        new Vector3(.01f, .01f, difference.length()),
                                        Vector3.zero(), material);
                        /* Last, set the world rotation of the node to the rotation calculated earlier and set the world position to
                               the midpoint between the given points . */
                                Anchor lineAnchor = node2.getAnchor();
                                nodeForLine = new Node();
                                nodeForLine.setParent(node1);
                                nodeForLine.setRenderable(model);
                                nodeForLine.setWorldPosition(Vector3.add(point1, point2).scaled(.5f));
                                nodeForLine.setWorldRotation(rotationFromAToB);
                            }
                    );



        }
    });


}
这是我在
drawLine()
函数中的point1、poin2和directionFromTopToBottom的示例:

point1: [x=0.060496617, y=-0.39098215, z=-0.21526277]
point2: [x=0.05695567, y=-0.39132282, z=-0.33304527]
directionFromTopToBottom: [x=0.030049745, y=0.0028910497, z=0.9995442]

您的代码没有调用
drawLineButton()
函数,是吗?无论如何,看起来您正在尝试使用Sceneform中的一些东西(MaterialFactory、ModelRenderable等),同时执行一些纯OpenGL渲染,就像在hello\u ar\u java中所做的那样

由于Sceneform使用灯丝作为渲染引擎,可以使用OpenGL或Vulkan,所以混合这些元素不会产生任何效果。因此,要么完全使用Sceneform,要么完全使用OpenGL(并了解OpenGL和Android的工作原理)


现在,如果您想继续使用hello_ar_java示例,请遵循OpenGL教程,以便能够为每个锚点生成一个顶点,并使用GL_线以您喜欢的线大小绘制它们。这里有一个很好的OpenGL教程:我建议大家学习入门部分,但请记住,这是OpenGL和Android使用OpenGL ES,虽然有一些不同,但计算机图形原理是相同的。

您编写的代码没有调用您的
drawLineButton()
函数,是吗?无论如何,看起来您正在尝试使用Sceneform中的一些东西(MaterialFactory、ModelRenderable等),同时执行一些纯OpenGL渲染,就像在hello\u ar\u java中所做的那样

由于Sceneform使用灯丝作为渲染引擎,可以使用OpenGL或Vulkan,所以混合这些元素不会产生任何效果。因此,要么完全使用Sceneform,要么完全使用OpenGL(并了解OpenGL和Android的工作原理)


现在,如果您想继续使用hello_ar_java示例,请遵循OpenGL教程,以便能够为每个锚点生成一个顶点,并使用GL_线以您喜欢的线大小绘制它们。这里有一个很好的OpenGL教程:我建议大家浏览一下入门部分,但请记住,这是OpenGL和Android使用OpenGL ES,虽然有一些不同,但计算机图形原理是相同的。

drawLineButton函数是从布局文件中单击调用的,但我也尝试了使用setOnClickListener的代码。我希望通过合并这两个系统获得成功,如果不可能,那么我将尝试使用GL_线。此时,我想尝试解决这个问题,因为我有所有必要的值,但线条不可见。但您当前的方法永远不会起作用,因为onDrawFrame()函数从未与Sceneform交互,因此它将永远不会呈现任何内容。但正如我所说的,避免使用这种方法,因为混合两种渲染机制(假设它们是单独的)并不能带来任何好处。我甚至不确定是否可以在自定义和独立的GLSurfaceView上使用Sceneform进行渲染。我不确定onDrawFrame()为什么不与Sceneform交互,但我遵循您的建议,我将尝试使用GL_行。基本上,使用hello_ar_java,您可以使用自己的GLSurfaceView和OpenGL上下文及配置。Sceneform还创建了它的OpenGL上下文+配置,它们甚至不使用GLSurfaceView,而是直接使用SurfaceView。此外,它们可能会在开始渲染时清理屏幕(与使用GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)的示例相同),因此,即使您让Sceneform在GLSurfaceView上渲染,当前也会删除上一次渲染的内容。这就是为什么我说混合使用它们不会带来任何好处。Hello@exper_1,OPENGL成功了吗?我面临着同样的问题,即无法绘制线条。单击时调用drawLineButton函数从布局文件,但我也尝试了使用setOnClickListener的代码。我希望通过合并两个系统成功,如果不可能,那么我将尝试使用GL_行。此时,我想尝试解决我所做的问题,我有所有必要的值,但行是不可见的。但您当前的方法从onDrawFram开始将永远无法工作函数从不与Sceneform交互,因此它永远不会渲染任何内容。但正如我所说的,避免使用此路径,因为混合使用假定它们是单独的两种渲染机制不会带来任何好处。我甚至不确定是否可以在自定义和独立的GLSurfaceView上使用Sceneform进行渲染。不确定为什么使用onDrawFrame()不与SceneForm交互,但我遵循您的建议,我将尝试使用GL_行。基本上,使用hello_ar_java,您有自己的GLSurfaceView和自己的OpenGL上下文和配置。SceneForm还创建其OpenGL上下文+配置,他们甚至不使用GLSurfaceView,而是直接使用SurfaceView。此外,他们可能会清理screen在开始渲染时(与使用GLES20.glClear(GLES20.GL\u COLOR\u BUFFER\u位)的示例相同),因此,即使您让Sceneform在GLSurfaceView上渲染,当前也会删除上一次渲染的内容。这就是为什么我说混合使用它们不会带来任何好处。Hello@exper_1,您使用OPENGL成功了吗?I
point1: [x=0.060496617, y=-0.39098215, z=-0.21526277]
point2: [x=0.05695567, y=-0.39132282, z=-0.33304527]
directionFromTopToBottom: [x=0.030049745, y=0.0028910497, z=0.9995442]