在 ARCore 中,如何将垂直线绘制到相机中心?

4
我有一些水平面,在那里我设置了我想要绘制的线的起点。
现在我想要从起点画一条垂直线到相机的中心,也就是ArFragment。 目前我的做法如下:
// create an anchor 1 meter away of current camera position and rotation
Anchor anchor = arFragment.getArSceneView().getSession().createAnchor(
            arFragment.getArSceneView().getArFrame().getCamera().getPose()
                    .compose(Pose.makeTranslation(0, 0, -1f))
                    .extractTranslation());

// create AnchorNode with position data of Anchor
AnchorNode anchorNode = new AnchorNode(anchor);
// remove anchor to be free change position of AnchorNode
anchorNode.setAnchor(null);
// get local position of new anchor node
Vector3 newLocPos = anchorNode.getLocalPosition();

// get the local position of start node
Vector3 fromVector = fromNode.getLocalPosition();

// since we want to make vertical line, set x and z of new AnchorNode to same as start
newLocPos.x = fromVector.x;
newLocPos.z = fromVector.z;
// set updated position data to new AnchorNode
anchorNode.setLocalPosition(newLocPos);
// set scene as parent to have node in UI
anchorNode.setParent(arFragment.getArSceneView().getScene());

// draw line between Nodes
....

当我能够将智能手机垂直握住时,这个功能按预期运行。 当我旋转相机时,由于创建的锚点不再位于屏幕中央,该线不再绘制到中央。 是否有官方或更好的方法可以使竖线如预期般工作,无论我如何握住智能手机? 更新:现在我已经通过计算交点来创建了一条线。
private static MyPoint calculateIntersectionPoint(MyPoint A, MyPoint B, MyPoint C, MyPoint D) {
    // Line AB represented as a1x + b1y = c1
    double a1 = B.y - A.y;
    double b1 = A.x - B.x;
    double c1 = a1 * (A.x) + b1 * (A.y);

    // Line CD represented as a2x + b2y = c2
    double a2 = D.y - C.y;
    double b2 = C.x - D.x;
    double c2 = a2 * (C.x) + b2 * (C.y);

    double determinant = a1 * b2 - a2 * b1;

    if (determinant == 0) {
        // The lines are parallel. This is simplified
        // by returning a pair of FLT_MAX
        return new MyPoint(Double.MAX_VALUE, Double.MAX_VALUE);
    } else {
        double x = (b2 * c1 - b1 * c2) / determinant;
        double y = (a1 * c2 - a2 * c1) / determinant;
        return new MyPoint(x, y);
    }
}


MyPoint interceptionPoint = calculateIntersectionPoint(
    new MyPoint(line1From.getWorldPosition().x, line1From.getWorldPosition().y),
    new MyPoint(line1To.getWorldPosition().x, line1To.getWorldPosition().y),
    new MyPoint(line2From.getWorldPosition().x, line2From.getWorldPosition().y),
    new MyPoint(line2To.getWorldPosition().x, line2To.getWorldPosition().y));

// get local position of new anchor node
Vector3 newLocPos = anchorNode.getWorldPosition();
// since we want to make vertical line, set x and z of new AnchorNode to same as start
newLocPos.y = (float) interceptionPoint.y;
newLocPos.x = fromVector.x;
newLocPos.z = fromVector.z;

// set updated position data to new AnchorNode
anchorNode.setWorldPosition(newLocPos);

唯一的问题是该线必须恰好位于智能手机的中心位置(右侧、左侧)。

smartphone center on line

在其他情况下,该行太长或太短。

smartphone center right of line

球体显示相机的中心位置。 更新2 更多解释。

enter image description here

我们在xz-room的某个地方设置了一条竖直线的起点。
然后我们离开该线段一些距离,看着我们想要终点的位置。
现在我将问题看作是2D的,并想象我的相机起点和终点与线段在同一个xy-room中,计算出线段的终点。
问题是,我的相机视图的起点和终点具有不同的z值,与我画的线段不同。
需要找到相机视图矢量上与线段在同一个xy-room中(线段的z = 点的z)的点(及其y值)。
有人有想法吗?
1个回答

0

看起来你在其中一步中从anchorNode中移除了锚点 - 我认为这是因为你想要移动anchorNode,但我怀疑这是你问题的根源。

下面的代码将在任何两个anchorNodes之间绘制一条线,并在旋转相机时保持不变(允许设备的任何小误差或移动)。这是从这个答案中提取的 (https://dev59.com/RyP-s4cB2Jgan1znSxn-#52816504),并内置到下面链接的项目中,所以你可以检查它:

private void drawLine(AnchorNode node1, AnchorNode node2) {
      //Draw a line between two AnchorNodes (adapted from https://dev59.com/RyP-s4cB2Jgan1znSxn-#52816504)
        Log.d(TAG,"drawLine");
        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);
                        }
                );

    }

您可以在此处查看完整代码:https://github.com/mickod/LineView


该应用程序仅在平面上创建锚点,而不是在空间中创建。在平面上创建后,我可以将其垂直移动。 - anatoli
我已经更新了我的问题。我已经尝试过这个应用程序,但它并不符合我的期望。而且,这是StackOverflow。我不需要从商店下载某个应用程序,我必须在我的应用程序中实现它。 - anatoli
@anatoli - 应用程序与上面答案中和 GitHub 链接中的代码完全相同。所有源代码都可以在 GitHub 链接中找到。应用程序链接只是让您快速查看它在设备上的外观。 - Mick
我使用了这段代码,没有错误。节点存在并具有如下值:Node(com.google.ar.sceneform.AnchorNode@a8c1dff)。但是线条没有显示出来。有什么提示吗? - exper_1
@exper_1 很难进行评论,因为您自己比任何人都更了解您的代码,但完整的代码在此处,并且已经经过测试可以正常工作:github.com/mickod/LineView 这可能是由于Sceneform版本或其他插件的更改导致的问题。一个简单而快速的检查是,您的背景上是否显示了线条颜色和透明度等内容。 - Mick
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接