Jairo Barros Junior ([email protected]) é bacharel em Sistemas de Informação pela Faculdade de Alagoas e possui experiência em desenvolvimento de software. Está cursando pós-graduação em gerência de projetos. Possui certificação SCJP 6 e é instrutor da tecnologia. Atua como líder técnico no Tribunal de Justiça do Estado de Alagoas e é co-fundador da empresa Sook – Desenvolvendo Inovações, na qual atua como líder de projetos utilizando as tecnologias Java e Ruby. Realidade Aumentada Transforme o Real no Virtual Construa um simples jogo de quebracabeça utilizando jMonkey Engine e NyARToolkit. Descubra como é possível interagir o real com o virtual, por meio de objetos simples e conheça os conceitos por trás desta tecnologia. Aprenda a construir jogos interativos, trazendo de volta o interesse pelos jogos tradicionais. Saiba quais são as principais ferramentas utilizadas para tornar possível a realização da realidade aumentada e quais os projetos que estão sendo desenvolvidos com essa poderosa tecnologia. 65 "SUJHPt5SBOTGPSNFP3FBMOP7JSUVBMo3FBMJEBEF"VNFOUBEB Figura 1. Demonstração de como funciona um ambiente de realidade aumentada. realidade aumentada, do inglês augmented reality, ou simplesmente AR, é a sobreposição de objetos virtuais tridimensionais, gerados por computador, em um ambiente real, por meio de um dispositivo tecnológico. Embora pareça mágica, não é, funciona da seguinte forma: por meio de um aplicativo, a câmera fica capturando imagens e as compara utilizando técnicas de visão computacional. Se existir alguma semelhança com o cenário preestabelecido, o aplicativo exibe em tempo real uma imagem em três dimensões, sobreposta no marcador. O marcador pode ser um quadrado preto-e-branco utilizado como forma de monitoramento. A AR não é uma tecnologia nova, porém só agora está despertando interesse dos pesquisadores e da indústria. A figura 1 ilustra como se dá este processo. Estão sendo criados livros bem mais interativos, imagine uma criança lendo a história do Sítio do Picapau Amarelo, de Monteiro Lobato, e após posicionar a imagem presente no livro em frente à câmera, o aplicativo reproduz sons e exibe em três dimensões os personagens. Mas a tecnologia não está apenas limitada à utilização do papel, na medicina existe o projeto VeinViewer, onde o aparelho emite raios infravermelhos sob a pele, identificando através do calor as veias. Após a sua identificação é projetada uma imagem em tempo real sobre a pele do paciente. Este projeto está sendo utilizado no tratamento de varizes. São diversas as áreas em que é possível a aplicação da realidade aumentada, ultimamente vem se investindo bastante na área de publicidade e propaganda, por atrair a atenção de clientes. Outro projeto impressionante é o Wikitude, desenvolvido para dispositivos móveis que utilizam o sistema Android e, em breve, no iPhone, o qual segue a mesma filosofia do Wikipédia, teoricamente a sua funcionalidade é simples, após posicionar a câmera para um horizonte o aplicativo exibe informações sobre o local na tela do aparelho, baseado na localização geográfica. A É possível afirmar que com a utilização da AR o poder de interatividade do usuário com os jogos virtuais do computador é bem maior, não estamos limitados apenas ao teclado e ao mouse: agora é possível sua manipulação direta com as mãos ou através de elementos mais simples, como placas, cubos de papel ou madeira, familiares à maioria das pessoas. Existem alguns projetos que estão sendo desenvolvidos com o 66 www.mundoj.com.br objetivo de trazer de volta o desejo de jogar os jogos tradicionais, como quebra-cabeças, jogo de palavras, torre de Hanói, cubo mágico e dominó. São diversas as vantagens que esses tipos de jogos proporcionam, pois permitem uma maior facilidade de interação entre pessoas que utilizam comunicação verbal, gestos, expressões faciais e movimentos naturais para manipulação de objetos. O principal projeto que torna possível a utilização da AR é o ARToolKit (http://www.hitl.washington.edu/artoolkit/), desenvolvido em C e C++, pelo laboratório HIT (Human Interface Technology) da universidade de Washington. A última versão está compatível com os principais sistemas operacionais. Além do ARToolkit há versões para algumas linguagens de programação, como Java, ActionScript3 e C#. A AR está compatível com as tecnologias Android, iPhone e WindowsMobile. Este artigo apresenta a utilização da realidade aumentada aplicada no desenvolvimento de um jogo de quebra-cabeça utilizando o framework NyARToolkit, que é uma versão da biblioteca ARToolkit para Java, juntamente com a API de jogos jMonkey Engine – jME, open-source. Configurando o ambiente O ambiente utilizado foi WindowsXP e Eclipse com JDK 6, porém todos os aplicativos e frameworks utilizados neste artigo podem ser implementados em qualquer plataforma. Antes de tudo, é necessário que se tenha uma webcam. Para este exemplo fui utilizada a LG-Webpro. Luminosidade adequada, boa resolução da câmera e um bom processamento podem contribuir para uma melhor qualidade do aplicativo. Utilizaremos basicamente dois frameworks e suas dependências para a implementação do jogo de quebra-cabeça, são eles: NyARToolKit NyARToolkit é um framework que proporciona a interação da webcam com os marcadores, escrito 100% em Java e está sob licença GPL. Para se ter uma noção da evolução deste framework, após a con- "SUJHPt5SBOTGPSNFP3FBMOP7JSUVBMo3FBMJEBEF"VNFOUBEB Figura 2. Representação do diretório onde se encontram as dlls. clusão do exemplo deste artigo, foi lançada uma nova versão. Faça o download da última versão "NyARToolkit for Java – NyARToolkit Core-2.4.0", disponível em: http://nyatla.jp/nyartoolkit/wiki/index. php?NyARToolkit%20for%20Java.en, e importe para a sua Workspace. Para importar, abra o Eclipse File->Import->General – Existing Projects into Workspace, selecione a pasta NyARToolkit-2.4.0 e importe os projetos: NyARToolkit, NyARToolkit.utils.jmf e NyARToolkit.utils.jogl. O projeto NyARToolkit.utils.jmf e o NyARToolkit.utils.jogl necessitam da biblioteca JMF 2.1, baixe o instalador, para o Windows, disponível em: http://java.sun.com/javase/technologies/desktop/media/ jmf/2.1.1/download.html. Antes de instalar o JMF, certifique-se que a webcam já esteja conectada ao computador, pois durante a instalação é realizada uma busca dos dispositivos, essa mesma ação pode ser realizada nas preferências do aplicativo. Além dessa biblioteca o projeto NyARToolkit.utils.jogl requer a gluegen-rt.jar e jogl.jar, que podem ser encontradas na pasta “lib” do projeto jMonkey Engine. Finalmente, para que o NyARToolkit consiga utilizar todas essas bibliotecas é necessário, para o Windows, algumas dlls. Para não fugir do foco deste artigo e torná-lo mais didático, você pode baixar todas elas a partir do site da revista, lembrando que assim como elas estão disponíveis para o Windows, existem para os outros sistemas operacionais. jMonkey Engine jMonkey Engine – jME é o motor gráfico, atualmente muito utilizado no desenvolvimento de jogos, escrito totalmente em Java. Ele irá apresentar nossos objetos em 3D e tornará possível a interação com teclado e mouse, caso necessário. Faça o download da última versão jME 2.0, disponível em: http://www.jmonkeyengine.com/ Criando o projeto do jogo Com o Eclipse aberto, crie um novo projeto Java, denominado de Puzzle. Configure o Build Path, associando os projetos importados anteriormente, Project->Properties->Java Build Path, na aba Projects adicione os três projetos do NyARToolkit. Descompacte a pasta com as dlls dentro deste projeto e novamente configure o Build Path, editando o caminho do Native Library Location, da sua JRE, para a pasta das dlls, como mostra a figura 2. Após ter configurado as bibliotecas do NyARToolkit, é hora de adicionar as bibliotecas do jME ao projeto. Para isso, localize e adicione os seguintes Jars, como mostra na figura 3. No final, seu projeto deve ficar com a mesma estrutura apresentada na figura 3. Para o desenvolvimento deste jogo, é necessário criar quatro marcadores e seus arquivos-padrão, que irão representar cada peça individualmente. É necessário ainda criar quatro peças em 3D e associá-las a uma imagem, que será o objetivo final do jogo. Criando os marcadores Após ter configurado o ambiente, é necessário criar os marcadores. Um marcador é a referência que a câmera possui para que o aplicativo possa acionar a execução de alguma funcionalidade. Um marcador pode ser representado de diversas formas. Neste artigo, será representado por imagens em 2D. Para cada marcador terá uma peça do jogo associada. Crie quatro imagens simples, diferentes, preto-e-branco, com alto contraste e com bordas grossas. Na parte central da imagem, desenhe um símbolo que será interpretado pela webcam. Lembrando que quanto maior a espessura do símbolo mais fácil sua identificação. Para este artigo foram utilizadas as imagens dos marcadores apresentadas na figura 4. 67 "SUJHPt5SBOTGPSNFP3FBMOP7JSUVBMo3FBMJEBEF"VNFOUBEB Figura 3. Estrutura geral do projeto e suas dependências. Figura 4. Marcadores. 68 www.mundoj.com.br "SUJHPt5SBOTGPSNFP3FBMOP7JSUVBMo3FBMJEBEF"VNFOUBEB Figura 5. Imagem que será o objetivo do quebra-cabeça. Para facilitar o manuseio dos marcadores, é importante que eles sejam colados em uma superfície rígida, você pode colá-los em pedaços de papelão ou madeira. A classe na Listagem 2 representa o modelo das peças. Esta classe é responsável por carregar o arquivo em 3D, aplicar a sua textura e configurar o diretório onde se encontra o arquivo .pat. Para que o jogo possa interagir com os marcadores, é necessário gerar um arquivo-padrão, que possui a extensão .pat. Nele está a representação do marcador. O arquivo .pat pode ser gerado no aplicativo MakerGenerator para Adobe Air, disponível em: http://saqoosha.net/lab/FLARToolKit/MarkerGenerator/MakerGenerator.air, ou até mesmo on-line, no site: http://flash. tarotaro.org/ar/MarkerGeneratorOnline.html. Com este aplicativo, é possível gerar o arquivo .pat de duas formas: posicionando a imagem do marcador já impressa em frente à webcam ou enviando o arquivo da imagem (.jpg, .gif ou .png). Salve os arquivos gerados dentro da pasta "Data", com a extensão .pat e com os seguintes nomes: 1, 2, 3 e 4. No final, teremos quatro marcadores iguais aos da figura 4, com seus respectivos arquivos .pat. Os marcadores e os arquivos .pat podem ser baixados a partir do site da revista. Agora, iremos implementar os métodos individualmente da classe Puzzle. Para não dificultar a visualização dos próximos códigos, todos os imports necessários estão na Listagem 1. Na Listagem 3 estão sendo configurados os parâmetros que serão utilizados pelo jMonkey. Juntando as peças Após ter criado os marcadores, deve-se modelar os objetos em 3D que serão representados pelas peças. Crie quatro peças em 3D de forma que uma se encaixe nas outras. Para a construção das peças foi utilizado o Blender na versão 2.49b, que pode ser baixado em: http://www.blender.org/ Salve cada peça individualmente dentro da pasta "Data", com a extensão .3ds e com os seguintes nomes: 1, 2, 3 e 4. Escolha uma imagem que será sobreposta nas peças, na qual formará o desenho do quebra-cabeça montado, e recorte a imagem de acordo com os objetos criados em 3D. Para este artigo, iremos utilizar a figura 5. Finalmente, agora é hora de criar a classe que irá interagir com todos esses objetos. A Listagem 1 apresenta um simples exemplo de uma classe base para qualquer implementação que deseje fazer com a utilização destes frameworks. A Listagem 4 contém as configurações necessárias para a inicialização do dispositivo da webcam. Nela são adicionados os códigos dos marcadores que serão capturados pela webcam e interpretados pelo método da Listagem 7. A Listagem 5 é uma classe que faz parte do projeto NyARToolkit Java3D utilities, porém não vem incluso na API que foi baixada. Ela encontra-se sob licença do MIT. De volta à implementação da classe Puzzle, a Listagem 6 é uma das mais importantes: é nela onde ocorre o processo de captura e armazenamento do buffer gerado pela webcam que será utilizado pelo método da Listagem 7. IMPORTANTE: por questão de performance, as imagens capturadas pela webcam não terão todas as cores, porém as imagens dos modelos em 3D que serão carregados estarão normais. Na Listagem 7 é onde ocorre todo o processamento principal, o método simpleUpdate é responsável por ficar comparando as imagens capturadas pela câmera, a fim de verificar a existência de marcadores. Após a identificação dos marcadores, as peças em 3D serão “projetadas” na superfície do papel. Este método é executado quadro a quadro, deve-se ter cuidado com sua implementação, pois se ele demorar a ser executado, o aplicativo terá um baixo desempenho na visualização, tornando lenta sua exibição. 69 "SUJHPt5SBOTGPSNFP3FBMOP7JSUVBMo3FBMJEBEF"VNFOUBEB Listagem 1. Modelo da classe base do jogo. Listagem 2. Classe modelo que representa as peças. package game; package game; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URL; import com.jme.app.SimpleGame; import com.jme.bounding.BoundingSphere; import com.jme.image.Texture; import com.jme.scene.Node; import com.jme.scene.Spatial; import com.jme.scene.state.TextureState; import com.jme.system.DisplaySystem; import com.jme.util.TextureManager; import com.jme.util.export.binary.BinaryImporter; import com.jmex.model.converters.FormatConverter; import com.jmex.model.converters.MaxToJme; import com.jmex.model.converters.ObjToJme; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; import java.util.ArrayList; import javax.media.Buffer; import jp.nyatla.nyartoolkit.NyARException; import jp.nyatla.nyartoolkit.core.NyARCode; import jp.nyatla.nyartoolkit.core.param.NyARPerspectiveProjectionMatrix; import jp.nyatla.nyartoolkit.core.transmat.NyARTransMatResult; import jp.nyatla.nyartoolkit.detector.NyARDetectMarker; import jp.nyatla.nyartoolkit.jmf.utils.JmfCaptureDevice; import jp.nyatla.nyartoolkit.jmf.utils.JmfCaptureDeviceList; import jp.nyatla.nyartoolkit.jmf.utils.JmfCaptureListener; import jp.nyatla.nyartoolkit.jogl.utils.GLNyARRaster_RGB; import com.jme.app.SimpleGame; import com.jme.image.Image; import com.jme.image.Texture; import com.jme.image.Image.Format; import com.jme.light.DirectionalLight; import com.jme.light.PointLight; import com.jme.math.Matrix3f; import com.jme.math.Vector3f; import com.jme.renderer.ColorRGBA; import com.jme.scene.shape.Quad; import com.jme.scene.state.TextureState; import com.jme.util.TextureManager; public class Puzzle extends SimpleGame implements JmfCaptureListener { private static final String PARAM_FILE = Puzzle.class.getResource(“/”). getPath() + “/Data/camera_para.dat”; private static final int WIDTH = 640; private static final int HEIGHT = 480; @Override protected void simpleInitGame() { //Terá todos os parâmetros para inicialização do jogo } @Override protected void simpleUpdate() { //Será chamado por cada frame, é ele que irá desenhar as peças nos marcadores } @Override public void onUpdateBuffer(Buffer i_buffer) { //Captura o buffer gerado pela webcam para incluí-lo no ambiente do jMonkey. } } class Piece extends Node { private DisplaySystem display; public Piece(String name, DisplaySystem display) { super(name); this.display = display; this.loadModel3ds(); this.loadTexture(); this.removeFromBoard(); } public String getPatCodeFile() { return Piece.class.getClassLoader().getResource(“Data/” + getName() + “.pat”).getFile(); } //Aplica a textura correspondente a peça private void loadTexture() { TextureState ts = this.display.getRenderer().createTextureState(); ts.setEnabled(true); Texture loadTexture = TextureManager.loadTexture( Piece.class.getClassLoader().getResource(“Data/” + getName() + “.png”), Texture.MinificationFilter.BilinearNoMipMaps, Texture.MagnificationFilter.Bilinear); loadTexture.setApply(Texture.ApplyMode.Decal); ts.setTexture(loadTexture); this.setRenderState(ts); this.updateRenderState(); } //Carrega o modelo em 3D correspondente a peça private void loadModel3ds() { MaxToJme maxToJme = new MaxToJme(); ByteArrayOutputStream output = new ByteArrayOutputStream(); URL url = Piece.class.getClassLoader().getResource(“Data/” + getName() + “.3ds”); BinaryImporter binaryImporter = BinaryImporter.getInstance(); try { maxToJme.convert(url.openStream(), output); Node model3d = (Node) binaryImporter.load( new ByteArrayInputStream(output.toByteArray())); this.attachChild(model3d); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } //Altera a posição da peça, para os casos onde o marcador não foi encontrado public void removeFromBoard() { this.setLocalTranslation(0,0,-100000f); } } www.mundoj.com.br ndoj.com. j.com. j.c om.br om. 70 www.mundoj.c "SUJHPt5SBOTGPSNFP3FBMOP7JSUVBMo3FBMJEBEF"VNFOUBEB Listagem 3. Configuração dos parâmetros de inicialização. private Quad background; private TextureState textureState; private Piece piece1; private Piece piece2; private Piece piece3; private Piece piece4; private JmfCaptureDevice capture; @Override protected void simpleInitGame() { this.display.setTitle(“Puzzle”); this.display.setVSyncEnabled(true); //Desabilita a interação com teclado e mouse this.input.setEnabled(false); //Altera a posição da câmera para ficar próximo a tela this.cam.setLocation(new Vector3f(0, 0, 0)); this.cam.update(); Listagem 4. Inicializa as configurações da câmera, junto com as do NyARToolkit. private GLNyARRaster_RGB raster; private NyARDetectMarker nyArDetectMarker; private Texture textureBackground; private Image image; private void initCapture() { try { //Instância o dispositivo da webcam JmfCaptureDeviceList devlist = new JmfCaptureDeviceList(); this.capture = devlist.getDevice(0); this.capture.setCaptureFormat(Puzzle.WIDTH, Puzzle.HEIGHT, 15f); this.capture.setOnCapture(this); //Criar o quadrado que irá exibir a imagem capturada pela webcam this.background = new Quad(“Background”); this.background.updateGeometry(Puzzle.WIDTH*4, Puzzle.HEIGHT*4); this.background.setCastsShadows(false); //Configura os parâmetros do NyARToolkit this.arParam = new JmeNyARParam(); this.arParam.loadARParamFromFile(Puzzle.PARAM_FILE); this.arParam.changeScreenSize(Puzzle.WIDTH, Puzzle.HEIGHT); //Gira em 180 graus o quadrado que irá exibir a imagem capturada pela webcam Matrix3f m = new Matrix3f(); m.fromAngleAxis((float) Math.toRadians(180), new Vector3f(0, 0, 0)); this.background.setLocalRotation(m); this.raster = new GLNyARRaster_RGB(this.arParam, this.capture. getCaptureFormat()); //Habilita o quadrado de fundo para processar as imagens que serão //atribuídas ao textureState this.textureState = this.display.getRenderer().createTextureState(); this.textureState.setEnabled(true); this.background.setRenderState(this.textureState); //Adiciona o código com a lista dos marcadores a serem capturados double[] width = new double[] { 80.0, 80.0, 80.0, 80.0 }; NyARCode[] arCodes = new NyARCode[4]; arCodes[0] = new NyARCode(16, 16); arCodes[0].loadARPattFromFile(this.piece1.getPatCodeFile()); arCodes[1] = new NyARCode(16, 16); arCodes[1].loadARPattFromFile(this.piece2.getPatCodeFile()); arCodes[2] = new NyARCode(16, 16); arCodes[2].loadARPattFromFile(this.piece3.getPatCodeFile()); arCodes[3] = new NyARCode(16, 16); arCodes[3].loadARPattFromFile(this.piece4.getPatCodeFile()); this.nyArDetectMarker = new NyARDetectMarker(this.arParam, arCodes, width, arCodes.length, this.raster.getBufferReader().getBufferType()); this.nyArDetectMarker.setContinueMode(false); //Cria as peças com seus respectivos nomes this.piece1 = new Piece(“1”,display); this.piece2 = new Piece(“2”,display); this.piece3 = new Piece(“3”,display); this.piece4 = new Piece(“4”,display); //Configura o ponto de luz this.buildLighting(); //Inicializa as configuração da câmera, junto com o NyARToolkit this.initCapture(); //Adiciona as peças no cenário this.rootNode.attachChild(this.piece1); this.rootNode.attachChild(this.piece2); this.rootNode.attachChild(this.piece3); this.rootNode.attachChild(this.piece4); this.rootNode.attachChild(this.background); //Define os posicionamentos da câmera NyARPerspectiveProjectionMatrix m = arParam.getPerspectiveProjectionMatrix(); background.setLocalTranslation(new Vector3f(0, 0,(float) -m.m00 * 4)); float[] ad = arParam.getCameraFrustum(); cam.setFrustum(ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]); try { //Inicializa o dispositivo de captura this.capture.start(); } catch (Exception e) { e.printStackTrace(); } } private void buildLighting() { PointLight pl = new PointLight(); pl.setAmbient(new ColorRGBA(0.75f, 0.75f, 0.75f, 1)); pl.setDiffuse(new ColorRGBA(1, 1, 1, 1)); pl.setLocation(new Vector3f(50, 0, 0)); pl.setEnabled(true); DirectionalLight dl = new DirectionalLight(); dl.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f)); dl.setDiffuse(new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f)); dl.setDirection(new Vector3f(0, -1, 1)); dl.setEnabled(true); this.lightState.attach(pl); this.lightState.attach(dl); } //Cria a textura que receberá os dados da imagem processada BufferedImage bufferImage = new BufferedImage(Puzzle.WIDTH, Puzzle.HEIGHT, BufferedImage.TYPE_INT_RGB); this.textureBackground = TextureManager.loadTexture(bufferImage, Texture.MinificationFilter.BilinearNoMipMaps, Texture.MagnificationFilter.Bilinear, true); } catch (Exception e) { e.printStackTrace(); } } 71 "SUJHPt5SBOTGPSNFP3FBMOP7JSUVBMo3FBMJEBEF"VNFOUBEB Listagem 5. Classe de parâmetros adaptada para a utilização do jMonkey. package game; import jp.nyatla.nyartoolkit.core.param.NyARParam; import jp.nyatla.nyartoolkit.jogl.utils.NyARGLUtil; /** * NyARParam for jMonkeyEngine */ public class JmeNyARParam extends NyARParam { private float distMin = 1.0f; private float distMax = 10000.0f; private float[] projection = null; Listagem 7. Exibe os objetos em 3D. private ArrayList<Piece> piecesToRemove = new ArrayList<Piece>(); private final NyARTransMatResult displayTransMatResult = new NyARTransMatResult(); @Override protected void simpleUpdate() { if (this.image == null) { return; } try { //Adiciona as peças na lista auxiliar para poder excluir do cenário as // peças sem referência de marcador this.piecesToRemove.add(this.piece1); this.piecesToRemove.add(this.piece2); this.piecesToRemove.add(this.piece3); this.piecesToRemove.add(this.piece4); public void setViewDistanceMin(float val) { projection = null; distMin = val; } //Adiciona na textura as imagens capturadas pela webcam synchronized (this.raster) { TextureManager.deleteTextureFromCard(this.textureBackground); this.textureBackground.setImage(this.image); this.textureState.setTexture(this.textureBackground); } public void setViewDistanceMax(float val) { projection = null; distMax = val; } public float[] getCameraFrustum() { if (projection != null) { return projection; } NyARGLUtil glu = new NyARGLUtil(null); double[] ad = new double[16]; glu.toCameraFrustumRH(this, ad); //Obtém a quantidade de marcadores identificados. int foundMarkerLite = this.nyArDetectMarker.detectMarkerLite( this.raster, 110); //Compara o índice do código do marcador para que possa alterar o // posicionamento da peça, exibindo na tela. for (int i = 0; i < foundMarkerLite; i++) { if (i > 3) { continue; } if (this.nyArDetectMarker.getARCodeIndex(i) == 0) { setLocalPosition(this.piece1, i); } if (this.nyArDetectMarker.getARCodeIndex(i) == 1) { setLocalPosition(this.piece2, i); } if (this.nyArDetectMarker.getARCodeIndex(i) == 2) { setLocalPosition(this.piece3, i); } if (this.nyArDetectMarker.getARCodeIndex(i) == 3) { setLocalPosition(this.piece4, i); } } float near = distMin; float far = distMax; float left = (float) (near * (ad[8] + 1) / ad[0]); float right = (float) (near * (ad[8] - 1) / ad[0]); float top = (float) (near * (ad[9] + 1) / ad[5]); float bottom = (float) (near * (ad[9] - 1) / ad[5]); projection = new float[] { near, far, left, right, top, bottom }; return projection; } } Listagem 6. Captura e armazena o buffer gerado pela webcam. @Override public void onUpdateBuffer(Buffer iBuffer) { try { synchronized (this.raster) { this.raster.setBuffer(iBuffer); ByteBuffer byteBuffer = ByteBuffer.wrap(this.raster.getGLRgbArray()); this.image = new Image(Format.RGB8, Puzzle.WIDTH, Puzzle.HEIGHT, byteBuffer); } } catch (Exception e) { e.printStackTrace(); } } 72 www.mundoj.com.br //Remove da tela as peças que estão sem referência de marcador for (Piece piece : this.piecesToRemove) { piece.removeFromBoard(); } this.piecesToRemove.clear(); Thread.sleep(2); } catch (Exception e) { e.printStackTrace(); } } "SUJHPt5SBOTGPSNFP3FBMOP7JSUVBMo3FBMJEBEF"VNFOUBEB C ont. Listagem 7. Exibe os objetos em 3D. //Altera o posicionamento das coordenadas(X,Y e Z) da peça de acordo com //o marcador private void setLocalPosition(Piece piece, int index) throws NyARException { this.piecesToRemove.remove(piece); this.nyArDetectMarker.getTransmationMatrix(index, displayTransMatResult); setLocalRotation(piece); piece.setLocalTranslation((float) -displayTransMatResult.m03, (float) (-displayTransMatResult.m13), (float) -displayTransMatResult.m23); } //Altera o posicionamento da rotação da peça de acordo com o marcador private void setLocalRotation(Piece piece) { piece.setLocalRotation(new Matrix3f((float) -displayTransMatResult.m00, (float) -displayTransMatResult.m01, (float) displayTransMatResult.m02, (float) -displayTransMatResult.m10, (float) -displayTransMatResult.m11, (float) displayTransMatResult.m12, (float) -displayTransMatResult.m20, (float) -displayTransMatResult.m21, (float) displayTransMatResult.m22)); } Listagem 8. Executa o jogo. public static void main(String[] args) { Puzzle game = new Puzzle(); game.setConfigShowMode(ConfigShowMode.AlwaysShow); game.start(); } Pronto, aguarde uns instantes até que o aplicativo seja carregado e divirta-se. Para que o objeto virtual possa aparecer, as bordas quadradas pretas do marcador devem estar à vista pela câmera. Como pode ser observado na figura 6 a forma de jogar é muito semelhante ao modelo de quebra-cabeça clássico. Só que com esse modelo de quebra-cabeça, podemos deixar ainda mais motivador do que o modelo clássico. Pois se pode agregar novas funcionalidade, como sons e estilos visuais de vitória. Pode-se ainda criar um ambiente mais complexo, adicionando a participação de vários jogadores, contabilizar as chances que cada jogador perdeu ao posicionar uma peça errada e salvar o tempo que o jogador levou para alcançar o objetivo. É importante lembrar que com a facilidade que se tem em alterar a imagem do objetivo do jogo, esse novo modelo de quebra-cabeça torna-se ainda mais dinâmico e atraente. Apesar deste artigo não apresentar nenhuma característica do aplicativo para Web, é possível adaptar este mesmo projeto para ser executado na Internet, através de Applets. Figura 6. Exibição final. Considerações finais A interação proporcionada por esta tecnologia pode contribuir de forma significativa tanto para o entretenimento quanto no processo de ensino de aprendizagem, pois fornecem ambientes agradáveis, motivadores e são ricos com ilustrações. Neste artigo, foram apresentados os principais projetos desenvolvidos e quais as ferramentas necessárias para a construção de um jogo ou aplicativo utilizando a realidade aumentada. Além do tipo de sistema de realidade aumentada utilizado neste artigo, que é o sistema de visão por vídeo baseado em monitor, o sistema de visão ótica direta, com a utilização de óculos, vem se inserindo rapidamente, tornando ainda mais fascinante. Agradecimentos Wallisson Narciso foi responsável pelo desenvolvimento da figura 1, que ilustra como se dá o processo de integração com a realidade aumentada. Ele também mantém seus trabalhos no blog http://nanquimaoquadrado. com/blog. Edvaldo Gomes Cruz foi responsável por criar as peças do quebra-cabeça em 3D. Agradeço também a todos que sanaram minhas dúvidas no fórum do site jMonkey. Referências t t t t t t t t t "35PPM,JUoIUUQXXXIJUMXBTIJOHUPOFEVBSUPPMLJUEPDVNFOUBUJPO K.POLFZ8JLJoIUUQXXXKNPOLFZFOHJOFDPNXJLJEPLVQIQ 3FBMJEBEF7JSUVBMF"VNFOUBEBoIUUQXXXSFBMJEBEFWJSUVBMDPNCS )BOEIFME"VHNFOUFE3FBMJUZoIUUQTUVEJFSTUVCFJDHUVHSB[BDBUIBOEIFME@BSBSUPPMLJUQMVT php ;03;"- &3$"3%040 "MFYBOESF,*3/&3 $MBVEJP-".06/*&3+Á/*03 &EHBSE3FBMJEBEF Aumentada Aplicada em Jogos Educacionais. http://www.realidadeaumentada.com.br/ BSUJHPTQEG ;03;"- &3#6$$*0-* "SUIVS"VHVTUP#BTUPT,*3/&3 $MBVEJP%FTFOWPMWJNFOUPEF+PHPTFN "NCJFOUF EF 3FBMJEBEF "VNFOUBEB IUUQXXXSFBMJEBEFBVNFOUBEBDPNCSBSUJHPT pdf ;03;"- & 3 ,*3/&3 $MBVEJP $"3%040 "MFYBOESF -".06/*&3 +Á/*03 &EHBSE 7JBCJMJ[BOEP P %FTFOWPMWJNFOUP EF +PHPT &TQBDJBJT DPN 3FBMJEBEF "VNFOUBEB IUUQXXX SFBMJEBEFBVNFOUBEBDPNCSBSUJHPTQEG .&*(6*/4 #JBODIJ4FSJRVFFUBM.VMUJEJNFOTJPOBM*OGPSNBUJPO7JTVBMJ[BUJPO6TJOH"VHNFOUFE 3FBMJUZIUUQXXXTCDPSHCSCJCMJPUFDBEJHJUBMEPXOMPBEQIQ QBQFS 4"/5*/ 3BGBFM,*3/&3 $MBVEJP5ÏDOJDBTQBSB'JYBS0CKFUPT7JSUVBJTFN"NCJFOUFTEF"VUPSJB DPN3FBMJEBEF"VNFOUBEB 73