Ferramentas do usuário

Ferramentas do site


prog2:visualizacao_de_modelos_3d

Diferenças

Aqui você vê as diferenças entre duas revisões dessa página.

Link para esta página de comparações

Próxima revisão Ambos lados da revisão seguinte
prog2:visualizacao_de_modelos_3d [2019/01/31 17:34]
127.0.0.1 edição externa
prog2:visualizacao_de_modelos_3d [2019/04/09 13:41]
maziero
Linha 1: Linha 1:
 +====== Visualização de Modelos 3D ======
 +
 +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/​visualização 3D como //​Blender//,​ //​3Dstudio//​ e //Rhino//.
 +  * 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 //​[[https://​en.wikipedia.org/​wiki/​Wire-frame_model|wireframe]]//,​ usando uma biblioteca gráfica.
 +  * Usar as teclas de setas //​left/​right//​ e //up/down// para mudar a posição do observador nos eixos X e Y, respectivamente,​ recalculando a projeção a cada mudança de posição.
 +  * Usar a tecla "​ESC"​ ou "​q"​ para sair do programa.
 +
 +A seguir serão apresentados mais detalhes sobre cada um desses requisitos.
 +
 +===== Formato Wavefront OBJ =====
 +
 +O formato de dados [[https://​en.wikipedia.org/​wiki/​Wavefront_.obj_file|Wavefront OBJ]] é considerado um "​formato universal"​ para a representação de objetos em 3 dimensões, sendo reconhecido pela maioria dos softwares de modelagem/​visualização em 3D.
 +
 +Nesse tipo de arquivo, os dados do objeto são representados em formato ASCII. Os dados com representação mais frequente são os //​vértices//​ e as //faces//:
 +
 +  * 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
 +
 +# v <x> <y> <​z> ​ - Define um vértice do objeto (podem ser int ou float)
 +v 16 32 16
 +v 16 32 -16
 +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 (v1 v2 v3 v4 ...)
 +f 1 3 4 2
 +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
 +</​code>​
 +
 +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 podem ser ignoradas.
 +</​note>​
 +
 +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 ''​g3dviewer'',​ ou neste [[https://​a360.autodesk.com/​viewer |visualizador online]] (ou [[http://​3dviewer.net/​|neste]]).
 +
 +===== Projeção em perspectiva =====
 +
 +A técnica de [[https://​en.wikipedia.org/​wiki/​3D_projection|projeção 3D]] consiste em transformar uma representação 3D em 2D, ou seja, com todos os seus pontos em um mesmo plano, possibilitando então sua visualização na tela do computador.
 +
 +Existem vários tipos de projeção, como a projeção ortográfica e a projeção em perspectiva. Na projeção em perspectiva,​ a posição do observador é considerada nos cálculos da transformação 3D-2D. Uma boa explicação da projeção em perspectiva pode ser encontrada [[http://​www.scratchapixel.com/​lessons/​3d-basic-rendering/​computing-pixel-coordinates-of-3d-point|neste site]].
 +
 +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 //​perspectiva fraca// (//weak perspective//​),​ descrita a seguir.
 +
 +==== Perspectiva fraca ====
 +
 +Considerando que as coordenadas da câmera são [x<​sub>​c</​sub>​ y<​sub>​c</​sub>​ z<​sub>​c</​sub>​] e que a câmera está olhando para a origem [0 0 0], a conversão das coordenadas 3D de cada vértice v = [x<​sub>​v</​sub>​ y<​sub>​v</​sub>​ z<​sub>​v</​sub>​] em sua projeção 2D p = [x<​sub>​p</​sub>​ y<​sub>​p</​sub>​] no plano z = 0 pode ser calculada desta forma:
 +
 +  * x<​sub>​p</​sub>​ = x<​sub>​c</​sub>​ + z<​sub>​c</​sub>​ × ( (x<​sub>​v</​sub>​ - x<​sub>​c</​sub>​) ÷ (z<​sub>​v</​sub>​ + z<​sub>​c</​sub>​) )
 +
 +  * y<​sub>​p</​sub>​ = y<​sub>​c</​sub>​ + z<​sub>​c</​sub>​ × ( (y<​sub>​v</​sub>​ - y<​sub>​c</​sub>​) ÷ (z<​sub>​v</​sub>​ + z<​sub>​c</​sub>​) )
 +
 +Assim é obtida uma coleção de pontos [x<​sub>​p</​sub>​ y<​sub>​p</​sub>​] que representa os vértices do objeto projetados no plano z=0.
 +
 +==== 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//, //​height//​)],​ onde //width// e //height// são as dimensões da janela de visualização,​ em pixels.
 +
 +Esta etapa transforma o o conjunto de pontos projetados [x<​sub>​p</​sub>​ y<​sub>​p</​sub>​] em um conjunto de pontos de desenho [x<​sub>​d</​sub>​ y<​sub>​d</​sub>​],​ que podem ser usados para plotar as arestas dos objetos na tela.
 +
 +**Passo 1**: calcular mínimos, máximos, centros e diferenças das coordenadas em X e Y
 +
 +  * x<​sub>​min</​sub>​ = min (x<​sub>​p</​sub>​)
 +  * x<​sub>​max</​sub>​ = max (x<​sub>​p</​sub>​)
 +  * x<​sub>​cen</​sub>​ = (x<​sub>​max</​sub>​ + x<​sub>​min</​sub>​) / 2
 +  * x<​sub>​dif</​sub>​ = x<​sub>​max</​sub>​ - x<​sub>​min</​sub>​
 +
 +  * y<​sub>​min</​sub>​ = min (y<​sub>​p</​sub>​)
 +  * y<​sub>​max</​sub>​ = max (y<​sub>​p</​sub>​)
 +  * y<​sub>​cen</​sub>​ = (y<​sub>​max</​sub>​ + y<​sub>​min</​sub>​) / 2
 +  * y<​sub>​dif</​sub>​ = y<​sub>​max</​sub>​ - y<​sub>​min</​sub>​
 +
 +**Passo 2**: calcular fator de escala para o desenho na tela
 +
 +  * W: largura da janela de desenho (em pixels)
 +  * H: altura ​ da janela de desenho (em pixels)
 +  * esc<​sub>​x</​sub>​ = W / x<​sub>​dif</​sub>​
 +  * esc<​sub>​y</​sub>​ = H / y<​sub>​dif</​sub>​
 +  * escala = min (esc<​sub>​x</​sub>,​ esc<​sub>​y</​sub>​)
 +
 +**Passo 3**: centrar pontos da projeção em [0 0]
 +
 +  * ∀ (x y)
 +    * x'<​sub>​p</​sub>​ = x<​sub>​p</​sub>​ - x<​sub>​cen</​sub>​
 +    * y'<​sub>​p</​sub>​ = y<​sub>​p</​sub>​ - y<​sub>​cen</​sub>​
 +
 +**Passo 4**: ajustar escala dos pontos da projeção para a tela
 +  * ∀ (x y)
 +    * x"<​sub>​p</​sub>​ = x'<​sub>​p</​sub>​ * escala
 +    * y"<​sub>​p</​sub>​ = y'<​sub>​p</​sub>​ * escala
 +
 +**Passo 5**: ajustar pontos do desenho em relação ao centro da tela
 +
 +  * ∀ (x y)
 +    * x<​sub>​d</​sub>​ = x"<​sub>​p</​sub>​ + W / 2
 +    * y<​sub>​d</​sub>​ = y"<​sub>​p</​sub>​ + H / 2
 +
 +Os passos 3 a 5 podem ser condensados em um único passo:
 +
 +  * ∀ (x y)
 +    * x<​sub>​d</​sub>​ = ( (x<​sub>​p</​sub>​ - x<​sub>​cen</​sub>​) * escala) + W / 2
 +    * y<​sub>​d</​sub>​ = ( (y<​sub>​p</​sub>​ - y<​sub>​cen</​sub>​) * escala) + H / 2
 +
 +Com isso é obtido um conjunto de pontos no intervalo [(0, 0) .. (//width//, //​height//​)] que pode ser usado para plotar na janela gráfica as arestas que definem o objeto 3D.
 +
 +===== 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 ''​strtok''​.
 +  - 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 //​wireframe//​ do objeto. Para desenhar uma face, desenhe separadamente as arestas que a compõem. Por exemplo, para desenhar a face (1 2 3 4), desenhe as arestas (1 2), (2 3), (3 4) e (4 1).
 +  - 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 ''​struct''​ para representar os elementos do modelo (vértices, faces, arestas)
 +  * Alocar memória para os elementos do modelo de forma dinâmica (''​malloc''/''​free''​)
 +  * Funcionar para **todos** os exemplos disponíveis nesta página
 +  * Estrutura **sugerida** de arquivos do código-fonte:​
 +    * ''​wireframe.c'':​ arquivo principal
 +    * ''​datatypes.h'':​ tipos de dados usados no programa
 +    * ''​objread.c/​h'':​ funções de leitura do arquivo OBJ
 +    * ''​perspect.c/​h'':​ funções de cálculo de perspectiva
 +    * ''​graphics.c/​h'':​ funções de apresentação gráfica
 +    * ... (se necessário)
 +  * Usar ''​Makefile''​
 +    * cláusulas ''​all''​ (default), ''​clean''​ e ''​purge''​
 +    * usar flag de compilação ''​-Wall''​
 +    * separar as fases de compilação e de ligação
 +    * **usar regras implícitas**
 +
 +Bônus (+2 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 ''​.c''​ e ''​.h''​
 +  * arquivo ''​Makefile''​
 +  * **não enviar** os arquivos OBJ de teste
 +
 +===== A biblioteca Allegro =====
 +
 +A biblioteca gráfica [[http://​liballeg.org/​|Allegro]] permite a manipulação de gráficos simples e áudio, sendo bem adaptada para a construção de jogos 2D. É uma biblioteca mais simples (mais limitada) que SDL, mas boa para projetos menores.
 +
 +Algumas de suas características:​
 +
 +  * multiplataforma:​ Linux, Windows, MacOS, Android, iOS
 +  * 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):
 +
 +<​code>​
 +sudo apt-get install liballegro5-dev
 +</​code>​
 +
 +Arquivos de cabeçalho necessários (mínimo):
 +
 +<code c>
 +#include <​allegro5/​allegro.h>​
 +</​code>​
 +
 +Flags de compilação (mínimo):
 +
 +  LDLIBS = -lallegro
 +
 +===== A biblioteca SDL =====
 +
 +Existe uma infinidade de bibliotecas gráficas; entre as mais populares está a biblioteca SDL (//​[[https://​www.libsdl.org/​|Simple DirectMedia Layer]]//). Além de gráficos, essa biblioteca permite a produção de sons e o gerenciamento de dispositivos de entrada/​saída (//mouse//, teclado, //​joystick//​) em várias plataformas.
 +
 +<note tip>
 +Use a função ''​lineRGBA (x1,​y1,​x2,​y2,​r,​g,​b,​a)''​ da extensão GFX/SDL para desenhar as linhas do objeto na janela gráfica. O aspecto do desenho fica melhor se ajustar o parâmetro //alpha// (''​a''​) para um valor ao redor de 100.
 +</​note>​
 +
 +Documentação e tutoriais sobre SDL/GFX:
 +
 +  * [[https://​www.libsdl.org]]
 +  * [[http://​lazyfoo.net/​SDL_tutorials/​index.php]]
 +  * [[http://​headerphile.com/​category/​sdl2/​page/​2/​]]
 +  * [[http://​www.aaroncox.net/​tutorials/​2dtutorials/​sdlshapes.html]] (GFX, bom ponto de partida)
 +  * [[http://​www.ferzkopp.net/​wordpress/​2016/​01/​02/​sdl_gfx-sdl2_gfx]] (GFX)
 +
 +A biblioteca SDL está disponível nas distribuições Linux (e também em Windows, Android e outros sistemas), nas versões 1.2 e 2.0.
 +
 +<note warning>
 +Use somente uma das versões da SDL (1.x ou 2.x), se misturar as duas versões no mesmo código poderão ocorrer erros!
 +</​note>​
 +
 +==== SDL Versão 1.2 ====
 +
 +Instalação da biblioteca SDL 1.2 e da extensão GFX em Linux (Ubuntu, Mint, Debian):
 +
 +<​code>​
 +sudo apt-get install libsdl1.2-dev libsdl-gfx1.2-dev
 +</​code>​
 +
 +Arquivos de cabeçalho necessários:​
 +
 +<code c>
 +#include <​SDL/​SDL.h>​
 +#include <​SDL/​SDL_gfxPrimitives.h>​
 +</​code>​
 +
 +Flags de compilação:​
 +
 +  LDLIBS = -lSDL -lSDL_gfx -lm
 +
 +==== SDL Versão 2.0 ====
 +
 +Instalação da biblioteca SDL 2 e da extensão GFX em Linux (Ubuntu, Mint, Debian):
 +
 +<​code>​
 +sudo apt-get install libsdl2-dev libsdl2-gfx-dev
 +</​code>​
 +
 +Arquivos de cabeçalho necessários:​
 +
 +<code c>
 +#include <​SDL2/​SDL.h>​
 +#include <​SDL2/​SDL2_gfxPrimitives.h>​
 +</​code>​
 +
 +Flags de compilação:​
 +  ​
 +  LDLIBS = -lSDL2 -lSDL2_gfx -lm
  
prog2/visualizacao_de_modelos_3d.txt · Última modificação: 2019/11/11 19:03 por maziero