Introdução ao Ogre3D
Maylson Gonçalves @maylson
Outubro/2010 Belém, Pará
Índice de Figuras Figura 1 - Download do OGRE SDK ................................................................................... 7 Figura 2 - Diretório para onde será extraído o OGRE SDK ............................................... 8 Figura 3 - Andamento da extração do OGRE SDK ............................................................ 8 Figura 4 - Conteúdo do diretório de instalação do OGRE SDK ......................................... 9 Figura 5 - Criação da variável de ambiente do OGRE ....................................................... 9 Figura 6 - Lista de variáveis de ambiente, com a nova variável criada .......................... 10 Figura 7 - Exemplos do OGRE SDK .................................................................................. 13 Figura 8 - Erro ao compilar o SampleBrowser ................................................................ 14 Figura 9 - Solução do erro no Pre-Link Event.................................................................. 14 Figura 10 - Janela de configuração do Ogre3D ............................................................... 15 Figura 11 - Screenshot do SampleBrowser ..................................................................... 16 Figura 12 - Criação de um novo projeto ......................................................................... 17 Figura 13 - Adicionando um arquivo ao projeto ............................................................ 18 Figura 14 - Criando o arquivo Main.cpp na subpasta Source......................................... 18 Figura 15 - Configuração da guia General em modo Release ........................................ 19 Figura 16 - Configuração da guia C/C++ >>> General ..................................................... 20 Figura 17 - Configuração da guia Linker >>> General..................................................... 21 Figura 18 - Configuração da guia Linker >>> Input ......................................................... 21
2
Sumário Índice de Figuras ............................................................................................................... 2 Introdução ao Ogre3D ...................................................................................................... 5 Pré-requisitos ................................................................................................................ 5 Plataformas ................................................................................................................... 6 Instalação do Ambiente de Desenvolvimento ................................................................. 7 Estrutura de Diretórios do OGRE SDK ......................................................................... 10 bin ........................................................................................................................... 10 Docs ........................................................................................................................ 11 include .................................................................................................................... 11 lib ............................................................................................................................ 11 Samples................................................................................................................... 12 media ...................................................................................................................... 12 Compilando os Exemplos do OGRE............................................................................. 12 Criando um Projeto no VC++ ...................................................................................... 16 Inicialização do OGRE ..................................................................................................... 23 Root ........................................................................................................................ 23 plugins.cfg ............................................................................................................... 23 ogre.cfg ................................................................................................................... 24 Ogre.log .................................................................................................................. 26 Render Window ...................................................................................................... 26 Scene Manager ....................................................................................................... 27 Render Loop............................................................................................................ 29 Frame Listener ........................................................................................................ 30 Main Rendering Loop ............................................................................................. 31 Gerenciamento dos Recursos de Media ........................................................................ 33 Gerenciamento de Recursos na Prática ................................................................. 33 Localização dos Recursos........................................................................................ 34 Inicialização dos Recursos ...................................................................................... 35 Descarregamento de Recursos ............................................................................... 36 Dispositivos de Entrada .................................................................................................. 37 3
Biblioteca de Input.................................................................................................. 37 Input Manager e Input Listener .............................................................................. 37 Materials ......................................................................................................................... 43 Scene Management ........................................................................................................ 43 Ferramentas de Produtividade ....................................................................................... 43 Animação ........................................................................................................................ 43 GUI com SdkTrays ........................................................................................................... 43 Estudo de Caso ............................................................................................................... 43 Hot tips ........................................................................................................................... 44 Dúvidas comuns.............................................................................................................. 44 Exportação com o Blender ............................................................................................. 44
4
Introdução ao Ogre3D OGRE (Object Oriented Graphics Rendering Engine) é um motor de renderização gráfica em tempo real, multiplataforma, escrito em C++ e de código aberto, construído para abstrair as especificidades das APIs (Application Interface Programming) de renderização gráfica de baixo nível, como o DirectX e o OpenGL. O OGRE é mantido por um pequeno grupo de desenvolvedores que trabalham no núcleo do motor, mas que também recebe contribuições de diversos usuários. O OGRE também pode ser utilizado em outras linguagens de programação, como Java, C# e Python, através de wrappers construídos pela comunidade, ou seja, não suportados oficialmente pela equipe de desenvolvimento do OGRE, estando em diversos graus de estabilidade e completude em relação ao OGRE oficial. Um erro comum relacionado ao OGRE é devido a sua qualidade como Motor de Jogos ou Game Engine. O OGRE não é, nem nunca teve a pretensão de ser uma plataforma de desenvolvimento de jogos completa, sendo, ao invés disso, apenas uma plataforma de renderização gráfica, podendo ser utilizada em diversas aplicações de computação gráfica, inclusive games. Uma pergunta comum nos fóruns do OGRE é: “Como eu rodo o OGRE?”. Bem, você não roda. OGRE não é um programa. Não existe um executável do OGRE. O OGRE é um SDK (Software Development Kit), o que significa que deve ser utilizado para desenvolver software.
Pré-requisitos Este curso é destinado à iniciantes em Ogre3D e em computação gráfica em geral, interessados em utilizar gráficos 3D acelerados por hardware em seus games e/ou aplicações. Apesar de ser um curso para iniciantes, alguns pré-requisitos devem ser cumpridos, como por exemplo, ser familiar com ISO Standard C++ e C++ STL, uma vez que este curso utilizará a API em C++ nativa do OGRE, e todos os códigos e exemplos estarão implementados em C++. Por exemplo, se você não entender o código abaixo:
for (std::vector::iterator it = m_myVec.begin(); it != m_MyVec.end(); it++) { //Loop code here; }
5
então você deve revisitar seus conceitos básicos de C++, pois iterar através de um container STL é uma tarefa comum em programas C++, de modo que você terá uma aprendizado mais confortável se entender o básico. Além disso, é necessário possuir uma cópia e se sentir hábil para utilizar o Microsoft Visual C++ .Net 2008 SP1. É necessário também que os drivers mais atuais da placa de vídeo do computador de desenvolvimento estejam instalados e funcionando corretamente.
Plataformas O desenvolvimento original do OGRE foi feito em Windows 32-bit. Esta ainda é a principal plataforma de desenvolvimento para o OGRE, embora isso não signifique que outras plataformas são desconsideradas. O time de desenvolvedores do OGRE tem um responsável exclusivo para tratar da compatibilidade do OGRE com o Linux. Assim como existe um encarregado exclusivo para Mac OS X, outro para iPhone/iPod etc. Todas essas plataformas são igualmente suportadas a partir da mesma base de código. Como OGRE tem suporte nativo ao OpenGL, é possível utilizar o OGRE em qualquer plataforma na qual exista suporte aceleração por hardware em OpenGL, como o Solaris da Sun. Entretanto, o núcleo de desenvolvedores do OGRE não suporta diretamente plataforma não-Linux/UNIX, sendo qualquer “port” desta natureza apenas esforço da comunidade.
6
Instalação do Ambiente de Desenvolvimento Para ter um ambiente de desenvolvimento funcional, você precisa ter o OGRE SDK e uma IDE (Integrated Development Environment). Neste curso usaremos o Visual C++ .Net 2008 SP1. O método mais simples de obter esse ambiente é seguindo os passos abaixo. 1. Fazer o download do OGRE SDK correto, de acordo com a IDE a ser utilizada; 2. Configurar sua IDE com os caminhos corretos para o OGRE SDK; 3. Compilar os exemplos do OGRE, garantindo que seu ambiente configurado. Para efetuar o download do instalador do OGRE SDK, acesse a página de downloads do OGRE: http://www.ogre3d.org/download/sdk. Escolha o OGRE 1.7.2 SDK for Visual C++ .Net 2008 (32-bit).
Figura 1 - Download do OGRE SDK
7
Ao executar o instalador, será necessário informar o caminho para onde o SDK será extraído. Indique o caminho do diretório raiz do Windows, C:\.
Figura 2 - Diretório para onde será extraído o OGRE SDK
Acompanhe o andamento da extração e fique atento para quaisquer erros no processo, que podem surgir por problemas de permissão de escrita no diretório, por exemplo.
Figura 3 - Andamento da extração do OGRE SDK
Após o final da operação de extração, o seu diretório do OGRE SDK estará como na Figura 4.
8
Figura 4 - Conteúdo do diretório de instalação do OGRE SDK
Agora é preciso criar uma variável de ambiente que faça referência ao diretório do OGRE SDK. Vá ao Painel de Controle >>> Sistema >>> Configurações Avançadas do Sistema >>> Propriedades do Sistema. Clique no botão “Variáveis de Ambiente...”. Na janela que abrir, clique no botão “Novo”. Por fins de padronização, nomeie a variável de ambiente como OGRE_HOME, indicando o diretório do OGRE SDK no campo Valor da Variável. Clique em OK, e pronto. A nova variável irá aparecer na lista de variáveis.
Figura 5 - Criação da variável de ambiente do OGRE
9
Figura 6 - Lista de variáveis de ambiente, com a nova variável criada
Essa variável é extensivamente utilizada nos exemplos do OGRE. Ela será útil para localizar a e para apropriadamente definir os diretórios de headers e de libraries do OGRE, de modo a não haver preocupação relativa ao diretório onde o OGRE foi instalado. Ela também será bastante utilizada nos exemplos deste curso.
Estrutura de Diretórios do OGRE SDK Na Figura 4 podemos ver o conteúdo do diretório do OGRE SDK. Vamos analisar os itens mais importantes para o prosseguimento deste curso.
bin
Esta pasta contém as DLLs padrão do OGRE SDK — OGRE e OIS (Object Oriented Input System, biblioteca de input oficial do OGRE, embora seja um projeto separado). 10
As DLLs dessas bibliotecas existem tanto na pasta release quanto na pasta debug, e cada uma contém seus respectivos tipos de DLL: a pasta debug contém DLLs nãootimizadas que incorporam informações de debug, muito úteis ao fazer o debugging de aplicações baseadas no OGRE. A pasta release contém DLLs otimizadas e enxutas (no sentido de não possuírem qualquer informação para debugging), as quais são utilizadas para distribuir o aplicativo baseado no OGRE.
Docs
Esta pasta contém as referências da API na forma CHM (Compiled Help), além do Manual online do OGRE no formato HTML. A referência da API é gerada a partir do código atual, utilizando uma ferramenta chamada doxygen, a qual realiza um parse nos headers do OGRE e cria referências em hyperlinks a partir de seus conteúdos e marcações especiais no código-fonte. É bastante útil para descobrir quais classes e métodos estão disponíveis na API do OGRE, além de conter uma breve descrição de uso de cada classe. É ainda mais útil se já houver familiaridade com a API e precisar apenas de uma rápida referência. O Manual é um sumário condensado e conciso e condensado das características e utilização de algum grande subsistema do OGRE, bem como uma discussão a respeito do uso de algumas características avançadas do OGRE. O Manual é escrito e mantido pela equipe de desenvolvimento do OGRE, e serve como um bom complemento para as referências da API quando for necessária uma fonte rápida fonte de informação sobre uma particular característica do OGRE.
include
Esta pasta contém os headers do OGRE, os quais serão referenciados no seu código, bem como os headers da OIS. Esta pasta deve ser referenciada na configuração de qualquer projeto que utilize o OGRE.
lib
Esta pasta contém as bibliotecas de importação do OGRE e da OIS, necessárias para linkar as DLLs da pasta bin. Cada DLL tem uma correspondente .lib: *_d.lib para *_d.dll e release *.lib para *.dll. Esta pasta deve ser referenciada na configuração de qualquer projeto que utilize o OGRE.
11
Samples
Esta pasta contém os exemplos do OGRE, cada exemplo destacando uma característica em particular do OGRE. Os exemplos são fornecidos com código-fonte e podem ser facilmente compilados.
media
Esta pasta contém todos os materials, textures, meshes, etc., que os exemplos do OGRE requerem para sua execução. Os subdiretórios desta pasta podem ser uma ótima referência para aprender sobre a operação de vários sistemas do OGRE (especialmente scripts de material e o sistema de efeitos de partícula).
Compilando os Exemplos do OGRE Compilar os exemplos do OGRE é uma ótima maneira de validar o seu ambiente de desenvolvimento. Além disso, os exemplos permitem analisar o uso e implementação de diversos recursos do OGRE. Para compilá-los, vá ao diretório do OGRE SDK, onde você encontrará o arquivo OGRE.sln. Ao abrir este arquivo, você verá algo semelhante à Figura 7. No Solution Explorer, você pode ver cada exemplo separadamente. Estes exemplos foram implementados de forma que, ao serem compilados, será criada uma DLL para cada exemplo (Sample_BezierPatch.dll, Sample_BSP.dll,.., Sample_Water.dll). Ao final da lista de projetos no Solution Explorer, encontramos o SampleBrowser. Este projeto será compilado na forma de um arquivo executável (SampleBrowser.exe), e este será responsável por carregar as DLLs de cada exemplo do OGRE SDK. Para compilar toda a “Solution”, no centro-superior da janela do VC++, selecione o modo Release (o padrão ao abrir pela primeira vez é o modo Debug). Em seguida, clique no menu Build >>> Build Solution (ou aperte F7).
12
Figura 7 - Exemplos do OGRE SDK
Caso o VC++ relate a ocorrência do erro mostrado na Figura 8, não se preocupe. Esse erro é devido a ausência do programa CMake no seu computador. Sua instalação não é necessária, no entanto, para remover o erro, no Solution Explorer, selecione o projeto SampleBrowser e acesse o menu Project >>> Properties. Em Configuration, selecione Release, na árvore lateral, selecione Build Events >>> Pre-Link Event, conforme a Figura 9. Na direita, deixe o item Command Line em branco. Clique em Aplicar e OK. Aperte F7 para compilar a Solution novamente.
13
Figura 8 - Erro ao compilar o SampleBrowser
Figura 9 - Solução do erro no Pre-Link Event
Se tudo correu normalmente, acesse o diretório do OGRE SDK, vá para a subpasta bin\Release e execute o SampleBrowser.exe. Você irá ver a janela mostrada na Figura 10.
14
Para o SampleBrowser, essa janela será exibida apenas na primeira vez em que este for executado. Nela é possível escolher o subsistema de renderização (DirectX ou OpenGL) e configurar opções como Full Screen, Video Mode etc. A Figura 11 mostra a janela do SampleBrowser com as opções Video Mode (800 x 600) e Full Screen (No). As informações sobre a configuração escolhida serão armazenadas no arquivo de texto ogre.cfg, a ser armazenado no Diretório de Documentos do Usuário, na subpasta Ogre\Cthugha.
Figura 10 - Janela de configuração do Ogre3D
15
Figura 11 - Screenshot do SampleBrowser
Criando um Projeto no VC++ Este curso introdutório engloba a criação de um framework base para rapidamente desenvolver aplicativos com o OGRE. Dessa forma, é necessário aprender a criar e configurar corretamente um projeto que utilize o OGRE. Existem algumas ferramentas, como o OgreAppWizard, que facilitam este processo, mas é sempre importante conhecer os procedimentos. Para criar um projeto novo no VC++, clique no menu File >>> New >>> Project...; Em Project Types, selecione General. Em Templates, selecione Empty Project, como mostrado na Figura 12. Em Location, insira o diretório onde o projeto será armazenado, no exemplo, o diretório é C:\MyProjects. Em Name, digite OgreFramework. O campo Solution Name será automaticamente preenchido. Marque a opção Create directory for solution (assim, será criada uma pasta dentro do diretório C:\MyProjects, com o nome do projeto). Clique em OK. 16
Figura 12 - Criação de um novo projeto
Uma vez que o projeto foi criado, será necessário configurá-lo para fazer uso do OGRE. Mas, antes, adicione um arquivo de extensão .cpp ao projeto (esse passo é importante para habilitar algumas configurações do projeto). Para criar o arquivo, no Solution Explorer, clique com o botão direito do mouse no projeto OgreFramework (logo abaixo de Solution ‘OgreFramework’). Em seguida clique em Add >>> New Item..., como mostrado na Figura 13. Na janela que aparecer (Figura 14), em Categories selecione Code, em Templates selecione C++ file (.cpp). Em Name digite Main.cpp. Atente para o fato de que o campo Location já aparece preenchido no diretório do projeto, no entanto, por padronização deste curso, todos os códigos-fontes (arquivos .h e .cpp) do projeto ficarão em uma subpasta chamada Source. Crie a subpasta e referencie-a no campo Location, como mostrado na Figura 9. Em seguida clique em OK. O arquivo Main.cpp deverá aparecer no Solution Explorer, dentro do filtro Source. Ainda não adicione qualquer código a este arquivo. Nós próximos capítulos vamos fazer as implementações e a estrutura do framework base.
17
Figura 13 - Adicionando um arquivo ao projeto
Figura 14 - Criando o arquivo Main.cpp na subpasta Source
18
Agora podemos configurar o projeto apropriadamente. O termo “Configurar o projeto” significa, em outras palavras, dizer ao VC++ onde ele deve procurar os headers do OGRE, onde ele deve procurar as libs do OGRE, quais libs do OGRE ele deve utilizar, onde ele deve gerar o executável, qual nome ele deve dar ao executável, onde ele deve gerar os arquivos intermediários etc. Sem que você o ajude, o VC++ não pode ajudar você. Lembrando que é necessário configurar o projeto duas vezes: uma para o modo Release, outra para o modo Debug. Entender a diferença e o propósito dos modos de compilação Release e Debug pode lhe poupar muitas dores de cabeça. PASSO I: Clique no menu Project >>> Properties. Na janela que aparecer (Figura 15), em Configuration selecione o item Release. PASSO II: Na árvore lateral, no item Configuration Properties, selecione o item General. Na direita, os itens Output Directory (diretório onde será gerado o executável) e Intermediate Directory (diretório onde serão gerados os arquivos intermediários) precisam ser preenchidos conforme abaixo: Para o campo Output Directory: Para o campo Intermediate Directory:
$(SolutionDir)\Bin\$(ConfigurationName) $(SolutionDir)\Obj\$(ConfigurationName)
Figura 15 - Configuração da guia General em modo Release
19
PASSO III: Agora, na árvore lateral, selecione o item C/C++ >>> General (Figura 16). Na direita, em Additional Include Directories, você precisar referenciar os diretórios onde estão localizados os headers do OGRE e do BOOST (biblioteca utilizada pelo OGRE). Clique no botão “...” para adicionar cada diretório separadamente. Os diretórios a serem adicionados são: $(OGRE_HOME)\include\OGRE $(OGRE_HOME)\boost_1_44
Figura 16 - Configuração da guia C/C++ >>> General
PASSO IV: Na árvore lateral, selecione o item Linker >>> General (Figura 17). Na direita, em Additional Library Directories, você precisar referenciar os diretórios onde estão localizados os arquivos .lib do OGRE e do BOOST. Clique no botão “...” para adicionar cada diretório separadamente. Os diretórios a serem adicionados são: $(OGRE_HOME)\lib\release $(OGRE_HOME)\lboost_1_44\lib
20
Figura 17 - Configuração da guia Linker >>> General
PASSO V: Na árvore lateral, selecione o item Linker >>> Input (Figura 18). Na direita, em Additional Dependencies, você precisar referenciar os arquivos .lib do OGRE. Apenas digite OgreMain.lib, pois é o único .lib necessário em nossos primeiros testes.
Figura 18 - Configuração da guia Linker >>> Input
21
Após isso, clique em Aplicar para finalizar a configuração do modo Release. Agora é necessário configurar o modo Debug, que é muito semelhante ao modo Release. Para fazer isso, é preciso repetir os 5 passos (um pouco modificados). No PASSO I, ao invés de selecionar o item Release, selecione o item Debug. Em seguida repita os PASSOS II e III. No PASSO IV, substitua $(OGRE_HOME)\lib\release por $(OGRE_HOME)\lib\debug. No PASSO V, substitua OgreMain.lib por OgreMain_d.lib. Após isso, clique em Aplicar, em seguida clique em OK. Pronto.
22
Inicialização do OGRE Agora que temos o OGRE devidamente instalado e funcional, e já sabemos com configurar um projeto corretamente para utilizar o OGRE, faremos um abatimento geral sobre a inicialização do OGRE. A inicialização aqui mostrada segue apenas as estruturas básicas de um programa OGRE, não se preocupando com outros detalhes da implementação, de modo que vamos apenas utilizar enxertos de código a fim de ilustrar as explicações. O corpo do código do framework base pode ser encontrado em http://www.waveit.com.br/IntroOgre3D/aula01.rar. Faça o download do código e adicione-o ao seu projeto. Se você criou o projeto corretamente, esse código deverá compilar sem erros. Vamos então à inicialização da engine!
Root
A primeira coisa a se fazer em qualquer aplicação OGRE é criar uma instancia do Root. Você deve fazer isso antes de chamar qualquer outra operação do OGRE (exceto para o LogManager, embora este não seja abortado neste curso introdutório). O construtor do Root recebe algumas strings opcionais como parâmetro, todas são nomes de arquivos.
Ogre::Root *mRoot = new Ogre::Root(“plugins.cfg”,“ogre.cfg”,“ogre.log”);
plugins.cfg
Um plug-in do OGRE é qualquer código modular (.dll no Windows, .so no Linux) que implementa uma das interfaces de plug-in, como SceneManager ou RenderSystem. O arquivo plugins.cfg contém uma lista de plug-ins que o OGRE carregará em sua inicialização, bem como a localização destes.
23
# Define plugin folder PluginFolder=. # Define plugins Plugin=RenderSystem_Direct3D9 Plugin=RenderSystem_GL # Plugin=RenderSystem_GLES Plugin=Plugin_ParticleFX
A diretiva PluginFolder diz ao OGRE onde procurar pelos plug-ins listados no arquivo. A forma como esse caminho é interpretado, fica a seu cargo: se você utilizar um caminho absoluto, OGRE irá procurar apenas neste diretório. Se você utilizar um caminho relativo (i.e., um caminho que não inicia com / ou \), então o OGRE buscará no caminho relativo ao diretório atual do executável. A diretiva PluginFolder especificada em nosso arquivo de exemplo diz ao OGRE para procurar pelos plug-ins no diretório atual do executável (“.”). Perceba que linhas que começam com # são tratadas como comentários em arquivos de configuração do OGRE. O restante do arquivo contém a lista de plug-ins que você deseja que o OGRE carregue. Perceba que as extensões dos plug-ins não são inseridas; isto é proposital, e lhe permite utilizar o mesmo arquivo de configuração em múltiplas plataformas, sem ter que lidar com convenções de nomes de arquivos (embora o Linux seja bem flexível nesse aspecto, não se importando com a extensão que você dá ao arquivo). Os primeiros dois plug-ins listados anteriormente são implementações de render systems (DirectX e OpenGL). Você não precisa incluir todos eles em seu programa; no fim, você precisa de apenas um render system.
ogre.cfg
O OGRE fornece um meio simples de definir as opções básicas de renderização através de uma janela com GUI (Graphical User Interface) nativa, como mostrado na Figura 10. Essa janela de configuração é responsável por permitir ao usuário modificar parâmetros da renderização, como por exemplo, Full Screen (Yes ou No), FSAA (Full Screen Anti-Aliasing, i.e., nível de serrilhado das imagens), Video-Mode (resolução da tela) etc. Para exibir essa janela de configuração: bool resposta = mRoot->showConfigDialog();
24
O método showConfigDialog retorna true ou false dependendo se o usuário clicou no botão OK ou no botão Cancelar. Você deve considerar terminar a aplicação caso o usuário clique no botão Cancelar. Utilizar a janela de configuração do OGRE significa tratar automaticamente das definições do render system escolhido, podendo modificá-los na própria janela da configuração. O que o tudo isso tem a ver com o arquivo ogre.cfg? É essa janela de configuração que gera esse arquivo. Claro que você também pode criar esse arquivo você mesmo abrindo o editor de textos, e se você estiver usando outros recursos mais “manuais”, você sequer precisa ter esse arquivo de configuração, mas, por agora, vamos apenas olhar o que esse arquivo contém. Render System=Direct3D9 Rendering Subsystem [Direct3D9 Rendering Subsystem] Allow NVPerfHUD=No FSAA=0 Floating-point mode=Fastest Full Screen=No Rendering Device=Monitor-1-NVIDIA GeForce GTS 250 Resource Creation Policy=Create on all devices VSync=No VSync Interval=1 Video Mode=800 x 600 @ 32-bit colour sRGB Gamma Conversion=No [OpenGL Rendering Subsystem] Colour Depth=32 Display Frequency=100 FSAA=0 Full Screen=Yes RTT Preferred Mode=FBO VSync=No VSync Interval=1 Video Mode=1024 x 768 sRGB Gamma Conversion=No
Perceba que estas opções acima correspondem às opções mostradas na janela de configuração. Estes valores variam de computador para computador. Embora este arquivo não seja perfeitamente compreensível e intuitivo para nós, humanos, ele foi realmente planejado para ser lido pela máquina, e embora seja possível defini-los à mão, provavelmente é melhor deixar a sua criação e edição a cargo da janela de configuração do OGRE. O OGRE também nos fornece um método para carregar o arquivo de configuração existente (i.e., ogre.cfg). 25
if (!mRoot->restoreConfig()) mRoot->showConfigDialog();
Esta seqüência de operação é muito comum quando utilizamos o arquivo ogre.cfg. Se o método restoreConfig() falhar, então não existe o arquivo ogre.cfg, e a a janela de configuração é, então, exibida. Quando o usuário clicar em OK, as definições serão salvas num recém-criado, de nome ogre.cfg. Utilizando o método restoreConfig(), você evita ter de forçar os usuários do aplicativo a verem a janela de configuração toda vez que executarem o programa. Você também pode salvar as definições atuais do OGRE para o arquivo ogre.cfg a qualquer momento, com o método saveConfig(). mRoot->saveConfig();
Ogre.log
O OGRE fornece ainda logs de diagnostico e exceções utilizando sua classe de gerenciamento de logs. Registros de logs são úteis para obter detalhes a respeito de uma falha ou erro na máquina do usuário, sem precisar perguntar a este por detalhes sobre o seu ambiente de execução. A saída de log gerada pelo OGRE contém todos os eventos, bem como dados sobre a inicialização, estados e informações sobre a capacidade da máquina em questão, sendo este arquivo gerado a partir de cada execução do programa. Essa saída é enviada para um arquivo de texto simples; o ogre.log. O nome deste arquivo é definido no momento da criação do Root.
Render Window
A qualquer ponto, após o render system ter sido selecionado (neste exemplo, ocorre quando o usuário seleciona e configura o render system na janela de configuração e clica em OK), você pode chamar o método initialise(), da classe Root:
26
mRoot->initialise(true, "OgreFramework"); Ogre::RenderWindow *mRenderWindow = mRoot->getAutoCreatedWindow();
Ou simplesmente: Ogre::RenderWindow *mRenderWindow = mRoot->initialise(true, "OgreFramework");
A primeira linha irá fazer com que o Root complete sua inicialização e crie uma janela de renderização com as definições que o usuário selecionou na janela de configuração. A string “OgreFramework” será o título desta janela. O segundo parâmetro não é obrigatório e, caso você não informe título algum, o padrão “OGRE Render Window” será utilizado. O primeiro parâmetro é obrigatório, ele diz ao OGRE se ele deve criar automaticamente a janela de renderização; para facilitar a compreensão nesta parte do curso, vamos apenas dizer ao OGRE para que crie nossa janela de renderização. A segunda linha obtém o ponteiro para a instancia do RenderWindow. O render window é somente uma parte da renderização da cena. Ele é o canvas, a superfície na qual o OGRE renderiza seu conteúdo. O OGRE precisa de pelo menos uma câmera para “capturar quadros” da sua cena 3D, e um ou mais viewports, os quais são regiões sobre a superfície de renderização (como o render window) na qual a câmera “revela” seu conteúdo.
Scene Manager
Não vamos nos aprofundar muito no Scene Manager por agora, uma vez que vamos falar dele com mais detalhes adiante. Entretanto, com o propósito de manter este capítulo coeso (já que mencionamos o Scene Manager tantas vezes), é necessário que você saiba pelo menos o básico sobre a criação do Scene Manager para utilizá-lo em seu código. Ok. Antes de utilizar a instancia de um Scene Manager, você deve criar uma. Ogre::SceneManager* mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC, "MySceneManager");
27
Quando o OGRE carrega seus plug-ins, entre esses plug-ins pode haver várias implementações de scene manager, como discutido anteriormente. Cada uma dessas implementações irá se auto-registrar junto ao OGRE como um tipo particular de scene manager:
ST_GENERIC: Implementação mínima de um scene manager, não otimizado para qualquer tipo de cena ou estrutura. Muito útil para cenas minimamente complexas (como as cenas onde existe apenas GUI).
ST_INTERIOR: Implementação otimizada para renderizar interiores e cenas potencialmente densas, do tipo quarto fechado.
ST_EXTERIOR_CLOSE: Implementação otimizada para renderizar cenas exteriores (outdoor scenes) com visibilidade até distancias próximas ou médias.
ST_EXTERIOR_FAR: Anacronismo para retro-compatibilidade entre versões do OGRE, pouco ou não mais utilizado. Utilize ST_EXTERIOR_CLOSE ou ST_EXTERIOR_REAL_FAR ao invés.
ST_EXTERIOR_REAL_FAR: Implementação típica para mundos do tipo “paged”. Mundo “paged” geralmente são enormes, possivelmente planetas inteiros.
No exemplo dado, criamos um scene manager do tipo ST_GENERIC, uma vez que não tínhamos nenhuma cena específica para renderizar. Você aprenderá mais sobre as classes SceneManager do OGRE mais adiante; por agora, é suficiente saber que elas funcionam como uma fábrica (pois implementam o Design Pattern Factory) para os mais diversos tipos diferentes de objetos que existem numa cena 3D, incluindo câmeras. De modo a criar uma nova câmera para renderizar sua cena 3D, você deve chamar o método createCamera() na interface SceneManager: Ogre::Camera *mCamera = mSceneMgr->createCamera("MyCamera"); mCamera->setNearClipDistance(1); mCamera->setFarClipDistance(1000); mCamera ->setAspectRatio(Ogre::Real(1.333333));
Neste exemplo, mSceneMgr é um ponteiro para uma instância válida do um SceneManager. A classe Camera tem muitas propriedades que podem ser ajustadas, e, claro, métodos para ajustá-las. 28
O código anterior demonstra o básico que você irá precisar para uma aplicação OGRE mínima. Ele define o aspect ratio equivalente a um display de 4:3 (como a maioria dos monitores CRT e alguns LCDs non-widescreen). Esse valor pode ser ajustado ou redefinido a qualque momento, e usualmente é definido como a razão entre a altura e comprimento do viewport (tal como fizemos aqui, visto que 4/3 é aproximadamente igual a 1.33333). O código mostrado também define os valores das distancias do near clip plane e do far clip plane. Aqui utilizamos adotamos nosso padrão de 1 e 1000, mas você pode utilizar qualquer um que quiser, tão logo a razão entre far e near esteja próxima de 1000, ou menos, para evitar problema de z-fighting. Posteriormente, vamos aprender como manipular a câmera de modos mais complexos, mas por agora, já é suficiente para o propósito de criar uma viewport em nossa janela de renderização. Ogre::Viewport *mViewport = mRenderWindow->addViewport(mCamera); mViewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0));
O código acima cria um novo viewport no render window que criamos quando chamamos o método initialise() anteriormente no Root. Esse código também define a cor do background do viewport para preto.
Render Loop
O modo mais simples de pedir ao OGRE a tarefa de renderizar sua cena é invocando o método startRendering() no Root: mRoot->startRendering();
Isso fará com que o OGRE renderize sua cena “eternamente” em loop, não importando que conteúdo você tenha em sua cena. Esse loop continuará existindo mesmo que você feche a janela de renderização criada utilizando (por exemplo, clicando no botão x, no canto direito das janelas dos aplicativos Windows), ou quando um frame listener devidamente registrado retorna false. Um método alternativo para terminar o loop de renderização é chamando o método
29
queueEndRendering() do Root, em qualquer lugar no código, embora seja mais comum simplesmente retornar false a partir de algum frame listener.
Frame Listener
Pra início de conversa, Frame listeners são o único meio pela qual você pode invocar seu próprio código durante o Render Loop do OGRE quando estiver utilizando o método startRendering(). Um frame listener é simplesmente uma classe que implementa a interface FrameListener, atuando como um callback que permite ao OGRE invocar o seu código no início, durante ou ao fim do processamento de cada frame. O Exemplo abaixo mostra como criar um frame listener. No framework base, a classe Application é um frame listener. class myFrameListener : public Ogre::FrameListener { public: bool frameStarted (const Ogre::FrameEvent &evt); bool frameEnded (const Ogre::FrameEvent &evt); }; bool myFrameListener::frameStarted(const Ogre::FrameEvent &evt) { // aqui você pode fazer algo antes do frame ser renderizado return true; } bool myFrameListener::frameEnded(const Ogre::FrameEvent &evt) { // aqui você pode fazer algo após o frame ser renderizado return true; } MyFrameListener myListener; // Não esqueça que você precisa adicionar um frame listener // ANTES de chamar o método startRendering()!!! // Assumindo que você já criou o Ogre::Root mRoot->addFrameListener(myListener); mRoot->startRendering();
30
A implementação do método frameStarted() será chamada antes do OGRE invocar o pipeline de renderização. Geralmente, o método frameEnded() é menos utilizado, sendo útil quando você precisa destruir algum objeto a cada frame, e é chamado após o OGRE completar a renderização do frame. Geralmente, durante cada frame. Você deve processar eventos de entrada da HID (Human Interface Device, como teclado, mouse, joystick, WiiMote, Kinect etc). Dependendo do evento ocorrido, você pode programar um modelo 3D se mova e/ou rotacione, pode fazer a câmera se mover ou girar, pode fazer um personagem andar ou o que quiser. Não importando que evento seja, ele ocorre durante um ou ambos os métodos de callback do FrameListener.
Main Rendering Loop
Uma típica aplicação OGRE irá renderizar os frames um após o outro, sem cessar (a menos que você interrompa, é claro). Vimos anteriormente o método para invocar o render loop do OGRE: startRendering(). Entretanto, esse método apenas inicia um pequeno loop que invoca outro método: renderOneFrame(). A existência deste último método é importante por diversos motivos. Por exemplo, você pode querer incorporar o OGRE em uma aplicação já existente ou em algum framework (o nosso caso, aliás), onde seria complicado utilizar o método startRendering(). É importante resaltar que você ainda pode utilizar as classes FrameListener com o método renderOneFrame(). O método renderOneFrame() é, na verdade, o método que notifica qualquer frame listener que esteja registrado junto ao Root. Em nosso framework base, utilizamos o método renderOneFrame() juntamente com um frame listener, que é a classe Application, assim, sempre que o método renderOneFrame() é chamado, ele notifica a classe Application que por sua vez executa o método frameRenderingQueued(), o qual é, em palavras simples, um intermediário entre os métodos frameStarted() e frameEnded() discutidos anteriormente . Abaixo temos um pequeno exemplo que objetiva lhe mostrar como você pode implementar seu próprio render loop manual, e onde exatamente ele estaria situado no fluxo do seu código.
31
// // // //
Faz tudo o que fizemos até agora a respeito da inicialização do OGRE: cria o Root, carrega plug-ins, cria o render window, scene manager, câmera e viewport, além de colocar alguma coisa na cena.
bool keepRendering = true; while (keepRendering) { // processa eventos da rede em eventos do aplicativo // processa eventos de input em eventos do aplicativo // renderiza o próximo frame mRoot->renderOneFrame(); // // // // if
verifica se deve sair do loop Nota: NextMessageInQueue() é completamente fictício sendo utilizado aqui apenas com fins ilustrativos Isso não existe no OGRE (NextMessageInQueue() == QUIT) keepRendering = false;
} // Deleta objetos criados para liberar memória // Então, finaliza o OGRE delete mRoot;
32
Gerenciamento dos Recursos de Media Temos razões muito boas para utilizar o sistema de gerenciamento de recursos do OGRE ao invés de simplesmente carregar os recursos a partir de um arquivo no disco rígido quando requisitado. O primeiro é velocidade: o acesso ao disco é muito lento quando comparado ao acesso à memória, de modo que não queremos exacerbar um já apertado tempo do frame carregando qualquer coisa do disco. Além disso, não somente é mais rápido ter dados carregados (potencialmente comprimidos), descompactados, e prontos para uso na memória, como também é mais eficiente descarregá-los quando não forem mais necessários, e trazê-los de volte caso sejam necessários novamente. Por fim, com o sistema de gerenciamento de recursos do OGRE, não precisamos carregar na memória, um por um, cada recurso que a aplicação possa precisar.
Gerenciamento de Recursos na Prática
Abaixo temos uma cópia do arquivo resources.cfg que acompanha o OGRE SDK. Este arquivo é utilizado pelo SampleBrowser para indicar a localização dos recursos. # Resources required by the sample browser and most samples. [Essential] Zip=../../media/packs/SdkTrays.zip FileSystem=../../media/thumbnails # Common sample resources needed by many of the samples. # Rarely used resources should be separately loaded by the # samples which require them. [Popular] FileSystem=../../media/fonts FileSystem=../../media/materials/programs FileSystem=../../media/materials/scripts FileSystem=../../media/materials/textures FileSystem=../../media/materials/textures/nvidia FileSystem=../../media/models FileSystem=../../media/particle FileSystem=../../media/DeferredShadingMedia Zip=../../media/packs/cubemap.zip Zip=../../media/packs/cubemapsJS.zip Zip=../../media/packs/dragon.zip Zip=../../media/packs/fresneldemo.zip Zip=../../media/packs/ogretestmap.zip Zip=../../media/packs/ogredance.zip
33
Zip=../../media/packs/Sinbad.zip Zip=../../media/packs/skybox.zip [General] FileSystem=../../media
Este arquivo é praticamente auto-explicativo. Três grupos de recursos são declarados e preenchidos: Essential, Popular e General. O grupo General sempre existe independente de ter sido declarado ou não. As definições de FileSystem e Zip descrevem o tipo de arquivo: FileSystem indica um recurso do tipo que é baseado numa localização no sistema de arquivos, enquanto que a definição Zip indica que o recurso é baseado num arquivo compactado (do tipo .zip padrão).
Localização dos Recursos
Uma pergunta comum nos fóruns é “Como posso definir a localização de um recurso sem utilizar o resources.cfg?”. Vejamos então a implementação do método addResources() da classe Manager, que lê o arquivo resources.cfg mostrado anteriormente. Ogre::ConfigFile cf; cf.load("resources.cfg"); Ogre::ConfigFile::SectionIterator seci =cf.getSectionIterator(); Ogre::String secName, typeName, archName; Ogre::ResourceGroupManager *rgm = Ogre::ResourceGroupManager::getSingletonPtr(); Ogre::ConfigFile::SettingsMultiMap *settings; while (seci.hasMoreElements()) { secName = seci.peekNextKey(); Settings = seci.getNext(); Ogre::ConfigFile::SettingsMultiMap::iterator i; for (i = settings->begin(); i != settings->end(); ++i) { typeName = i->first; archName = i->second; rgm->addResourceLocation(archName, typeName, secName); } }
34
Este código simplesmente itera sobre cada seção no arquivo (neste caso, as seções são também os nomes dos grupos: Essential, Popular e General), e para cada seção, itera cada par de nome/valor. Para cada par de nome/valor, é chamado o método addResourceLocation() do ResourceGroupManager. O primeiro método a ser observado é o addResourceLocation(). Pode ser mais fácil observar a analogia entre o código e o arquivo de configuração, no exemplo hard-coded abaixo. Ogre::ResourceGroupManager *rgm = Ogre::ResourceGroupManager::getSingletonPtr(); rgm->addResourceLocation(
"../../media/packs/SdkTrays.zip", "Zip", "Essential");
rgm->addResourceLocation(
"../../media", "FileSystem", "General");
rgm->addResourceLocation(
"../../media/fonts", "FileSystem", "General");
// e assim por diante, para o resto dos caminhos no arquivo
Perceba que todos os exemplos estão utilizando caminhos relativos. O OGRE não tem qualquer problema com caminhos absolutos, porém, se você utilizá-los, seu programa correrá o risco de não funcionar em outra máquina que não seja a sua, uma vez que você não poderá garantir que todos os computadores estarão organizados da mesma forma que o seu. Então, faça um favor a si mesmo e utilize caminhos relativos para localizar seus recursos.
Inicialização dos Recursos
Uma vez que você tenha definido a localização dos seus recursos, você terá que inicializa-los antes de utilizá-los na aplicação (é por isso que temos o método loadResources() na classe Application do framework base). Você deve também ter criado pelo menos um RenderWindow antes de tentar inicializar seus recursos, uma vez que fazer o parser dos scripts, poderá criar recursos que utilizam a GPU, os quais requerem um contexto de renderização para que venham a existir.
35
Ogre::ResourceGroupManager *rgm = Ogre::ResourceGroupManager::getSingletonPtr(); // initialize all of the previously defined resource groups rgm->initialiseAllResourceGroups(); // or, alternately, initialize the defined resource groups // one at a time rgm->initialiseResourceGroup("General"); rgm->initialiseResourceGroup("Essential"); rgm->initialiseResourceGroup("Popular");
No código acima, o primeiro exemplo inicializa todos os grupos que ainda não foram inicializados. Já o segundo exemplo inicializa apenas os grupos especificados, um de cada vez.
Descarregamento de Recursos
Você pode descarregar um recurso (individualmente ou por grupos) da memória qualquer momento; se o recurso estiver referenciado em outro lugar no seu código quando você descarregá-lo, ele será recarregado na próxima vez que for utilizado. O OGRE, então, irá preveni-lo de desacrregar permanentemente um recurso que ainda esteja em uso, de modo a salvá-lo de uma situação potencialmente ruim (pelo menos em termos de recursos relacionados a aplicações 3D). O código abaixo mostra como descarregar um grupo de recursos através da interface ResourceGroupManager: Ogre::ResourceGroupManager *rgm = Ogre::ResourceGroupManager::getSingletonPtr(); rgm->unloadResourceGroup("Popular", true); rgm->unloadUnreferencedResourcesInGroup("Popular", true);
Como já mencionado, a interface carrega e descarrega recursos de um único grupo a cada vez. Este código apenas descarrega os recursos da memória; ele não remove as instancias desses recursos. O método unloadUnreferencedResourcesInGroup() irá descarregar somente os recursos para os quais não existe qualquer referência.
36
Dispositivos de Entrada Neste capítulo, iremos estudar como se dá a utilização da biblioteca OIS (Object Oriented Input System) em conjunto com o Framework base. O Framework elaborado neste curso tem uma arquitetura flexível, de modo a suportar futuras expansões ao uso de dispositivos não-convencionais, como o Wiimote, Kinect, Dispositivos Hápticos, Joysticks etc. Por agora, vamos nos limitar aos dois dispositivos mais comuns: Mouse e Teclado.
Biblioteca de Input
A OIS é uma biblioteca open-source, multiplataforma, que suporta diversos dispositivos de interface com o ser humano, como mouse e teclado (suporta outros dispositivos também, não abordados neste curso). Para integrar a OIS no Framework base, basta incluir no seu projeto (Additional Include Directories, no VC++) o diretório $(OGRE_HOME)\include\. Nas bibliotecas a serem linkadas (Additional Dependencies), inclua a lib OIS.lib. Adicione os arquivos InputManager.cpp e InputManager.h ao seu projeto (arquivos enviados por email). Como o propósito deste curso não é abordar a uma biblioteca de input, e sim uma biblioteca de renderização, não entraremos nos detalhes da OIS. Por agora, basta saber que o InputManager funcionará para o framework como uma caixa-preta, onde iremos apenas utilizar seus métodos.
Input Manager e Input Listener
A OIS utiliza bastante o Design Pattern Observer (ou Listener) o qual permite que uma classe seja notificada sempre que determinados eventos ocorrerem. No nosso caso, desejamos que o Manager seja notificado pela OIS sempre que ocorrerem os seguintes eventos:
Tecla pressionada; Tecla liberada; Mouse movido; Botão do mouse pressionado; Botão do mouse liberado. 37
Como o intuito do Framework é fazer com que o programa seja escrito na camada Application, fizemos com que a tarefa de lidar diretamente com a OIS fique a cargo do Manager, através de um subsistema chamado de Input Manager. Assim, a classe Manager será o Listener de eventos gerados pelo mouse e teclado. O Manager poderá, então, notificar a classe Application a respeito desses eventos. Para isso devemos fazer com que o Manager herde as classes OIS::MouseListener e OIS::KeyListener. Assim, no Manager.h, faça
#include “InputManager.h”
class Manager : public OIS::MouseListener, public OIS::KeyListener { // código anterior do Manager; };
Após fazer do Manager o nosso Input Listener, devemos herdar e implementar alguns métodos pure virtuals das classes OIS::MouseListener e OIS::KeyListener. A declaração da assinatura destes métodos deve ser feita na Manager.h. Esses métodos serão chamados sempre que o evento correspondente acontecer.
protected: // Private methods inherited from OIS. virtual bool mouseMoved (const OIS::MouseEvent &arg); virtual bool mousePressed (const OIS::MouseEvent &arg, OIS::MouseButtonID id); virtual bool mouseReleased (const OIS::MouseEvent &arg, OIS::MouseButtonID id); virtual bool keyPressed (const OIS::KeyEvent &arg); virtual bool keyReleased (const OIS::KeyEvent &arg);
Adicionalmente, na classe Manager, você pode criar um atributo-ponteiro para a classe Input Manager. Dessa forma fica mais fácil acessar sua instancia (quando estiver declarada, obviamente). Ou, ao invés, você poderia acessar sua instancia 38
diretamente através de seu método Singleton (a classe Input Manager implementa o Design Pattern Singleton). Para criar o atributo ponteiro, apenas faça: InputManager
*mInputMgr;
Agora precisamos criar obter uma instancia válida do Input Manager, registrar o Manager como um Input Listener e por último, porém não menos importante, escutar por eventos a cada frame. Para isso, no método setup(), em qualquer lugar após a criação do Render Window, faça:
01 02 03 04 05 06 07 08 09
mInputMgr = new InputManager(); mInputMgr->initialise(mRenderWindow, true); mInputMgr->setWindowExtents (mRenderWindow->getHeight(), mRenderWindow->getWidth()); mInputMgr->addKeyListener(this, "MyKeyListener"); mInputMgr->addMouseListener(this, "MyMouseListener");
Na linha 01, é criada a instância do Input Manager. A linha seguinte inicializa o subsistema, passando como parâmetro o Render Window (pois este representa a janela na qual os eventos serão recebidos); o segundo parâmetro é um valor boolean, onde se for verdadeiro, o aplicativo mantém (ou seja, não oculta) o mouse nativo do sistema operacional. Se for falso, o mouse nativo é ocultado, podendo ceder espaço a um mouse com ícone personalizado, como veremos no capítulo GUI com SdkTrays. Na linha 04 é definida a área útil na qual os eventos serão recebidos. As linhas 08 e 09 registram o Manager (ponteiro this) como um Key Listener e Mouse Listener, respectivamente. Agora é necessário implementar os métodos que foram herdados. Perceba que o código abaixo mostra a implementação de cada método, e veja também que automaticamente chamamos o evento correspondente na classe Application (embora os métodos correspondentes na Application só serão implementados nos próximos passos).
39
01 02 03 04 05
bool Manager::mouseMoved(const OIS::MouseEvent &arg) { return mApp->mouseMoved(arg); }
06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
bool Manager::mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { return mApp->mousePressed(arg, id); } bool Manager::mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { return mApp->mouseReleased(arg, id); } bool Manager::keyPressed(const OIS::KeyEvent &arg) { return mApp->keyPressed(arg); } bool Manager::keyReleased(const OIS::KeyEvent &arg) { return mApp->keyReleased(arg); }
Após implementar estes métodos, para finalizar a integração do Input Manager com o Manager, precisamos:
Escutar os dispositivos a cada frame; Redimensionar a área válida para o mouse, quando a janela for redimensionada; Deletar o Input Manager ao finalizar o Aplicativo.
É importante ressaltar que a OIS não utiliza threads ou qualquer outro tipo de mágica para escutar os dispositivos. Sendo assim, é necessário verificar os estados do mouse e do teclado a cada instante. O melhor modo de fazer isso é escutando-os a cada frame (este é o modo de entrada buffered, caso você resolva fazer suas próprias pesquisas no assunto). No método update(), coloque: mInputMgr->capture();
40
Para redimensionar a área de atuação do mouse ao redimensionar a janela, no método WindowResized(), adicione: mInputMgr->setWindowExtents(rw->getWidth(), rw->getHeight());
No método shutdown(), após deletar o mApp, adicione: if (mInputMgr)->capture(); delete mInputMgr;
Após isso, basta implementar o métodos correspondentes na Application. A declaração da assinatura destes métodos deve ser feita na Application.h. Esses métodos serão chamados através do Manager, sempre que o evento correspondente acontecer.
public: bool mouseMoved (const OIS::MouseEvent &arg); bool mousePressed (const OIS::MouseEvent &arg, OIS::MouseButtonID id); bool mouseReleased (const OIS::MouseEvent &arg, OIS::MouseButtonID id); bool keyPressed (const OIS::KeyEvent &arg); bool keyReleased (const OIS::KeyEvent &arg);
No Application.cpp, esses métodos serão utilizados para responder a ações do mouse e do teclado. Abaixo temos um exemplo de implementação.
01 02 03 04 05 06 07 08 09 10
bool Application::mouseMoved(const OIS::MouseEvent &arg) { return true; } bool Application::mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { return true; }
41
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
bool Application::mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { return true; } bool Application::keyPressed(const OIS::KeyEvent &arg) { return true; } bool Application::keyReleased(const OIS::KeyEvent &arg) { return true; }
42
Materials TODO.
Scene Management TODO.
Ferramentas de Produtividade TODO.
Animação TODO.
GUI com SdkTrays TODO.
Estudo de Caso TODO.
43
Hot tips TODO.
Dúvidas comuns TODO.
Exportação com o Blender TODO.
44