Tecnologias de Jogos de Vídeo Abel J. P. Gomes & Gonçalo Amador LAB. 6 Departamento de Informática Universidade da Beira Interior Portugal 2013 Copyright 2009-2013 All rights reserved. LAB. 6 SISTEMAS DE PARTÍCULAS 1. Objetivos 2. Conceitos 3. Exercícios teóricos e de programação 4. Trabalho futuro Lab. 6 SISTEMAS DE PARTÍCULAS Nesta lição prático-laboratorial aprender-se-á como funciona um motor de partículas simples, para efeitos de explosões, e um motor de partículas complexo, para efeitos de líquidos. Irão também ser abordados alguns dos casos em que os motores de partículas são empregues, para simular determinado efeito. 1. Objetivos específicos de aprendizagem Terminada esta ficha de trabalho, o aluno deve saber e ser capaz de: 1. Saber implementar um motor de partículas simples e um motor complexo, mais especificamente para efeitos de explosões e liquidos respetivamente. 2. Identificar quais os possíveis casos de uso e limitações de um sistema de partículas. 3. Identificar de que forma os motores de partículas a implementar podem ser adicionados ao módulo da física do motor de jogos JMOGE, e para que possíveis usos. 2. Sistemas de Partículas Os sistemas de partículas foram primeiramente concebidos para serem usados em efeitos especiais em filmes (“Star Trek II: The Wrath of Khan”) e só mais tarde foram também utilizados em jogos, a título de exemplo o jogo Quake II, como ilustrado na Fig. 1. O conceito inerente por detrás de um motor de partículas é que toda a matéria é constituída por milhões de átomos. No entanto, devido há quantidade enorme de átomos necessários (biliões ou mais), o que implicaria uma enorme capacidade de processamento, para simular algo complexo como água dentro de um copo, utiliza-se número muito menores de elementos (i.e., partículas), na casa das dezenas até aos milhares. Uma vez que podem existir múltiplos sistemas de partículas em simultâneo, o número de partículas varia dependendo da quantidade de sistemas a simular e do número de partículas em cada sistema. Figura 1: Efeito de “squish” de sangue no jogo Quake II, suportado por um sistema de partículas simples. Existem dois tipos de sistemas de partículas: os simples e os complexos. O que os distingue é que nos sistemas simples é incomum existirem testes de colisões entre partículas, existe em regra apenas um tipo ou fase de partículas, e cada partícula é desenhada individualmente e não a geometria formada por ela e partículas próximas. Nos sistemas complexos as partículas obedecem a regras físicas, mais complexas, e.g., na simulação de líquidos recorrendo ao sistema de equações de Navier-Stokes. No mesmo sistema as partículas podem ser de diversos tipos, i.e., ter fases distintas, e.g., numa simulação de líquidos podem existir partículas do tipo água e do tipo óleo. Nos sistemas complexos as partículas podem ainda conter informação sobre a geometria da partícula em função da sua proximidade com partículas vizinhas, como ilustrado nas Fig. 3 e 4 para uma simulação de líquidos, com e sem reconstrução. Figura 2: Simulação de um líquido recorrendo a um sistema de partículas complexo, sem reconstrução. Figura 3: Simulação de um líquido recorrendo a um sistema de partículas complexo, com reconstrução e efeitos de ótica. Os sistemas de partículas servem em particular para simular fenómenos naturais, e.g., nuvens, bolhas de ar dentro de água, cascatas, explosões, etc. Em jogos utilizam-se motores de partículas simples e complexos, mas com números reduzidos de partículas, de forma a assegurar o desempenho em tempo real dos jogos. No entanto em industrias como a de filmes de animação por computador, os sistemas de partículas de elevada complexidade com números de partículas, na casa das dezenas de milhar, são empregues. Um sistema de partículas possui por norma duas entidades distintas: partícula, e um gestor de partículas. A partícula tem como propriedades mínimas a sua posição, velocidade, aceleração, idade, massa, e tempo de vida. Uma partícula pode durar para sempre mas dependendo do uso pretendido morre ao fim de algum tempo. Um efeito de partículas acaba quando todas as partículas morrem. O gestor de partículas cria e atualiza cada uma das partículas a seu cargo ao longo do tempo. Um motor de partículas pode ter um gestor para múltiplos efeitos de partículas, ou podem haver múltiplos gestores um por efeito pretendido. De referir que efeitos aqui refere-se a um fenómeno, e.g., explosão, fumo, fogo, liquido, etc, e não a condições distintas de simulação, e.g., água a verter para um copo ou um rio a correr continua a ser um efeito de líquidos um gestor apenas condições iniciais diferentes. Para esta ficha é disponibilizado um projeto de apoio (ParticleSystem) que tem dois sistemas de partículas, um simples para explosões e um complexo para líquidos. De referir que para explosões não são considerados efeitos de combustão, o que tornaria o sistema simples num sistema complexo. São apenas considerados efeitos de expansão, i.e., partido de uma posição inicial as partículas movem-se para longe desse ponto. No projeto referido apenas é necessário alterar, para cada um dos sistemas, um total de quatro classes: Particle.java, ParticleSystem.java. A classe Particle.java implementa o interface IParticle.java para uma partícula num sistema simples (explosão) e uma partícula complexa (líquidos). A classe ParticleSystem.java implementa o interface IParticleSystem.java para um gestor de partículas num sistema simples (explosão) e num sistema complexo (líquidos). As classes GameRendererExplosion.java e GameRendererSPH.java são as classes principais de cada sistema de partículas, onde é configurada uma aplicação gráfica em JOGL. No caso do sistema simples quando o botão esquerdo do rato é premido um efeito de explosão é gerado (após a realização dos exercícios que se seguem). No sistema complexo quando o botão esquerdo do rato é premido são adicionadas partículas de liquido, e quando o botão direito é premido são adicionadas partículas do tipo obstáculo. O sistema de partículas complexo utiliza SPHs, que carece de alguma introdução prévia. 3. Smoothed-Particle Hydrodynamics (SPH) Existem diversas formas de simular fluidos, entre outros líquidos. As SPH (http://en.wikipedia.org/wiki/Smoothed-particle_hydrodynamics) recorrem às equações de Navier-Stokes (http://en.wikipedia.org/wiki/Navier %E2%80%93Stokes_equations), e permitem simular a interação entre fluidos de diversos tipos ou fases, e.g., água e fumo. As SPH são uma abordagem Lagrangiana, i.e., as alterações ao fluido são observadas em cada um dos elementos que o constitui, ou seja, todas as partículas, de tipos distintos ou não, pertencentes ao mesmo sistema complexo de partículas. Cada partícula tem associada uma distância de “smooth” (parâmetro SMOOTHING_LENGTH, da classe ParticleSystem.java, na diretoria “physics/particleSystem/SPH”). As propriedades físicas de cada partícula no sistema são influenciadas por todas as demais partículas no sistema, que estejam a esta distância. Esta influência é controlada ou “smooth”, i.e., garante a estabilidade numérica do sistema. Tal como em sistemas de partículas simples atualizar/avançar a simulação para um determinado intervalo de tempo em segundos (parâmetro TIMESTEP, da classe ParticleSystem.java, na diretoria “physics/particleSystem/SPH”) consiste em atualizar cada partícula. A título de exemplo o intervalo do tempo por omissão é 0.6 segundos, ou seja, a simulação é atualizada cerca de 2 vezes para cada segundo de simulação. Aumentar este valor introduz mais instabilidade na simulação, diminui-lo significa mais cálculo por segundo de simulação mas uma simulação mais exata. Não esquecer, que mais partículas também implicam mais cálculo. Sendo o número de partículas e o número de vezes que a simulação tem de ser atualizada por segundo dois dos principais critérios de desempenho das SPH. De referir que existem outros critérios mas que não estão implementados nem serão abordados no decorrer desta ficha, e.g., reconstrução da superfície de um liquido. Aproximar/estimar uma solução para as equações de Navier-Stokes, requer decomposição em passos. A ideia subjacente a reter é atualizar (método update(GL2 gl) da classe ParticleSystem.java) o sistema de partículas consiste em realizar um conjunto de passos para cada partícula, de referir por ordem os métodos: redistributeGrid(), computeDensities(), computeStressTensors(), addAccelerations() e renderParticle(GL2 gl) da classe ParticleSystem.java, na diretoria “physics/particleSystem/SPH”. O que o primeiro método faz resume-se a recriar uma grelha em que cada célula contem uma das partículas existentes no sistema. O segundo método atualiza o termo da densidade ou seja a quantidade de partículas que afetam cada partícula no sistema. O terceiro método recalcula a pressão e velocidade a que cada partícula está sujeita em função de partículas na sua proximidade. O penúltimo método atualiza as propriedades físicas de cada partícula tendo em conta acelerações externas como por exemplo a gravidade e trata do casos em que as partículas tentam sair do espaço de simulação (força as partículas a simular a colisão com uma parede neste caso). O ultimo passo consiste em desenhar cada uma das partículas. De referir ainda que existem neste modelo dois tipos de partículas: liquido e obstáculos sólidos. No entanto podiam haver mais tipos de partículas, e.g., gás, outro liquido, etc. Cada um dos métodos referido consiste em realizar uma ou mais atualizações todas as partículas do sistema. Partes desses métodos irão ser implementados nesta ficha, na a classe Particle.java na diretoria “physics/particleSystem/SPH”. No sistema simples para efeitos de explosões, irá ser verificado que o sistema ao fazer uma atualização, atualiza toda e cada partícula, num total de 2 métodos apenas. No sistema complexo uma atualização do sistema implica vários passos constituídos cada por 1 ou mais sub-passos por partícula. É importante referir que não é expectável que o aluno absorva todos os pormenores da simulação de líquidos (o que levaria alguns meses no mínimo), apenas que tenha uma ideia de estruturação de sistemas de partículas simples e complexos, e da dificuldade na implementação entre estes. De referir que existe uma componente adicional de reconstrução de geometria para sistemas complexos do partículas, que não é abordada nesta ficha. 4. Exercícios teóricos e de programação Exercício 1. Após fazer o download do projeto ParticleSystem, vamos primeiramente implementar o sistema de partículas simples para explosões, através da finalização das classes Particle.java e ParticleSystem.java, na diretoria “physics/particleSystem/explosion”. Uma partícula (classe Particle.java) tem uma posição, uma velocidade, uma aceleração, um tamanho, uma cor, uma idade, e um tempo máximo de vida. Nesta classe falta implementar dois métodos: 1. public void update(); 2. public boolean isDead(); O método update() consiste em atualizar para uma determinada partícula a sua a posição, velocidade, aceleração, tamanho, cor, e idade. O método isDead() serve apenas para verificar para uma determinada partícula se esta atingiu o seu tempo de vida máximo permitido. Cada partícula é desenhada como um ponto colorido numa determinada na posição espacial que esta ocupa. Após concluída a implementação da classe Particle.java. É necessário concluir a implementação da classe ParticleSystem.java. Nesta classe apenas é necessário completar o método: 1. public void update(); Este método consiste em atualizar as partículas existentes no sistema de partículas, e remover todas as partículas que tenham falecido. Dica: Como em fichas anteriores em todas as classes do motor de particulas simples a completar existem instruções, nos “Action Items” do Netbeans, do tipo “TODO: (ParticleSystemExplosion) ...”. Se o sistema estiver implementado corretamente, neste momento aquando o aluno correr a aplicação, a cada clique do botão direito do rato um sistema de partículas será criado relativamente perto do cursor do rato dentro da janela da aplicação. Visualmente será visto um efeito simplista que aparenta ser uma explosão. De notar que se forem feitos cliques de rato repetidos com alguma rapidez, vão ser criados vários sistemas de partículas e não apenas um. Exercício 2. O exercício 2 consiste em implementar o sistema de partículas complexo. As alterações necessárias apenas serão realizadas na classe Particle.java, na diretoria “physics/particleSystem/SPH”. É primeiramente necessário alterar a classe principal do projeto, i.e., clicar com o botão direito do rato no projeto no Netbeans, Properties, run, em “Main Class:”, browse e substituir o ui.GameRendererExplosion por ui.GameRendererSPH. De seguida é necessário implementar alguns métodos descritos em cada um dos “Action Items” do Netbeans, do tipo “TODO: (ParticleSystemSPH) ...”. É de referir que os algoritmos estão explicados passo a passo, mas para uma adicional perceção no que cada método faz é sugerido uma consulta aos links: http://zeus.mat.puc-rio.br/tomlew/pdfs/lucas_wuw.pdf http://www.essentialmath.com/GDC2010/VanVerth_Fluids10.pdf Se o sistema de partículas complexo estiver implementado corretamente, neste momento aquando o aluno correr a aplicação, irá visualizar o sistema a evoluir, como ilustrado na Fig.4: Figura 4: Simulação de líquidos utilizando SPH, em 2D, sem reconstrução, com partículas do tipo sólido (rosa) e liquido (azuis). Exercício 3. O exercício 3 consiste em alterar as condições iniciais da simulação, i.e., a quantidade de partículas inicial e a posição destas. Para ser possível realizar este exercício é necessário alterar o método reset(), na classe ParticleSystem.java, na diretoria “physics/particleSystem/SPH”. Fica a critério do aluno as alterações a realizar. Apenas é necessário que seja outro cenário, e.g., areia (fluido) a cair de uma ampulheta, sendo as paredes um V de partículas do tipo obstáculo sólido ou boundingParticles. Exercício 4. Vamos agora avaliar os conhecimentos, adquiridos pelo aluno, no decorrer da resolução da componente prática desta ficha, recorrendo a algumas questões teóricas: 1. Suponha um jogo em que um sistema de partículas representava uma parede, e cada partícula, um tijolo ou porção da parede. Se a parede fosse destruída, apesar de não implicar a destruição/morte de todas as partículas, porque razão é comum o sistema ser removido após a destruição da parede? Justifique. 2. É possível tornar mais eficiente o desenho de partículas em ambos os sistemas implementados? Justifique. 3. Porque razão o sistema de simulação complexo implementado seria inapropriado para simular oceanos? 4. Que adições teriam de ser feitas ao sistema de simulação complexo implementado para este simular cascatas? 5. Trabalho futuro Se o aluno tiver um projeto de sistemas de partículas, neste momento pode começar a a debruçar-se sobre o dito projeto. O aluno deverá implementar ou uma explosão mais correta fisicamente. Para gerar uma explosão mais complexa será necessário recorrer a texturas para um efeito mais realista, i.e., a textura deverá ser usada em função ou da distancia da partícula à sua posição inicial ou da sua idade. A combustão também será algo a introduzir, i.e., a mudança de tipo de gás ao longo do tempo. Dito de outra forma de mais quente para mais frio até passar a ser fumo. Finalmente, fazer explodir algo, ou, a explosão aplicada a uma geometria. Isto exige algum tipo de mapeamento entre partícula e triângulo, podendo uma partícula ser um triângulo. De ter em atenção que a explosão de um objeto é um sistema conservativo, i.e., nada se perde tudo se transforma. Ou seja se um carro explodir parte dele vai ser consumido na explosão e posterior incêndio, mas parte da sua massa ficará intacta ainda que deformada. Além do projeto existem algumas expansões ao JMOGE que findada esta ficha podem ser alvo de estudo, algumas a titulo de sugestão: 1. Paralelizar, via multithreading em Java, um dos sistemas de partículas implementados. 2. As partículas podiam ter uma idade fixa, e o sistema corresponder a um objeto na cena, e.g., uma parede de tijolos, e o sistema permitira um objeto fragmentário. 3. Um simulador de fluidos com tipos distintos de líquidos.