Criando seu primeiro aplicativo ARCore

Criando seu primeiro aplicativo ARCore


Em um artigo anterior, eu já expliquei o que é o ARCore e como ele ajuda os desenvolvedores a criar aplicativos incríveis de realidade aumentada, sem a necessidade de entender matemática e OpenGL.


Se você ainda não o leu, é altamente recomendável fazer isso antes de seguir para este artigo e começar a desenvolver aplicativos ARCore.


Introdução


Para começar a desenvolver aplicativos ARCore, primeiro você precisa adicionar o suporte ARCore ao seu projeto. É muito simples, pois usaremos o Android Studio e o Sceneform SDK. Existem duas operações principais que são executadas automaticamente pelo Sceneform:


  1. Verifique o ARCore.
  2. Solicite permissão para usar a câmera.

Você não precisa se preocupar com essas duas etapas ao criar um aplicativo ARCore usando o Sceneform SDK. Você só precisa adicionar o Sceneform SDK ao seu projeto.


Crie um novo projeto do Android Studio com uma atividade vazia.


Inclua a seguinte dependência no arquivo build.gradle no nível do projeto:


 dependencies { classpath 'com.google.ar.sceneform:plugin:1.5.0' } 

E inclua esta dependência no arquivo build.gradle no nível do aplicativo:


 implementation "com.google.ar.sceneform.ux:sceneform-ux:1.5.0" 

Agora sincronize o projeto com os arquivos Gradle e aguarde até que a compilação seja concluída. Assim, o Sceneform SDK e o plugin Sceneform para Android Studio serão adicionados ao projeto. Isso permitirá que você visualize .sfb , que são modelos 3D que serão renderizados em sua câmera, além de ajudá-lo a importar, visualizar e criar recursos 3D.


Criando seu primeiro aplicativo ARCore


Agora que a instalação do Android Studio está concluída e o Sceneform SDK está instalado, podemos começar a criar nosso primeiro aplicativo ARCore.


Primeiro, precisamos adicionar um fragmento Sceneform ao nosso layout. Esta é a chamada cena em que todos os nossos modelos 3D serão colocados. O fragmento se encarregará de inicializar a câmera e processar as permissões por conta própria.


Vá para o seu arquivo de layout principal. No meu caso, este é o arquivo activity_main.xml . E adicione o fragmento Sceneform lá:


 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <fragment android:name="com.google.ar.sceneform.ux.ArFragment" android:id="@+id/ux_fragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> 

match_parent a largura e a altura do match_parent para que a cena fique em tela cheia. Você pode escolher os tamanhos de acordo com suas necessidades.


Verificação de compatibilidade


Isso é tudo o que você precisa fazer no arquivo de layout. Agora passamos para Activity, no meu caso, é MainActivity . Adicione um método à Atividade:


 public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { Log.e(TAG, "Sceneform requires Android N or later"); Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG).show(); activity.finish(); return false; } String openGlVersionString = ((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE)) .getDeviceConfigurationInfo() .getGlEsVersion(); if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) { Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later"); Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG) .show(); activity.finish(); return false; } return true; } 

Este método verifica se o seu dispositivo suporta o Sceneform SDK ou não. O SDK requer a API Android nível 27 ou superior e o OpenGL ES versão 3.0 ou superior. Se o dispositivo não suportar esses dois parâmetros, a cena não será carregada e o aplicativo exibirá uma tela em branco.


No entanto, você ainda pode implementar todas as outras funções do seu aplicativo que não exijam o Sceneform SDK.


Depois de verificar a compatibilidade, podemos criar nosso modelo 3D e anexá-lo à cena.


Adicionando ativos


Agora você precisa adicionar modelos 3D ao projeto que será exibido na sua tela. Você mesmo pode criar esses modelos se estiver familiarizado com o processo de criação deles. Ou você pode ir para Poly .


Lá você encontrará um enorme repositório de recursos 3D para escolher. Além disso, eles são gratuitos para download.


Poly


No Android Studio, abra a pasta do aplicativo no painel esquerdo. Você precisa de uma pasta de dados de amostra . Esta pasta conterá todos os seus modelos 3D. Dentro desta pasta, crie uma pasta com o nome do seu modelo.


No arquivo baixado da Poly, você provavelmente encontrará 3 arquivos:


  1. arquivo .mtl
  2. arquivo .obj
  3. arquivo .png

O mais importante desses três arquivos é o arquivo .obj . Este é o seu modelo. Coloque todos os 3 arquivos em sampledata -> "your model folder" .


O caminho para o modelo 3D


Agora clique com o botão direito do mouse no arquivo .obj . A primeira opção seria Importar ativo da forma de cena . Clique nele, não altere as configurações padrão, apenas clique em Concluir na próxima janela. Depois disso, sincronize o projeto com os arquivos Gradle.


A importação do recurso 3D que será usado no seu projeto está concluída. Em seguida, vamos usar o modelo 3D em nosso código e incluí-lo na cena.


Criação de modelo


Adicione o seguinte código à sua atividade e eu explicarei linha por linha:


 private static final String TAG = MainActivity.class.getSimpleName(); private static final double MIN_OPENGL_VERSION = 3.0; ArFragment arFragment; ModelRenderable lampPostRenderable; @Override @SuppressWarnings({"AndroidApiChecker", "FutureReturnValueIgnored"}) protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!checkIsSupportedDeviceOrFinish(this)) { return; } setContentView(R.layout.activity_main); arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment); ModelRenderable.builder() .setSource(this, Uri.parse("LampPost.sfb")) .build() .thenAccept(renderable -> lampPostRenderable = renderable) .exceptionally(throwable -> { Toast toast = Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return null; }); } 

Primeiro, encontramos o arFragment , que adicionamos anteriormente ao layout. Esse fragmento é responsável pelo armazenamento e operação da cena. Você pode imaginar isso como um recipiente para a nossa cena.


Em seguida, usamos a classe ModelRenderable para criar nosso modelo. Usando o método setSource carregamos nosso modelo a partir do arquivo .sfb que foi gerado quando os recursos foram importados. O método thenAccept obtém o modelo após a criação e definimos o modelo carregado como nossa variável lampPostRenderable .


Para tratamento de erros, temos um método exceptionally , chamado se ocorrer uma exceção.


Tudo isso acontece de forma assíncrona, para que você não precise se preocupar com multithreading.


Agora que o modelo está carregado e salvo na variável lampPostRenderable , vamos adicioná-lo à nossa cena.


Adicionando um modelo à cena


Nossa cena está em arFragment e receberá eventos de toque do usuário. Portanto, precisamos instalar um ouvinte onTap para o nosso fragmento para processar toques e colocar objetos onde for necessário. Adicione o seguinte código ao método onCreate :


 arFragment.setOnTapArPlaneListener( (HitResult hitresult, Plane plane, MotionEvent motionevent) -> { if (lampPostRenderable == null){ return; } Anchor anchor = hitresult.createAnchor(); AnchorNode anchorNode = new AnchorNode(anchor); anchorNode.setParent(arFragment.getArSceneView().getScene()); TransformableNode lamp = new TransformableNode(arFragment.getTransformationSystem()); lamp.setParent(anchorNode); lamp.setRenderable(lampPostRenderable); lamp.select(); } ); 

Definimos o ouvinte onTapArPlaneListener para o nosso fragmento de AR. A sintaxe a seguir é usada para expressões lambda. Se você não estiver familiarizado com isso, consulte este pequeno guia sobre este tópico.


Primeiro, criamos uma âncora a partir do HitResult usando hitresult.createAnchor() e a salvamos no objeto Anchor .


Em seguida, criamos um nó a partir dessa âncora. Ele será chamado AnchorNode e será anexado à cena usando o método setParent .


Em seguida, criamos um TransformableNode , que será nosso modelo, e o vinculamos ao nosso nó. TransformableNode ainda não possui nenhuma informação sobre o objeto que ele deve exibir. Passaremos esse objeto para ele usando o método setRenderable , que usa como parâmetro um objeto do tipo ModelRenderable (lembre-se, obtivemos esse objeto e o lampPostRenderable ?). E, finalmente, chamamos o método lamp.select() ;


Ooh! Muita terminologia. Não se preocupe, vou explicar tudo agora:


  1. Cena : este é o local onde todos os seus objetos 3D serão exibidos. Essa cena está localizada no fragmento de AR que adicionamos ao layout.


  2. HitResult : trata-se de uma linha imaginária (ou raio) vinda do infinito, que fornece o ponto de interseção de si mesmo com um objeto do mundo real.


  3. Âncora : Este é um local e orientação fixos no mundo real. Pode ser entendida como as coordenadas (x, y, z) no espaço tridimensional. Pose é a posição e orientação de um objeto no palco. É usado para converter o espaço de coordenadas local de um objeto em um espaço de coordenadas real.


  4. Nó âncora : este é um nó que se posiciona automaticamente no mundo real. Este é o primeiro nó que é instalado quando um plano é detectado.


  5. TransformableNode : este é o nó com o qual você pode interagir. Pode ser movido, dimensionado, girado e assim por diante. Neste exemplo, podemos escalar nosso objeto e girá-lo. Daí o nome Transformable.



Não há ciência de foguetes. É realmente relativamente simples. A cena inteira pode ser visualizada na forma de um gráfico no qual o pai é a cena e os filhos são nós âncoras, que depois se ramificam em vários outros nós e objetos que serão exibidos na tela.


Como resultado, sua Atividade deve ficar assim:


 package com.ayusch.arcorefirst; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.net.Uri; import android.os.Build; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.widget.Toast; import com.google.ar.core.Anchor; import com.google.ar.core.HitResult; import com.google.ar.core.Plane; import com.google.ar.sceneform.AnchorNode; import com.google.ar.sceneform.rendering.ModelRenderable; import com.google.ar.sceneform.ux.ArFragment; import com.google.ar.sceneform.ux.TransformableNode; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private static final double MIN_OPENGL_VERSION = 3.0; ArFragment arFragment; ModelRenderable lampPostRenderable; @Override @SuppressWarnings({"AndroidApiChecker", "FutureReturnValueIgnored"}) protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (!checkIsSupportedDeviceOrFinish(this)) { return; } setContentView(R.layout.activity_main); arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment); ModelRenderable.builder() .setSource(this, Uri.parse("LampPost.sfb")) .build() .thenAccept(renderable -> lampPostRenderable = renderable) .exceptionally(throwable -> { Toast toast = Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return null; }); arFragment.setOnTapArPlaneListener( (HitResult hitresult, Plane plane, MotionEvent motionevent) -> { if (lampPostRenderable == null){ return; } Anchor anchor = hitresult.createAnchor(); AnchorNode anchorNode = new AnchorNode(anchor); anchorNode.setParent(arFragment.getArSceneView().getScene()); TransformableNode lamp = new TransformableNode(arFragment.getTransformationSystem()); lamp.setParent(anchorNode); lamp.setRenderable(lampPostRenderable); lamp.select(); } ); } public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { Log.e(TAG, "Sceneform requires Android N or later"); Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG).show(); activity.finish(); return false; } String openGlVersionString = ((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE)) .getDeviceConfigurationInfo() .getGlEsVersion(); if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) { Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later"); Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG) .show(); activity.finish(); return false; } return true; } } 

Parabéns! Você acabou de concluir a criação do seu primeiro aplicativo ARCore. Comece adicionando objetos a ele e você verá como eles começam a ganhar vida no mundo real.


Esta foi sua primeira olhada em como criar um aplicativo ARCore simples do zero no Android Studio. Na próxima lição, aprofundarei o ARCore e adicionarei mais funcionalidades ao aplicativo.

Source: https://habr.com/ru/post/pt438178/


All Articles