IA725 - Computação Gráfica
Nomes:
Honório Gomes RA: 991880 ( hgomes@fee.unicamp.br )
Leonardo Rocha RA: 006092 (
leorocha@dca.fee.unicamp.br )
Professora: Wu Shin
Ting (
ting@dca.fee.unicamp.br )(DCA/ FEEC/ UNICAMP).
Este trabalho faz parte das atividades práticas da disciplina
"Computação Gráfica" (IA725) lecionada no curso de
pos-graduação da Faculdade
de Engenharia Elétrica e de Computação da Universidade Estadual de Campinas
(UNICAMP).
O objetivo é a construção de um jogo de "Batalha
Naval" renderizado em uma cena tridimensional tridimensional utilizando
a linguagem " OpenGL".
Este projeto é composto de três etapas.
Esta proposta foi desenvolvida da seguinte forma.
1° ETAPA (Modelos em wireframe)
Devido a grande dificuldade em reproduzir modelos próximos aos
reais , decidimos utilizar um programa para converter modelos escritos
em programas de desenho vetorial em uma lista de vértices. Estes
vértices (bem como outras informações úteis,
normal, cor, ...) então foram inseridos em estruturas de dados,
onde poderiam ser facilmente manipulados.
Buscando por modelos para utilizar no projeto, encontramos um tutorial
em GameDev.Net que ensinava a
tratuzir modelos escritos no 3D Studio (*.3ds) em uma
descrição OpenGL. Este tutorial incluia um programa
exemplo( que utilizamos como base para o desenvolvimento de nosso jogo)
escrito em C++ e utilizando a bibloteca SDL.
Foram escolhidos 4 modelos para serem utilizados: bote salva vidas;
submarino; porta-aviões; destroier.
O ponto chave desta tradução pode ser visto no main.h,
onde temos definidas as classes t3DObjetc, t3DModel, que irão
armazenar as informações contidas em um único
modelo.
Observando o tutorial que está contido nestes arquivos, podemos
perceber que os modelos são "montados" com a junção
de faces triangulares, sendo cada seqüência de três
vértices formando uma destas faces.
A grande tarefa de traduzir este modelo e inserí-lo em objetos
destas classes é feita pelos métodos da classe CLoad3DS
(definida em 3ds.h).
Esta classe possui diversos métodos para executar o
tradução do modelo, bem como interpretar
informções de cor e textura.
Uma vez interpretado e carregado, torna-se simples a
maniplulação dos vértices contidos do modelo
contido em um objeto t3DModel, pois dentro dele (considerando que um que
esta classe tem diversos objetos t3DObject) eles podem ser lidos como o
conteúdo de um vetor, que cada tres posições
simbolizam uma face triangular.
assim para renderizar o modelo por completo, bastaria utilizar o
seguinte loop:
for(cada modelo){
//Transformações
geométricas para o posicionamento.
glBegin(GL_TRIANGLES);
for(número de objetos){
for(número de faces do
objeto){
for(3
vezes o número de faces){
glNormal3f(normal_no_ponto);
glVertex4f(ponto , escala);
}
}
}
glEnd();
}
Além disso, pensando em um jogo tradicional
de batalha naval os barcos ficam dispostos na posição
vertical ou horizontal em um tabuleiro. Por isso é renderizado um
tabuleiro com células quadradas em um plano paralelo ao plano
que futuramente serão "desenhado" os barcos.
Como resultado podemos ter a seguinte cena:
Uma vez
posicionados os barcos, é necessário construir estruturas
ara controlar o posicionamento da câmera.
Como o programa base utilizado para construir este
jogo utilizava a biblioteca SDL para construir um ambiente onde os
comandos OpenGL pudessem ser utilizados nativamente, decidimos utilizar
a estruturas estruturas de tratamento de evento disponíveis nesta
biblioteca.
Então uma maneira eficiente de reposicionar a
câmera em relação a cena formada seria fazer com que
ela acompanhasse o movimento do mouse (evento SDL_MOUSEMOTION). Na captura
deste evento obtemos duas informações importantes, as
variações relativas nos eixos "x" e "y" (xrel e yrel)
representadas pro números inteiros de 16 bits.
Além do movimento da câmera devemos
definir qual a sua distância em relação a cena. Por
isso definimos o lugar geométrico das posições que
a câmera pode assumir um espaço esférico em torno do
tabuleiro.
Para facilitar a implementação fizemos
com que a câmera apontasse para o centro do tabuleiro, assim sua
posição poderia ser determinada por coordenadas
esféricas (r, theta, phi) em que o zoom (tamanho do raio) pode
ser controlado através das teclas "+" e "-" do teclado
alfanumérico (evento SDL_KEYDOWN).
Então a cada atualização da posição
da câmera deve-se chamar o comando:
gluLookAt(XCentro +
r*cos(theta)*sin(phi), YCentro + r*sin(theta)*sin(phi), r*cos(phi)
, 0, 0,0 , vetor_normal );
Por último deveria ser implementada a
interface em que o jogador escolheria a posição onde
atirar.
Nesta primeira etapa estes dados deveriam ser
obitdos através do teclado, o que inicialmente esta
obrigação gerava um problema, pois toda vez que o programa
esperava o jogador escolher a posição do tabuleiro que
qeria atacar, a cena deixava de ser renderizada.
Isto foi resolvido dividindo em
funções separadas a renderização e a
ação do jogador e fazendo com que o programa principal os
chamasse em "threads" diferentes que compartilham as variáveis de
posiconamento na tela, sendo estas acessadas com um esquema de
exclusão mútua.
Por fim, restava sinalizar ao jogador quando sua
tentativa tinha exito. Para isto será utilizado uma
seqüência de imagens (bitmaps) para simular uma
explosão na célula que contém uma parte de algum
dos barcos. Esta seqüência seria:
Assim uma possível cena durante o jogo seria:
2° ETAPA (Mudança de Cenário e Tonalização)
Nesta etapa, os modelos do jogo e o
cenário são tonalizados com o
modelo Gouraud. Além da tonalização,
vários modelos receberam texturas. Em alguns casos o
número de triângulos foi reduzido para
aumentar o desempenho. Sob o grid foi desenhado
outro grid com
a textura da água , e esta mapeada em cada quadrado de forma que simula
o movimento das ondas. Para aumentar o
realismo, o grid da água também
faz um movimento ondulatório, mostrando o movimento de
subida e descida das ondas.
A simulação da
iluminação do dia e da noite é feita através
da alteração das propriedades da fonte de luz. Os
parâmetros GL_AMBIENT, GL_DIFFUSE e GL_SPECULAR são os
seguintes para o cenário de dia, sob luz do sol:
3° ETAPA (Texturização)
Para usar esta
funcão corretamente, primeiro muda-se temporariamente o modo de
rasterização para GL_SELECT com
Para determinar qual a posição selecionada, cada quadrado
do tabuleiro é rotulado com um índice, que corresponde
à sua posição no vetor de pontos, através
das funções:
Figuras:
Download do código completo: bship_v3.tar.gz