Diferenças
Aqui você vê as diferenças entre duas revisões dessa página.
c:visualizacao_de_modelos_3d [2023/08/01 19:13] – criada maziero | c:visualizacao_de_modelos_3d [2023/08/01 19:29] (atual) – edição externa 127.0.0.1 | ||
---|---|---|---|
Linha 1: | Linha 1: | ||
+ | ====== Visualização de Modelos 3D ====== | ||
+ | |||
+ | {{ animation.gif |}} | ||
+ | |||
+ | Este projeto consiste em construir um programa para ler uma descrição de objeto em 3 dimensões de um arquivo em disco e apresentar na tela a visualização desse objeto, considerando uma projeção em perspectiva. | ||
+ | |||
+ | Os requisitos do projeto são: | ||
+ | |||
+ | * Ler a descrição de objeto 3D de um arquivo em disco. O objeto está descrito no formato //Wavefront OBJ//, usado em ferramentas de modelagem/ | ||
+ | * Calcular a projeção em perspectiva dos vértices e arestas do objeto. | ||
+ | * Mostrar em uma janela gráfica a projeção obtida com representação // | ||
+ | * Usar as teclas de setas // | ||
+ | * Usar a tecla " | ||
+ | |||
+ | A seguir serão apresentados mais detalhes sobre cada um desses requisitos. | ||
+ | |||
+ | ===== Formato Wavefront OBJ ===== | ||
+ | |||
+ | O formato de dados [[https:// | ||
+ | |||
+ | Nesse tipo de arquivo, os dados do objeto são representados em formato ASCII. Os dados com representação mais frequente são os // | ||
+ | |||
+ | * um **vértice** é um ponto no espaço, com coordenadas (x, y, z) em ponto flutuante. | ||
+ | * uma **face** é uma sequência de 3 ou mais vértices que define uma superfície. | ||
+ | |||
+ | Um exemplo simples de objeto 3D no formato OBJ: | ||
+ | |||
+ | <code obj cubo.obj> | ||
+ | # OBJ - Wavefront object file | ||
+ | # Esta linha contém um comentário | ||
+ | |||
+ | # definição dos vértices (coordenadas x y z) | ||
+ | # números podem ser inteiros ou reais | ||
+ | v 16 32 16 # definição do vértice v1 | ||
+ | v 16 32 -16 # definição do vértice v2 | ||
+ | v 16 0 16 # ... | ||
+ | v 16 0 -16 | ||
+ | v -16 32 16 | ||
+ | v -16 32 -16 | ||
+ | v -16 0 16 | ||
+ | v -16 0 -16 | ||
+ | |||
+ | # definição das faces | ||
+ | f 1 3 4 2 # face f1: v1 -> v3 -> v4 -> v2 -> v1 | ||
+ | f 6 8 7 5 | ||
+ | f 2 6 5 1 | ||
+ | f 3 7 8 4 | ||
+ | f 1 5 7 3 | ||
+ | f 4 8 6 2 | ||
+ | </ | ||
+ | |||
+ | Além dos vértices e faces, o formato OBJ também permite definir linhas, pontos, normais, texturas e outros elementos importantes em um modelo 3D. | ||
+ | |||
+ | <note important> | ||
+ | Neste projeto, somente precisam ser tratadas as declarações de vértices e faces. As demais declarações (vn, vt, l, etc) podem ser ignoradas. | ||
+ | </ | ||
+ | |||
+ | Mais exemplos de objetos 3D estão disponíveis a seguir: | ||
+ | |||
+ | * {{spike.obj|Pirâmide}} (5 vértices, 5 faces) | ||
+ | * {{cube.obj|Cubo}} (8 vértices, 6 faces) | ||
+ | * {{dodecahedron.obj|Dodecaedro}} (20 vértices, 36 faces) | ||
+ | * {{teapot.obj|Bule}} (822 vértices, 1600 faces) | ||
+ | * {{skeleton.obj|Esqueleto}} (8338 vértices, 16034 faces) | ||
+ | * {{bunny.obj|Coelho}} (34834 vértices, 69451 faces) | ||
+ | |||
+ | Esses arquivos podem ser facilmente visualizados no Linux através do programa '' | ||
+ | |||
+ | ===== Projeção em perspectiva ===== | ||
+ | |||
+ | A técnica de [[https:// | ||
+ | |||
+ | Existem vários tipos de projeção, como a projeção ortográfica e a projeção em perspectiva. Na projeção em perspectiva, | ||
+ | |||
+ | ==== Perspectiva fraca ==== | ||
+ | |||
+ | Os cálculos necessários à projeção podem ser complexos e demorados, mas algumas simplificações podem ser realizadas. Este projeto usa uma simplificação chamada // | ||
+ | |||
+ | Considerando que as coordenadas da câmera são [x< | ||
+ | |||
+ | * x< | ||
+ | |||
+ | * y< | ||
+ | |||
+ | Assim é obtida uma coleção de pontos [x< | ||
+ | |||
+ | ==== Conversão para coordenadas de tela ==== | ||
+ | |||
+ | Para que os pontos obtidos na etapa anterior possam ser plotados na tela, eles devem primeiro ser ajustados para o intervalo [(0,0) ... (//width//, // | ||
+ | |||
+ | Esta etapa transforma o o conjunto de pontos projetados [x< | ||
+ | |||
+ | **Passo 1**: calcular mínimos, máximos, centros e diferenças das coordenadas em X e Y | ||
+ | |||
+ | * x< | ||
+ | * x< | ||
+ | * x< | ||
+ | * x< | ||
+ | |||
+ | * y< | ||
+ | * y< | ||
+ | * y< | ||
+ | * y< | ||
+ | |||
+ | **Passo 2**: calcular fator de escala para o desenho na tela | ||
+ | |||
+ | * W: largura da janela de desenho (em pixels) | ||
+ | * H: altura | ||
+ | * esc< | ||
+ | * esc< | ||
+ | * escala = min (esc< | ||
+ | |||
+ | **Passo 3**: centrar pontos da projeção em [0 0] | ||
+ | |||
+ | * ∀ (x y) | ||
+ | * x'< | ||
+ | * y'< | ||
+ | |||
+ | **Passo 4**: ajustar escala dos pontos da projeção para a tela | ||
+ | * ∀ (x y) | ||
+ | * x"< | ||
+ | * y"< | ||
+ | |||
+ | **Passo 5**: ajustar pontos do desenho em relação ao centro da tela | ||
+ | |||
+ | * ∀ (x y) | ||
+ | * x< | ||
+ | * y< | ||
+ | |||
+ | <note tip> | ||
+ | Os passos 3 a 5 podem ser condensados em um único passo: | ||
+ | |||
+ | * ∀ (x y) | ||
+ | * x< | ||
+ | * y< | ||
+ | </ | ||
+ | |||
+ | Com isso é obtido um conjunto de pontos no intervalo [(0, 0) .. (//width//, // | ||
+ | |||
+ | ===== Atividade ===== | ||
+ | |||
+ | Para apresentar a visualização de um objeto 3D, o programa deve: | ||
+ | |||
+ | - Ler o conjunto de vértices e faces do arquivo de entrada | ||
+ | - Modelos grandes podem conter milhões de vértices, portanto o uso de alocação dinâmica de memória é obrigatório. | ||
+ | - Para tratar os dados do arquivo OBJ, sugere-se usar a função '' | ||
+ | - Para uma dada posição da câmera, calcular as projeções 2D dos vértices 3D. | ||
+ | - Converter os pontos projetados para coordenadas de tela; sugere-se usar uma janela de 800×600 pixels. | ||
+ | - Desenhar as faces na tela, produzindo uma representação // | ||
+ | - Ler as teclas de setas (← → ↑ ↓), ajustar as coordenadas da câmera, recalcular a projeção e desenhá-la novamente. | ||
+ | - Tecla ESC (ou fechar a janela) para sair do programa. | ||
+ | |||
+ | Formas de chamada do executável (**ambas** devem ser implementadas): | ||
+ | |||
+ | # usando argc/argv | ||
+ | wireframe arquivo.obj | ||
+ | | ||
+ | # usando stdin | ||
+ | wireframe < arquivo.obj | ||
+ | # ou | ||
+ | cat arquivo.obj | wireframe | ||
+ | |||
+ | A implementação deve atender os seguintes requisitos: | ||
+ | |||
+ | * Usar as funções da biblioteca gráfica indicada pelo professor | ||
+ | * Usar '' | ||
+ | * Alocar memória para os elementos do modelo de forma dinâmica ('' | ||
+ | * Funcionar para **todos** os exemplos disponíveis nesta página | ||
+ | * Estrutura **sugerida** de arquivos do código-fonte: | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * '' | ||
+ | * ... (se necessário) | ||
+ | * Usar '' | ||
+ | * cláusulas '' | ||
+ | * usar flag de compilação '' | ||
+ | * separar as fases de compilação e de ligação | ||
+ | * **usar regras implícitas** | ||
+ | |||
+ | Bônus (+ 20/100 pontos cada): | ||
+ | * Usar o mouse para girar o objeto na tela | ||
+ | * Usar perspectiva completa ao invés da perspectiva fraca | ||
+ | |||
+ | O que deve ser entregue ao professor: | ||
+ | * arquivos '' | ||
+ | * arquivo '' | ||
+ | * **não enviar** os arquivos OBJ de teste | ||
+ | |||
+ | ===== Estruturas de dados sugeridas ===== | ||
+ | |||
+ | As estruturas mais adequadas para este projeto são vetores de elementos (de pontos 3D, de pontos 2D, de retas, etc). Como o número de elementos não é fixo, esses vetores devem ser alocados dinamicamente. Entretanto, o número de elementos só é conhecido ao final da leitura do arquivo OBJ, por isso não é possível alocar cada vetor com seu tamanho final desde o início do programa. | ||
+ | |||
+ | A estratégia recomendada para esse problema é fazer uma alocação inicial e aumentá-la conforme a necessidade (usando a chamada '' | ||
+ | |||
+ | /* | ||
+ | |||
+ | O pseudocódigo a seguir ilustra a definição e alocação do vetor de pontos 3D: | ||
+ | |||
+ | <code c> | ||
+ | // define um ponto 3D | ||
+ | typedef struct | ||
+ | { | ||
+ | float x, y, z ; | ||
+ | } ponto3d_t ; | ||
+ | |||
+ | // tamanho do bloco de alocação | ||
+ | #define TAM_BLOCO 1000 | ||
+ | |||
+ | // definição do vetor de pontos 3D | ||
+ | ponto3d_t p3d[] = NULL; // ponteiro para vetor de pontos 3D | ||
+ | int num_pontos3d = 0 ; // número de pontos 3D | ||
+ | int max_pontos3d = 0 ; // número máximo de pontos 3D | ||
+ | |||
+ | ... | ||
+ | |||
+ | // após ler um ponto 3D do arquivo OBJ | ||
+ | |||
+ | // se for necessário, | ||
+ | if (num_pontos3d >= max_pontos3d) | ||
+ | { | ||
+ | // adiciona TAM_BLOCO elementos ao tamanho do vetor | ||
+ | max_pontos3d += TAM_BLOCO ; | ||
+ | p3d = realloc (p3d, max_pontos3d * sizeof (ponto3d_t)) ; | ||
+ | if (!p3d) | ||
+ | { | ||
+ | // erro: realloc falhou | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // guarda o ponto lido (primeiro ponto é p3d[1]) | ||
+ | num_pontos3d++ ; | ||
+ | p3d[num_pontos3d].x = valor lido de x ; | ||
+ | p3d[num_pontos3d].y = valor lido de y ; | ||
+ | p3d[num_pontos3d].z = valor lido de z ; | ||
+ | </ | ||
+ | |||
+ | */ | ||
+ | |||
+ | ===== A biblioteca SDL ===== | ||
+ | |||
+ | Existe uma infinidade de bibliotecas gráficas; entre as mais populares está a biblioteca SDL (// | ||
+ | |||
+ | <note important> | ||
+ | Recomenda-se usar SDL 2, a versão mais recente da biblioteca. Tome cuidado, pois existem muitos exemplos e tutoriais na Internet que usam versões mais antigas da SDL, incompatíveis com a versão atual. | ||
+ | </ | ||
+ | |||
+ | Documentação e tutoriais sobre SDL: | ||
+ | |||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[http:// | ||
+ | |||
+ | Instalação da biblioteca SDL 2 em Linux (Ubuntu, Mint, Debian): | ||
+ | |||
+ | < | ||
+ | sudo apt-get install libsdl2-dev | ||
+ | </ | ||
+ | |||
+ | Arquivos de cabeçalho necessários: | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | </ | ||
+ | |||
+ | Flags de compilação: | ||
+ | | ||
+ | LDLIBS = -lSDL2 | ||
+ | |||
+ | ===== A biblioteca Allegro ===== | ||
+ | |||
+ | A biblioteca gráfica [[http:// | ||
+ | |||
+ | Algumas de suas características: | ||
+ | |||
+ | * multiplataforma: | ||
+ | * pode ser usada em C e outras linguagens | ||
+ | * usa aceleração gráfica (através de OpenGL ou DirectX) | ||
+ | * manipulação de áudio e vídeo | ||
+ | * leitura de mouse, teclado e joystick | ||
+ | |||
+ | Instalação da biblioteca Allegro 5 em Linux (Ubuntu, Mint, Debian): | ||
+ | |||
+ | < | ||
+ | sudo apt-get install liballegro5-dev | ||
+ | </ | ||
+ | |||
+ | Arquivos de cabeçalho necessários (mínimo, depende dos módulos usados): | ||
+ | |||
+ | <code c> | ||
+ | #include < | ||
+ | </ | ||
+ | |||
+ | Flags de compilação (idem): | ||
+ | |||
+ | LDLIBS = -lallegro | ||