
Neste guia, você aprenderá como adicionar modelos 3D ao mundo real. A biblioteca ARCore do Google permite adicionar modelos 3D completos a uma imagem 2D (foto ou vídeo).
Você precisa fornecer ao sistema algum tipo de imagem de referência, que o ARCore procurará no mundo real para adicionar um modelo 3D à imagem com base nele. A realidade aumentada já é amplamente utilizada, por exemplo, em livros, jornais, revistas, etc.
Antes de mergulhar neste tutorial, você deve se familiarizar com os dois artigos anteriores sobre este tópico que apresentarão os termos básicos de RA:
O que são imagens de realidade aumentada?
De acordo com a documentação dos desenvolvedores , as imagens de realidade aumentada no ARCore permitem criar aplicativos de realidade aumentada que podem "animar" imagens 2D, como pôsteres ou embalagens de produtos.
Você faz o upload de algumas imagens de referência no ARCore e, em seguida, ele informa sobre a detecção delas durante a sessão de recuperação garantida, por exemplo, ao gravar um vídeo. E essas informações são usadas para posicionar o modelo 3D em uma imagem 2D.
Limitações do uso de imagens de realidade aumentada
Aqui estão algumas das limitações que você pode encontrar ao usar imagens de realidade aumentada:
- O ARCore pode processar apenas até 20 imagens de referência por vez.
- O plano físico no mundo real deve ser plano e sua área deve ser superior a 15 cm x 15 cm.
- O ARCore não pode rastrear imagens e objetos em movimento.
Escolhendo a imagem de referência correta
Aqui estão algumas dicas para escolher uma boa imagem de referência para o ARCore:
- Imagens de realidade aumentada suportam os formatos PNG, JPEG e JPG.
- Não importa se a imagem é colorida ou em preto e branco, o principal é que ela esteja em alto contraste.
- A resolução da imagem deve ter pelo menos 300 x 300 pixels.
- Usar imagens de alta resolução não significa desempenho aprimorado.
- Imagens com padrões repetidos (como padrões ou bolinhas) devem ser evitadas.
- Use a ferramenta arcoreimg para avaliar como sua imagem funciona. Recomenda-se uma classificação de pelo menos 75 pontos.
Como usar a ferramenta arcoreimg:
- Faça o download do SDK do ARCore para Android neste link .
- Descompacte o conteúdo do arquivo em qualquer local.
- Na pasta extraída, vá para tools> arcoreimg> windows (mesmo se você tiver Linux ou macOS).
- Abra um prompt de comando neste diretório.
- E insira este comando:
arcoreimg.exe eval-img --input_image_path=dog.png
Substitua dog.png pelo caminho completo para sua imagem.
Introdução ao aplicativo de realidade aumentada
Agora que você se familiarizou com o ARCore e selecionou uma boa imagem com uma classificação de mais de 75, é hora de começar a escrever o código do aplicativo.
Criação de fragmentos
Vamos criar um fragmento e adicioná-lo à nossa atividade. Crie uma classe chamada CustomArFragment
e herde-a do ArFragment
. Aqui está o código para CustomArFragment
:
package com.ayusch.augmentedimages; import android.util.Log; import com.google.ar.core.Config; import com.google.ar.core.Session; import com.google.ar.sceneform.ux.ArFragment; public class CustomArFragment extends ArFragment { @Override protected Config getSessionConfiguration(Session session) { getPlaneDiscoveryController().setInstructionView(null); Config config = new Config(session); config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE); session.configure(config); getArSceneView().setupSession(session); return config; } }
Antes de tudo, desligamos a detecção de avião. Ao fazer isso, removemos o ícone de mão da tela que aparece imediatamente após a inicialização do fragmento e informa ao usuário sobre a necessidade de mover seu smartphone para encontrar o avião. Não precisamos mais disso, porque não encontramos aviões aleatórios, mas uma imagem concreta.
Em seguida, configuramos o modo de atualização para a sessão LATEST_CAMERA_IMAGE
. Isso garante que seremos informados sobre atualizações de imagens sempre que o quadro da câmera for atualizado.
Configuração do banco de dados de imagens
Adicione a imagem de referência selecionada (que você deseja encontrar no mundo físico) à pasta de ativos (crie-a se ainda não estiver). Agora podemos adicionar imagens ao nosso banco de dados.
Criaremos esse banco de dados assim que o fragmento for criado. Nos logs, exibimos o resultado desta operação:
if ((((MainActivity) getActivity()).setupAugmentedImagesDb(config, session))) { Log.d("SetupAugImgDb", "Success"); } else { Log.e("SetupAugImgDb","Faliure setting up db"); }
Veja como será o CustomArFragment
:
package com.ayusch.augmentedimages; import android.util.Log; import com.google.ar.core.Config; import com.google.ar.core.Session; import com.google.ar.sceneform.ux.ArFragment; public class CustomArFragment extends ArFragment { @Override protected Config getSessionConfiguration(Session session) { getPlaneDiscoveryController().setInstructionView(null); Config config = new Config(session); config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE); session.configure(config); getArSceneView().setupSession(session); if ((((MainActivity) getActivity()).setupAugmentedImagesDb(config, session))) { Log.d("SetupAugImgDb", "Success"); } else { Log.e("SetupAugImgDb","Faliure setting up db"); } return config; } }
Em breve, adicionaremos o método MainActivity
ao MainActivity
. Agora vamos adicionar CustomArFragment
ao nosso activity_main.xml
:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <fragment android:id="@+id/sceneform_fragment" android:name="com.ayusch.augmentedimages.CustomArFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.constraint.ConstraintLayout>
Adicionando uma imagem ao banco de dados
Agora vamos configurar nosso banco de dados de imagens, encontrar a imagem de referência no mundo real e adicionar um modelo 3D à imagem.
Vamos começar configurando nosso banco de dados. Crie um método público setupAugmentedImagesDb
na classe MainActivity
:
public boolean setupAugmentedImagesDb(Config config, Session session) { AugmentedImageDatabase augmentedImageDatabase; Bitmap bitmap = loadAugmentedImage(); if (bitmap == null) { return false; } augmentedImageDatabase = new AugmentedImageDatabase(session); augmentedImageDatabase.addImage("tiger", bitmap); config.setAugmentedImageDatabase(augmentedImageDatabase); return true; } private Bitmap loadAugmentedImage() { try (InputStream is = getAssets().open("blanket.jpeg")) { return BitmapFactory.decodeStream(is); } catch (IOException e) { Log.e("ImageLoad", "IO Exception", e); } return null; }
Também criamos um método loadAugmentedImage
que carrega uma imagem de uma pasta de recursos e retorna um bitmap.
Em setupAugmentedImagesDb
primeiro inicializamos nosso banco de dados para a sessão atual e adicionamos a imagem a esse banco de dados. Nomeamos nossa imagem como tigre . Em seguida, instalamos esse banco de dados na configuração e retornamos true
, indicando que a imagem foi adicionada com sucesso.
Detecção de imagens de referência no mundo real
Agora começaremos a descobrir nossas imagens de referência no mundo real. Para fazer isso, criaremos um ouvinte que será chamado toda vez que o quadro de vídeo for atualizado, e esse quadro será analisado para a presença de uma imagem de referência no local.
Adicione esta linha ao método onCreate()
em MainActivity
:
arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame);
Agora adicione o método onUpdateFrame
a MainActivity
:
@RequiresApi(api = Build.VERSION_CODES.N) private void onUpdateFrame(FrameTime frameTime) { Frame frame = arFragment.getArSceneView().getArFrame(); Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class); for (AugmentedImage augmentedImage : augmentedImages) { if (augmentedImage.getTrackingState() == TrackingState.TRACKING) { if (augmentedImage.getName().equals("tiger") && shouldAddModel) { placeObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), Uri.parse("Mesh_BengalTiger.sfb")); shouldAddModel = false; } } } }
Na primeira linha, obtemos o próprio quadro. Um quadro pode ser imaginado como uma captura de tela regular de um vídeo. Se você conhece o funcionamento do vídeo, sabe que é apenas uma coleção de imagens que se modificam muito rapidamente, dando a impressão de algo em movimento. Acabamos de tirar uma dessas fotos.
Depois que recebemos o quadro, analisamos a presença de nossa imagem de referência. Levamos uma lista de todos os itens rastreados pelo ARCore usando frame.getUpdatedTrackables
. Em seguida, iteramos sobre ele e verificamos se nossa imagem de tigre está presente no quadro.
Se uma correspondência for encontrada, simplesmente pegamos e colocamos o modelo 3D em cima da imagem detectada.
Nota O sinalizador shouldAddModel
usado para adicionar o modelo 3D apenas uma vez.
Colocando um modelo 3D sobre uma imagem de referência
Agora que encontramos nossa imagem de referência no mundo real, podemos adicionar um modelo 3D em cima dela. Adicione os addNodeToScene
e addNodeToScene
:
placeObject
: esse método é usado para criar um objeto renderizado usando um determinado Uri
. Depois que a renderização é concluída, o objeto é passado para o método addNodeToScene
, onde o objeto é anexado ao nó e esse nó é colocado em cena.addNodeToScene
: esse método cria um nó a partir da âncora resultante, cria outro nó ao qual o objeto visualizado se une, depois adiciona esse nó ao nó âncora e o coloca no palco.
É assim que o MainActivity
parece MainActivity
:
package com.ayusch.augmentedimages; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.support.annotation.RequiresApi; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.Toast; import com.google.ar.core.Anchor; import com.google.ar.core.AugmentedImage; import com.google.ar.core.AugmentedImageDatabase; import com.google.ar.core.Config; import com.google.ar.core.Frame; import com.google.ar.core.Session; import com.google.ar.core.TrackingState; import com.google.ar.sceneform.AnchorNode; import com.google.ar.sceneform.FrameTime; import com.google.ar.sceneform.rendering.ModelRenderable; import com.google.ar.sceneform.rendering.Renderable; import com.google.ar.sceneform.ux.ArFragment; import com.google.ar.sceneform.ux.TransformableNode; import java.io.IOException; import java.io.InputStream; import java.util.Collection; public class MainActivity extends AppCompatActivity { ArFragment arFragment; boolean shouldAddModel = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); arFragment = (CustomArFragment) getSupportFragmentManager().findFragmentById(R.id.sceneform_fragment); arFragment.getPlaneDiscoveryController().hide(); arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame); } @RequiresApi(api = Build.VERSION_CODES.N) private void placeObject(ArFragment arFragment, Anchor anchor, Uri uri) { ModelRenderable.builder() .setSource(arFragment.getContext(), uri) .build() .thenAccept(modelRenderable -> addNodeToScene(arFragment, anchor, modelRenderable)) .exceptionally(throwable -> { Toast.makeText(arFragment.getContext(), "Error:" + throwable.getMessage(), Toast.LENGTH_LONG).show(); return null; } ); } @RequiresApi(api = Build.VERSION_CODES.N) private void onUpdateFrame(FrameTime frameTime) { Frame frame = arFragment.getArSceneView().getArFrame(); Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class); for (AugmentedImage augmentedImage : augmentedImages) { if (augmentedImage.getTrackingState() == TrackingState.TRACKING) { if (augmentedImage.getName().equals("tiger") && shouldAddModel) { placeObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), Uri.parse("Mesh_BengalTiger.sfb")); shouldAddModel = false; } } } } public boolean setupAugmentedImagesDb(Config config, Session session) { AugmentedImageDatabase augmentedImageDatabase; Bitmap bitmap = loadAugmentedImage(); if (bitmap == null) { return false; } augmentedImageDatabase = new AugmentedImageDatabase(session); augmentedImageDatabase.addImage("tiger", bitmap); config.setAugmentedImageDatabase(augmentedImageDatabase); return true; } private Bitmap loadAugmentedImage() { try (InputStream is = getAssets().open("blanket.jpeg")) { return BitmapFactory.decodeStream(is); } catch (IOException e) { Log.e("ImageLoad", "IO Exception", e); } return null; } private void addNodeToScene(ArFragment arFragment, Anchor anchor, Renderable renderable) { AnchorNode anchorNode = new AnchorNode(anchor); TransformableNode node = new TransformableNode(arFragment.getTransformationSystem()); node.setRenderable(renderable); node.setParent(anchorNode); arFragment.getArSceneView().getScene().addChild(anchorNode); node.select(); } }
Agora execute seu aplicativo. Você deve ver a tela como mostrado abaixo. Mova o telefone levemente acima do objeto de referência. E assim que o ARCore detecta a imagem de referência no mundo real, ela adiciona seu modelo 3D.

Leia também: Criando seu primeiro aplicativo ARCore