Ponto V!

Home Arquitetura Programação Animação por Vértices
Bruno Crivelari Sanches
Animação por VérticesImprimir
Escrito por Bruno Crivelari Sanches
Índice do Artigo
Animação por Vértices
Uma Classe Para Carregar Modelos
Lendo Arquivo Md2
Animando e Desenhando os Modelos
Construindo um Visualizador
Todas Páginas

No artigo anterior sobre “Técnicas de Animação para jogos 3d” vimos de maneira simplificada como funcionam dois métodos de animação. Neste artigo vamos nos aprofundar no primeiro método (animação por vértices) e aprender como criar um visualizador de animações.

Usaremos como ponto de partida a estrutura de classes mostrada no artigo “Organizando a janela em classes” e criaremos novas classes para carregar modelos do formato md2.

O formato md2 foi criado para o jogo Quake II e foi bem popular na época desse jogo devido a sua simplicidade e a quantidade de jogos que utilizaram este motor.

Apesar da técnica de animação por vértices não ser comum hoje em dia em jogos para PC, ela ainda pode ser usada em maquinas onde existem limitações de hardware (celulares e outros dispositivos portáteis), ela também é interessante para se aprender conceitos básicos de animação (interpolação por exemplo) sem precisar de complicações matemáticas que as outras técnicas costuma exigir.

Formato Md2

O arquivo md2 é dividido em dois blocos principais: cabeçalho e dados. No cabeçalho temos um número magico que é usado para confirmar se o arquivo é mesmo um arquivo md2, além disso o cabeçalho contém informações sobre os dados contidos no arquivo, como número de vértices, números de quadros, etc. Na segunda parte do arquivo temos os dados do modelo.

No código abaixo vemos uma estrutura de dados em C que pode ser usada para ler o cabeçalho do arquivo:

typedef struct
{
    int ident;              // numero magico, "IDP2"
    int version;            // versao do Md2, deve ser 8

    int skinWidth;          // Largura da textura
    int skinHeight;         // Altura da textura

    int framesize;          // Tamanho em bytes de um quadro

    int numSkins;           // Numero de skins
    int numVertices;        // Numero de vertices por quadro
    int numTexCoord;        // Numero de coordenadas de textura
    int numTriangles;       // Numero de triangulos
    int numGlCmds;          // Numero de comandos opengl
    int numFrames;          // Numero de quadros

    int offsetSkins;        // offset para dados do skin
    int offsetSt;           // offset para coordenadas de textura
    int offsetTriangles;    // offset para dados do triangulo
    int offsetFrames;       // offset para os dados dos quadros
    int offsetGlCmds;       // offset para os comandos openGL
    int offsetEnd;          // offset para o final do arquivo
} Md2Header_t;

A partir deste ponto assumimos que no compilador utilizado um int tem tamanho de 4 bytes, caso seu compilador use um tamanho diferente será preciso utilizar outro tipo de dado. Outros tamanhos que são assumidos ao longo deste artigo:

  • int: 4 bytes
  • float: 4 bytes
  • char: 1 byte
  • short: 2 bytes

Após o cabeçalho do arquivo md2 temos os dados do modelo. Para melhor organizar o arquivo este é dividido em blocos e cada bloco contém um tipo de dado, como se cada bloco fosse uma tabela em um banco de dados. O cabeçalho além de nos dar informações para provar que o arquivo é mesmo um arquivo md2 fornece dados sobre cada um desses blocos, dizendo seu tamanho e sua localização dentro do arquivo.

Os primeiros quatro bytes do arquivo possuem o identificador (ou número magico) e deve ser sempre a string “IDP2”, caso o valor seja outro o arquivo não é um md2. Em seguida temos a versão do arquivo, a que utilizamos no artigo é a 8, que é a versão utilizada pelo Quake II.

Não será preciso usar todos os dados do modelo para construir o visualizador, por isso iremos considerar aqui apenas os dados que o visualizador precisa, veremos a seguir os dados que iremos considerar.

Quadros de Animação

O primeiro bloco a ser lido é o bloco que contém os dados dos quadros, este é especificado pelos campos numFrames e offsetFrames, que indicam a quantidade de quadros e a posição destes dentro do arquivo, cada quadro é representado pela estrutura abaixo:

struct Md2Frame_t
{        
    float scale[3];        // Escala do quadro
    float translate[3];    // Translação
    char name[16];     // nome do quadro
} ;

Note que cada quadro possui apenas um vetor com a escala e um vetor representando a translação do quadro, isso é usado porque os vértices do modelo são compactados e veremos mais a frente como usar esses valores para descompactar cada vértice de um quadro, outro dado relevante é o nome do quadro, que iremos usar para agrupar os quadros de uma animação. Originalmente no jogo Quake as animações eram controladas diretamente no código, para cada modelo existe um arquivo de cabeçalho C com macros indicando cada quadro de animação e estruturas de dados que juntam os quadros de cada animação.

No visualizador iremos tirar proveito do fato dos nomes serem do formato: nome??, onde nome é o nome da animação (exemplo: stand) e ?? o número do quadro, um exemplo de quadros de uma animação: stand00, stand01, stand02, stand03.

Após cada quadro temos no arquivo a seqüência de vértices deste quadro, para saber a quantidade de vértices basta consultar o campo numVertices do cabeçalho do arquivo. Cada vértice é representado pela estrutura a seguir:

typedef struct
{
    unsigned char v[3];         // Posicao compactada
    unsigned char normalIndex;  // Indice do vetor normal
} Md2Vertex_t;

O campo v armazena as coordenadas x, y e z do vértice, para descompactar uma coordenada basta multiplicar cada elemento pela escala do quadro e somar com a translação do quadro.

Comandos OpenGL

Após carregar os quadros iremos carregar os comandos OpenGL. Como o Quake II dava suporte a apenas OpenGL para renderização via hardware muitos de seus arquivos eram otimizados para uso com OpenGL. No caso dos arquivos md2 estes já vem com suporte a algumas primitivas OpenGL, nesse caso GL_TRIANGLE_STRIP e GL_TRIANGLE_FAN. O bloco de comandos é formado por um vetor de elementos de 4 bytes, podendo estes serem números inteiros ou de ponto flutuante.

Para decodificar esse bloco basta ler o primeiro valor, que vai ser sempre um inteiro. Se for um numero positivo temos um GL_TRIANGLE_STRIP, se for negativo um GL_TRIANGLE_FAN (nesse caso, devemos deixar o numero positivo). O número indica a quantidade de comandos que devemos ler, sendo que cada comando é formado por três números, os dois primeiros são as coordenadas de textura do vértice e o ultimo o índice deste vértice, este índice nos indica qual vértice do quadro atual deve ser desenhado, na imagem abaixo podemos ver os dados de um suposto modelo que contém dois conjuntos de primitivas:

Untitled



Comentários (9)
  • Vitor Almeida da Silva  - Muito bom
    avatar

    Muito completo o artigo Bruno, parabéns.

  • Bruno Crivelari Sanches
    avatar

    Obrigado Vitor!

  • Vinícius Godoy de Mendonça  - Muito bom!
    avatar

    Ótimo artigo. Eu não explicaria melhor.

    Embora a classe original tenha sido realmente do meu jogo, meu C++ anda um pouco enferrujado, e você fez ótimos links para os seus artigos.

  • Bruno Crivelari Sanches
    avatar

    eu andava enferrujado no md2, demorou um pouco para lembrar como funcionavam certas coisas, mesmo usando o seu código :).

  • Bruno Crivelari Sanches
    avatar

    Show Zé! Quem sabe agora você não anima o seu visualizador também? :)

  • Luiz França  - Obrigado
    avatar

    Fala Bruno, eu novo no ramo de games mais tenho uma pena noção.
    trabalho como editor de video para dvds muscias e estou muito interessado no ramo de games.

    muito obrigado e parabéns

  • Victor
    avatar

    Que tipos de buffer você está falando? VBO?

  • Bruno
    avatar

    Sim, esses mesmos.

Escrever um comentário
Your Contact Details:
Gravatar enabled
Comentário:
[b] [i] [u] [url] [quote] [code] [img]   
:angry::0:confused::cheer:B):evil::silly::dry::lol::kiss::D:pinch::(:shock:
:X:side::):P:unsure::woohoo::huh::whistle:;):S:!::?::idea::arrow:
Security
Por favor coloque o código anti-spam que você lê na imagem.
LAST_UPDATED2  

Busca

Linguagens

Twitter