google-ar / sceneform-android-sdk

Sceneform SDK for Android
https://developers.google.com/sceneform/develop/
Apache License 2.0
1.23k stars 604 forks source link

Rendering/displaying a navigation path with renderables in ARCore? #291

Open nbazos opened 6 years ago

nbazos commented 6 years ago

I am currently developing an indoor augmented reality navigation android application and I am struggling using Google ARCore with Sceneform to create a navigation path from my current location to the destination (my question is about rendering and displaying, I already have my location necessities sorted out).

If someone could describe to me conceptually, or with code, a good starting strategy to iteratively render an arrowRenderable at different positions I would be very appreciative (for example, do I use Poses, setWorldPosition(), setLocalPosition(), etc...). I can convert (lat,long) to camera space as well so I am really looking to understand ARCore rendering better.

In regards to my implementation, I am using IndoorAtlas to handle my indoor positioning. The IndoorAtlas Android SDK comes with a wayfinding capability that creates routes from your current location to a destination (this is loaded in from a previously set wayfinding graph through IndoorAtlas online toolset). These routes are composed of legs that have a beginning and ending (lat,long) coordinates. What I am trying to do is render objects in AR iteratively along the ending (lat,long) coordinates.

Thank you in advance and please let me know if you would like additional information.

Here is an example of one implementation I tried:

public void createNavigationPath() {
        // loop through the wayfinding route
        for (IARoutingLeg leg : mCurrentRoute) {

            // current loc
            Location currentLoc = new Location("Current Location");
            currentLoc.setLatitude(mLocation.latitude);
            currentLoc.setLongitude(mLocation.latitude);

            // end of wayfinding route segment
            Location legEnd = new Location("Leg End");
            legEnd.setLatitude(leg.getEnd().getLatitude());
            legEnd.setLongitude(leg.getEnd().getLongitude());

            // conversion from (lat,long) to camera space
            // conversion implementation credit:  
            // https://github.com/dat-ng/ar-location-based-android
            float[] currentLocationInECEF = WSG84toECEF(currentLoc);
            float[] pointInECEF = WSG84toECEF(legEnd);
            float[] pointInENU = ECEFtoENU(currentLoc, currentLocationInECEF, pointInECEF);

            float[] cameraCoordinateVector = new float[4];

            Matrix.multiplyMV(cameraCoordinateVector, 0, mRotatedProjectionMatrix, 0, pointInENU, 0);

            Frame frame = arFragment.getArSceneView().getArFrame();

            // cameraCoordinateVector[2] is z, that always less than 0 to display on right position
            // if z > 0, the point will display on the opposite
            if (cameraCoordinateVector[2] < 0) {
                float x = (0.5f + cameraCoordinateVector[0] / cameraCoordinateVector[3]) * arFragment.getArSceneView().getWidth();
                float y = (0.5f - cameraCoordinateVector[1] / cameraCoordinateVector[3]) * arFragment.getArSceneView().getHeight();

                // Pose pose = new Pose(new float[]{x,y,cameraCoordinateVector[2]}, new float[]{0,0,0});

                Anchor anchor = arFragment.getArSceneView().getSession().createAnchor(frame.getCamera().getPose().compose(Pose.makeTranslation(x,y,cameraCoordinateVector[2])).extractTranslation());
                AnchorNode anchorNode = new AnchorNode(anchor);

                Node tempNode = new Node();
                tempNode.setParent(anchorNode);
                tempNode.setRenderable(arrowRenderable);

                Log.d(TAG, "Render Completed");
            }
        }
    }

In my onCreate:

 // set update listener on the AR scene for every frame
        arFragment.getArSceneView()
                .getScene()
                .addOnUpdateListener(
                        frameTime -> {
                            // check if renderables have finished loading
                            if(!hasFinishedLoading) {
                                return;
                            }

                            // check if AR is active
                            Frame frame = arFragment.getArSceneView().getArFrame();
                            if (frame == null) {
                                return;
                            }

                            if (frame.getCamera().getTrackingState() != TrackingState.TRACKING) {
                                return;
                            }

                            // check if a destination is selected and a current location is reported
                            if(IAHelper.mDestination != null && IAHelper.mLocation != null) {
                                // tell the user they have arrived at their destination when within a certain distance from the destination point
                                Location current = new Location("Current Location");
                                current.setLatitude(IAHelper.mLocation.latitude);
                                current.setLongitude(IAHelper.mLocation.longitude);
                                Location destination = new Location("Destination");
                                destination.setLatitude(IAHelper.mDestination.latitude);
                                destination.setLongitude(IAHelper.mDestination.longitude);

                                float distanceBetween = current.distanceTo(destination);

                                Log.d(geoLocTag, "distanceBetween: " + distanceBetween);

                                isClose = distanceBetween < 6;

                                Log.d(geoLocTag, "isClose: " + isClose);
                            }

                            // check if a route to the destination currently exists
                            if(IAHelper.mCurrentRoute != null) {
                                createNavigationPath();
                            }
                        });
dvsource1 commented 6 years ago

i have this problem too. when you find out a solution please notify me.. dvkaush@gmail.com i use estimote ibeacons also for my project. (my English is bad)!

stevenduan17 commented 6 years ago

@nbazos Have you got the way to render arrows?

malik-at-work commented 6 years ago

Hi thanks for this request. Probably the best way to address it would be for us to write some sort of sample doing this. We don't have that currently, but we will track the request as we consider future samples.

stevenduan17 commented 6 years ago

@malik-at-work That couldn't be better! Thanks .

nbazos commented 6 years ago

@malik-at-work Thank you, that sounds great!

strider1981 commented 5 years ago

Hi @malik-at-work any chance of getting a sample code for this? @nbazos were you able to get it working? Please let me know. Thanks

monxarat commented 4 years ago

Hi @nbazos I have the same problem, if you have completed this, could you show it to me?