Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class AR_Activity extends AppCompatActivity implements GLSurfaceView.Renderer {
- private static final String TAG = AR_Activity.class.getSimpleName();
- // Rendering. The Renderers are created here, and initialized when the GL surface is created.
- private GLSurfaceView surfaceView;
- private final SBH messageSnackbarHelper = new SBH();
- private DRH displayRotationHelper;
- private final TSH trackingStateHelper = new TSH(this);
- private TH tapHelper;
- private final BGRenderer backgroundRenderer = new BGRenderer();
- private final OBJRenderer virtualObject = new OBJRenderer();
- //private final OBJRenderer virtualObjectShadow = new OBJRenderer();
- private final PlaneRenderer planeRenderer = new PlaneRenderer();
- private final PCRenderer pointCloudRenderer = new PCRenderer();
- // Temporary matrix allocated here to reduce number of allocations for each frame.
- private final float[] anchorMatrix = new float[16];
- //private static final float[] DEFAULT_COLOR = new float[] {0f, 0f, 0f, 0f};
- private static final String SEARCHING_PLANE_MESSAGE = "Searching for surfaces...";
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- FSH.setFullScreenOnWindowFocusChanged(this, hasFocus);
- }
- @Override
- public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
- GLES20.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
- // Prepare the rendering objects. This involves reading shaders, so may throw an IOException.
- try {
- // Create the texture and pass it to ARCore session to be filled during update().
- backgroundRenderer.createOnGlThread(/*context=*/ this);
- planeRenderer.createOnGlThread(/*context=*/ this, "models/trigrid.png");
- pointCloudRenderer.createOnGlThread(/*context=*/ this);
- virtualObject.createOnGlThread(/*context=*/ this, "models/andy.obj", "models/andy.png");
- virtualObject.setMaterialProperties(0.0f, 2.0f, 0.5f, 6.0f);
- //virtualObjectShadow.createOnGlThread(
- // /*context=*/ this, "models/andy_shadow.obj", "models/andy_shadow.png");
- //virtualObjectShadow.setBlendMode(OBJRenderer.BlendMode.Shadow);
- //virtualObjectShadow.setMaterialProperties(1.0f, 0.0f, 0.0f, 1.0f);
- } catch (IOException e) {
- Log.e(TAG, "Failed to read an asset file", e);
- }
- }
- @Override
- public void onSurfaceChanged(GL10 gl10, int width, int height) {
- displayRotationHelper.onSurfaceChanged(width, height);
- GLES20.glViewport(0, 0, width, height);
- }
- @Override
- public void onDrawFrame(GL10 gl10) {
- // 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 (arSession == null) {
- return;
- }
- // Notify ARCore session that the view size changed so that the perspective matrix and
- // the video background can be properly adjusted.
- displayRotationHelper.updateSessionIfNeeded(arSession);
- try {
- arSession.setCameraTextureName(backgroundRenderer.getTextureId());
- // 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 frame rate.
- Frame frame = arSession.update();
- Camera camera = frame.getCamera();
- // Handle one tap per frame.
- handleTap(frame, camera);
- // If frame is ready, render camera preview image to the GL surface.
- backgroundRenderer.draw(frame);
- // Keep the screen unlocked while tracking, but allow it to lock when tracking stops.
- trackingStateHelper.updateKeepScreenOnFlag(camera.getTrackingState());
- // If not tracking, don't draw 3D objects, show tracking failure reason instead.
- if (camera.getTrackingState() == TrackingState.PAUSED) {
- messageSnackbarHelper.showMessage(
- this, TSH.getTrackingFailureReasonString(camera));
- 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.
- // The first three components are color scaling factors.
- // The last one is the average pixel intensity in gamma space.
- final float[] colorCorrectionRgba = new float[4];
- frame.getLightEstimate().getColorCorrection(colorCorrectionRgba, 0);
- // Visualize tracked points.
- // Use try-with-resources to automatically release the point cloud.
- try (PointCloud pointCloud = frame.acquirePointCloud()) {
- pointCloudRenderer.update(pointCloud);
- pointCloudRenderer.draw(viewmtx, projmtx);
- }
- // No tracking error at this point. If we detected any plane, then hide the
- // message UI, otherwise show searchingPlane message.
- if (hasTrackingPlane()) {
- messageSnackbarHelper.hide(this);
- } else {
- messageSnackbarHelper.showMessage(this, SEARCHING_PLANE_MESSAGE);
- }
- // Visualize planes.
- planeRenderer.drawPlanes(
- arSession.getAllTrackables(Plane.class), camera.getDisplayOrientedPose(), projmtx);
- // Visualize anchors created by touch.
- float scaleFactor = 1.0f;
- for (ColoredAnchor coloredAnchor : anchors) {
- if (coloredAnchor.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.
- coloredAnchor.anchor.getPose().toMatrix(anchorMatrix, 0);
- // Update and draw the model and its shadow.
- virtualObject.updateModelMatrix(anchorMatrix, scaleFactor);
- //virtualObjectShadow.updateModelMatrix(anchorMatrix, scaleFactor);
- virtualObject.draw(viewmtx, projmtx, colorCorrectionRgba, coloredAnchor.color);
- //virtualObjectShadow.draw(viewmtx, projmtx, colorCorrectionRgba, coloredAnchor.color);
- }
- } catch (Throwable t) {
- // Avoid crashing the application due to unhandled exceptions.
- Log.e(TAG, "Exception on the OpenGL thread", t);
- }
- }
- // Handle only one tap per frame, as taps are usually low frequency compared to frame rate.
- private void handleTap(Frame frame, Camera camera) {
- MotionEvent tap = tapHelper.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())
- && (PlaneRenderer.calculateDistanceToPlane(hit.getHitPose(), camera.getPose()) > 0))
- || (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() >= 20) {
- anchors.get(0).anchor.detach();
- anchors.remove(0);
- }
- // Assign a color to the object for rendering based on the trackable type
- // this anchor attached to. For AR_TRACKABLE_POINT, it's blue color, and
- // for AR_TRACKABLE_PLANE, it's green color.
- float[] objColor;
- if (trackable instanceof Point) {
- objColor = new float[] {66.0f, 133.0f, 244.0f, 255.0f};
- } else {
- objColor = new float[] {139.0f, 195.0f, 74.0f, 255.0f};
- }
- // 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(new ColoredAnchor(hit.createAnchor(), objColor));
- break;
- }
- }
- }
- }
- private boolean hasTrackingPlane() {
- for (Plane plane : arSession.getAllTrackables(Plane.class)) {
- if (plane.getTrackingState() == TrackingState.TRACKING) {
- return true;
- }
- }
- return false;
- }
- // Anchors created from taps used for object placing with a given color.
- private static class ColoredAnchor {
- final Anchor anchor;
- final float[] color;
- ColoredAnchor(Anchor a, float[] color4f) {
- this.anchor = a;
- this.color = color4f;
- }
- }
- private final ArrayList<ColoredAnchor> anchors = new ArrayList<>();
- private Session arSession;
- private boolean RequestedInstall = true;
- @SuppressLint("ClickableViewAccessibility")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_ar_view);
- surfaceView = findViewById(R.id.surface_view);
- displayRotationHelper = new DRH(/*context=*/ this);
- // Set up tap listener.
- tapHelper = new TH(/*context=*/ this);
- surfaceView.setOnTouchListener(tapHelper);
- // Set up renderer.
- surfaceView.setPreserveEGLContextOnPause(true);
- surfaceView.setEGLContextClientVersion(2);
- surfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); // Alpha used for plane blending.
- surfaceView.setRenderer(this);
- surfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
- surfaceView.setWillNotDraw(false);
- }
- @Override
- protected void onResume() {
- super.onResume();
- if (CPH.hasCameraPermission(this)) {
- CPH.requestCameraPermission(this);
- return;
- }
- // Make sure Google Play Services for AR is installed and up to date.
- try {
- if (arSession == null) {
- switch (ArCoreApk.getInstance().requestInstall(this, RequestedInstall)) {
- case INSTALLED:
- // Success, create the AR session.
- arSession = new Session(this);
- break;
- case INSTALL_REQUESTED:
- // Ensures next invocation of requestInstall() will either return
- // INSTALLED or throw an exception.
- RequestedInstall = false;
- }
- }
- } catch (UnavailableUserDeclinedInstallationException e) {
- // Display an appropriate message to the user and return gracefully.
- Toast.makeText(this, "TODO: handle exception " + e, Toast.LENGTH_LONG)
- .show();
- } catch (Exception ex) {
- // Current catch statements.
- // mSession is still null.
- }
- try {
- if (arSession != null) {
- arSession.resume();
- }
- } catch (CameraNotAvailableException e) {
- // In some cases (such as another camera app launching) the camera may be given to
- // a different app instead. Handle this properly by showing a message and recreate the
- // session at the next iteration.
- messageSnackbarHelper.showError(this, "Camera not available. Please restart the app.");
- arSession = null;
- return;
- }
- surfaceView.onResume();
- displayRotationHelper.onResume();
- }
- @Override
- public void onPause() {
- super.onPause();
- if (arSession != null) {
- // Note that the order matters - GLSurfaceView is paused first so that it does not try
- // to query the session. If Session is paused before GLSurfaceView, GLSurfaceView may
- // still call session.update() and get a SessionPausedException.
- displayRotationHelper.onPause();
- surfaceView.onPause();
- arSession.pause();
- }
- }
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (CPH.hasCameraPermission(this)) {
- Toast.makeText(this, "Camera permission is needed to run this application", Toast.LENGTH_LONG)
- .show();
- if (!CPH.shouldShowRequestPermissionRationale(this)) {
- // Permission denied with checking "Do not ask again".
- CPH.launchPermissionSettings(this);
- }
- finish();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement