Buscar

MATEMATICA E FISICA APLICADAS A JOGOS pdf un2


Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 29 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 29 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 29 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

MATEMÁTICA	E	FÍSICA	APLICADA	A	JOGOS
CAPI�TULO 2 – PROJETO E DESENVOLVIMENTO
DE UM JOGO DIGITAL 2D
Rodrigo Alves Costa
Introdução
A computação grá�ica passou por um crescimento fenomenal nas últimas duas décadas, evoluindo de grá�icos
2D simples a ambientes tridimensionais complexos e de alta qualidade. No entretenimento, a computação
grá�ica é amplamente utilizada em �ilmes e jogos de computador. Mais e mais �ilmes de animação estão sendo
feitos inteiramente por meio de computadores. Até mesmo �ilmes não animados dependem muito de
computação grá�ica para desenvolver efeitos especiais: basta testemunhar, por exemplo, o sucesso dos �ilmes
da saga “Star Wars”, que já começou em meados da década de 1970. O desenvolvimento de grá�icos de
computador em computadores pessoais e consoles de jogos domésticos também foi fenomenal nos últimos
anos com sistemas de baixo custo que agora são capazes de exibir milhões de pixels e imagens por segundo.
Você sabia que há, ainda, usos signi�icativos de grá�icos de computador em aplicativos cujo propósito
principal não é o entretenimento? Por exemplo, sistemas de realidade virtual são frequentemente usados para
aplicações de treinamento. A computação grá�ica é uma ferramenta indispensável para a visualização
cientı́�ica e para o design assistido por computador. Precisamos de bons métodos para exibir grandes
conjuntos de dados de maneira compreensı́vel e para mostrar os resultados de simulações cientı́�icas em larga
escala.
A arte e a ciência da computação grá�ica vêm se desenvolvendo desde o advento dos computadores, e
começaram a valer no inı́cio dos anos 1960. Desde então, tornou-se um campo rico, profundo e coerente. O
objetivo deste capı́tulo é apresentar os fundamentos matemáticos do desenvolvimento de jogos e da
computação grá�ica, juntamente com uma introdução prática à programação usando o OpenGL. Acreditamos
que a compreensão da base matemática é importante para qualquer uso avançado de computação grá�ica e,por
esse motivo, este capı́tulo tenta cobrir a matemática subjacente à computação grá�ica. O princı́pio que guia a
seleção de conteúdo para este capı́tulo foi escolher tópicos de importância prática para pro�issionais de
computação grá�ica, em particular para desenvolvedores de software. Nossa intenção é que o conhecimento
aqui contido sirva como uma introdução abrangente às ferramentas padrão usadas em computação grá�ica e,
especialmente, à teoria matemática por trás dessas ferramentas.
2.1 Orientações
E� altamente recomendável que você tente executar os programas descritos aqui e que escreva alguns
programas OpenGL, conforme recomendado nas atividades práticas. O OpenGL é uma API independente de
plataforma (interface de programação de aplicativos) para renderização de grá�icos 3D. Uma grande vantagem
do uso do OpenGL é que ele é um padrão do setor amplamente suportado.
Outros ambientes 3D, principalmente, o Direct3D, da Microsoft, e o Metal, da Apple, têm recursos
semelhantes. No entanto, eles são especı́�icos para os sistemas operacionais Windows e Macintosh.
Este capı́tulo apresenta trechos de código dos programas C ++ usando os recursos do OpenGL. Todos esses
programas usam o estilo de programação OpenGL "moderno" e não o OpenGL antigo, que usavam o chamado
"modo imediato". Todos os programas OpenGL incluem código-fonte completo e são acompanhados por
VOCÊ QUER LER?
A tecnologia Computer	 Graphic	 Imagery (CGI), ou seja, imagens geradas por
computador, vem sendo utilizada há décadas pela indústria cinematográ�ica. No artigo
“O que é CGI e computação grá�ica?”, você poderá aprender mais a repeito da história
dessa interessante área de conhecimento. Leia o artigo completo em:
https://canaltech.com.br/software/O-que-e-CGI-e-computacao-gra�ica/.
VOCÊ SABIA?
Há vários anos, a API voltada para jogos que dominou o mercado foi o Directx, mas
ainda continua assim? A API, proprietária Directx, dominou o mercado durante
muitos anos, sempre à frente de concorrentes como o OpenGL, mas isto foi
mudando. Atualmente a OpenGL é a opção do mercado pro�issional de animação,
servindo como padrão para jogos de smartphones, sendo uma plataforma de
código aberto de uso genérico, diferente do Directx.
explicações, as quais documentam os recursos do código linha por linha. A programação em OpenGL pode ser
complexa, mas espera-se que essa estrutura lhe proporcione uma introdução direta e acessı́vel à programação
do OpenGL.
Os softwares disponibilizados por meio deste curso podem ser usado sem nenhuma restrição, exceto em
produtos comerciais. Seu uso em projetos substanciais não comerciais também deve ser reconhecido.
O OpenGL SuperBible (HILL, 2001) é uma introdução tutorial do OpenGL no tamanho de um livro. Para fontes
mais o�iciais, há o OpenGL	Programming	Guide e o OpenGL	Shading	Language	Book (HILL, 2001) escrito por
alguns dos desenvolvedores do OpenGL. Esses dois últimos livros podem ser difı́ceis de ler para o iniciante.
Qualquer que seja a fonte usada, ela deve abranger o OpenGL versão 3.3 ou posterior.
Finalmente, talvez não seja necessário mencionar, mas a Internet é um recurso indispensável, uma vez que há
muitas informações on-line sobre o OpenGL. De fato, é recomendável que, ao ler o livro, fazer uma pesquisa
na Internet para cada comando OpenGL encontrado.
VOCÊ QUER LER?
A API OpenGL é muito útil para os desenvolvedores de jogos, sendo constituıd́a de
bibliotecas grá�icas que agilizam a criação de formas e cenários, facilitando a atividade
de programar. Existem muitas fontes disponıv́eis para aprender o OpenGL, sendo uma
opção interessante, o e-book dos tutoriais. Acesse o material completo em:
https://learnopengl.com.
2.2 Pontos, Linhas e Triângulos
Este capı́tulo introdutório explicará alguns dos conceitos básicos dos grá�icos 2D, com ênfase em como
começar o desenho simples no OpenGL. Usaremos a chamada interface de programação chamada "Modern
OpenGL". Clique no botão a seguir para saber mais.
Um programa grá�ico usando o OpenGL tipicamente é desenhado para ser executado na unidade central de
processamento (CPU) de um computador. Por sua vez, a CPU é usada para gerar dados grá�icos e pequenos
programas de GPU, os chamados sombreadores, ou "shaders".
Os dados grá�icos e os “shaders” são carregados da CPU para a GPU, que executa esses programas nos núcleos,
gerando, assim, a imagem na tela do computador. Em um aplicativo capaz de renderizar uma cena 3D, a CPU
especi�ica a imagem em função de um conjunto de triângulos (triangularização) que, por sua vez, são
de�inidos em termos de seus vértices.
As informações sobre os vértices e triângulos são carregadas na memória da GPU e ela executa, inicialmente,
aplicadores denominados “vertex	shaders”. Os “vertex	shaders” operam independentemente em cada vértice.
Posteriormente, OpenGL subdivide vértices em triângulos e, �inalmente, a GPU executa pequenos programas
chamados “fragment	 shaders”, capazes de projetar e manipular cada pixel na tela. Esse processo se repete
sempre que a tela é renderizada e, dependendo da GPU, podem variar de 30 a 60 vezes por segundo.
Modern
OpenGL
O OpenGL moderno foi projetado para aproveitar o poder das unidades de
processamento grá�ico (GPUs). Uma GPU é uma espécie de minisupercomputador e,
normalmente, contém centenas ou até milhares de núcleos. Cada núcleo em uma GPU
é um computador pequeno capaz de executar pequenos programas e lidar com
pequenos cálculos. Isso permite que uma GPU atue como um computador paralelo
poderoso, capaz de executar vários cálculos ao mesmo tempo. As GPUs foram
originalmente desenvolvidas para lidar com cálculos grá�icos, por exemplo, para
executar um programa separado para cada pixel em uma tela de computador. Eles
evoluı́ram para se tornarem muito mais poderosos e capazes de lidar com muitas
aplicações em diversos campos, como computação cientı́�ica,bioinformática,
ciência de dados e aprendizagem de máquina.
VOCÊ QUER VER?
Você quer aprender um pouco mais sobre o apaixonante mundo da realidade virtual?
O vıd́eo do site Tecmundo, “A história da Realidade Virtual”, mostra a história desde os
simples óculos adaptados até as modernas tecnologias de imersão, que possibilitam a
interação total do usuário. Acesse o vıd́eo disponıv́el em:
https://www.youtube.com/watch?v=DjkIhyrSzvw.
Há 3 modelos para os modos grá�icos de exibição: (1) pontos de desenho, (2) linhas de desenho e (3)
triângulos de desenho. Os três modelos são diferentes arquiteturas de hardware para exibição grá�ica. Os
pontos de desenho correspondem ao modelo de uma imagem grá�ica como uma matriz de pixels num formato
retangular. Por sua vez, as linhas de desenho correspondem à exibição vetorial de grá�icos. Finalmente, o
desenho de triângulos corresponde aos métodos usados pelos sistemas grá�icos mais modernos, que podem
exibir imagens tridimensionais.
2.2.1 Array Retangular de Pixels
O modelo de mais baixo nı́vel para tratar uma imagem grá�ica como uma matriz retangular de pixels, onde
cada pixel pode ser de�inido de maneira independe, com uma cor e brilho diferentes, é o modelo de exibição
usado para monitores LCD, CRTs e projetores. Especi�icamente para monitores de computador, televisões,
telefones celulares e para a maioria dos �ilmes, se os pixels forem pequenos o su�iciente, eles não poderão ser
vistos individualmente pelo olho humano e a imagem, embora composta de pontos, aparecerá como uma
única imagem suave.
Esse princı́pio também é usado na arte, principalmente, em mosaicos e, mais ainda, no pontilhismo, em que
as imagens são compostas por pequenas manchas de cor sólida, mas parecem formar uma imagem contı́nua
quando vistas a uma distância su�iciente.
Imagens grá�icas representadas como uma matriz retangular de pixels é uma forma de entender grá�icos
computacionais por meio de uma abstração conveniente e não, necessariamente, precisa. Por exemplo, na
maioria dos monitores, cada pixel consiste em três pontos separados e cada ponto gera uma das três cores
primárias, vermelho, azul e verde, e pode ser con�igurado independentemente para um valor de brilho.
Assim, cada pixel é realmente formado a partir de três pontos coloridos. Com uma lupa su�icientemente boa,
você pode ver cada pixel como cores separadas. Em dispositivos de baixa resolução, como uma televisão CRT
antiga, dependendo do design fı́sico da tela, as cores separadas podem aparecer em pontos ou listras
individuais. As três cores primárias de vermelho, amarelo e azul, conforme representadas na �igura a seguir,
podem ser combinadas para gerar uma paleta de cores variadas. No entanto, é natural que não possam
reproduzir todas as cores visı́veis possı́veis.
Uma segunda forma pela qual o modelo de matriz retangular não é preciso é porque, às vezes, o
endereçamento de imagens por subpixel é usado. Por exemplo, as impressoras a laser e a jato de tinta reduzem
problemas de frequência (efeitos de aliasing), como bordas irregulares nas linhas, desenhos e sı́mbolos,
posicionando o toner ou os pontos de tinta com posicionamento. Alguns computadores usam a renderização
no nı́vel do subpixel, exibindo texto em uma resolução mais alta do que seria possı́vel, tratando assim cada
pixel como três subpixels endereçáveis de forma independente. Dessa forma, o dispositivo pode posicionar o
texto no nı́vel do subpixel e alcançar um nı́vel mais alto de detalhes. Isso pode bene�iciar também os textos
sendo exibidos, já que os caracteres podem ser mais bem formados.
Neste capı́tulo, no entanto, raramente teremos ocasião de examinar questões de subpixels. Faz mais sentido
modelarmos um pixel como sendo um único ponto retangular que pode ser de�inido com a cor e o brilho
desejados. Entretanto, há muitas ocasiões em que o fato de uma imagem grá�ica de computador ser composta
de pixels pode ser importante. Por exemplo, o algoritmo de Bresenham (BO� HM; Prautsch, 1985) pode ser
usado para aproximar uma linha inclinada reta com pixels. Além disso, ao usar textura e ray	 tracing
(ASHDOWN, 1994), é importante evitar os problemas de aliasing que podem surgir com a amostragem de
uma imagem contı́nua ou de alta resolução em um conjunto de pixels.
Em princı́pio, qualquer imagem pode ser renderizada, de�inindo diretamente os nı́veis de brilho para cada
pixel na imagem. Na prática, é muito mais fácil não considerar os pixels e trabalhar em nı́veis mais altos de
modelagens baseadas em triangularização. Em aplicativos de programação grá�ica de alto nı́vel, geralmente,
ignoramos o fato de que a imagem grá�ica é renderizada usando uma matriz retangular de pixels.
Ressaltamos que a maioria dos programas OpenGL funciona desenhando triângulos e permite que o hardware
grá�ico lide com a maior parte do trabalho de conversão dos resultados em nı́veis de brilho de pixel. Isso se
baseia em várias técnicas so�isticadas para desenhar diversos triângulos sobrepostos na tela do computador
como uma verdadeira matriz de pixels, incluindo métodos de sombreamento e suavização e aplicação de
mapas de textura.
Figura 1 - Um pixel é formado por sub-regiões ou subpixels, cada um dos quais mostra uma das três cores.
Fonte: Elaborado pelo autor, 2019.
2.2.2 Gráficos de vetores
Os grá�icos vetoriais tradicionais renderizam imagens como um conjunto de linhas. Isso não permite
desenhar superfı́cies ou objetos sólidos. Em vez disso, é mais fácil desenhar formas bidimensionais, grá�icos
de funções ou imagens de estrutura de arame de objetos tridimensionais. Um protótipo que pode ser usado
como exemplo de sistemas de grá�icos vetoriais são os plotters de caneta, tais como os de “geometria da
tartaruga”.
Os plotters de caneta possuem uma caneta de desenho que se move sobre uma folha plana de papel. Os
comandos disponı́veis incluem (a) pen	 up, que levanta a caneta da superfı́cie do papel, (b) pen	 down, que
abaixa a ponta da caneta sobre o papel e (c) move-to (x, y), que move a caneta em uma linha reta da posição
atual para o ponto com as coordenadas ⟨x, y⟩, como mostrado na �igura a seguir.
Quando a caneta está levantada, ela se move sem desenhar e quando a caneta está abaixada, ela desenha à
medida que se move. Além disso, pode haver comandos para alternar para uma caneta de cor diferente e
comandos para percorrer caminhos curvos, como arcos circulares ou elı́pticos e curvas Bézier (1974).
Outro exemplo de dispositivos grá�icos vetoriais são os terminais de exibição de grá�icos vetoriais que,
tradicionalmente, são monitores monocromáticos que podem desenhar linhas arbitrárias. Nesses terminais
de exibição de grá�icos vetoriais, a tela é uma grande extensão de fósforo e não possui pixels. Um osciloscópio
tradicional à moda antiga é outro exemplo de um dispositivo de exibição de grá�icos vetoriais. Um show de
luzes a laser também é um tipo de imagem de grá�icos vetoriais.
Figura 2 - Exemplo de comandos de grá�icos vetoriais.
Fonte: Elaborado pelo autor, 2019.
Os terminais de exibição de grá�icos vetoriais deixaram de ser comuns há décadas, portanto, as imagens de
grá�icos vetoriais, geralmente, são renderizadas em telas baseadas em pixels. Em sistemas baseados em
pixels, a imagem da tela é armazenada como um bitmap, ou seja, como uma tabela contendo todas as cores de
pixels. Em vez disso, um sistema de grá�icos vetoriais armazena a imagem como uma lista de comandos, por
exemplo, como uma lista de comandos para cima / baixo da caneta e para mover. Essa lista de comandos é
chamada de lista de exibição.
Como o hardware grá�ico baseado em pixel é muito prevalente, as imagens grá�icas vetoriais modernas,
geralmente, são exibidas nesse tipo de hardware. No entanto, é importante destacar que hardware baseado em
pixel não pode desenhar diretamente linhas ou curvas arbitrárias e, em vez disso, deve aproximar linhas e
curvascom pixels. Por outro lado, tem a vantagem de poder desenhar imagens mais so�isticadas, incluindo
regiões de renderização preenchidas ou sombreadas com uma cor, padrão ou imagem.
A linguagem postscript da Adobe é um exemplo proeminente de um moderno sistema de grá�icos vetoriais.
Outro exemplo acessı́vel é o elemento , da linguagem Javascript (BUSS; FILLMORE, 2001), que torna muito
fácil mostrar grá�icos vetoriais em uma página web. O usa comandos tais como moveto(x,y) e lineto(x,y), que
habilitam a mesma funcionalidade de penup, pendown e move-to.
2.2.3 Triângulos
Um passo adiante, tanto em abstração, quanto em so�isticação, é o modelo poligonal de imagens grá�icas. E�
muito comum que as imagens grá�icas tridimensionais sejam modeladas primeiro como um conjunto de
polı́gonos. Por exemplo, elas são convertidas em triângulos para serem exibidas em uma tela (bidimensional).
A imagem �inal é composta por diversas imagens triangulares menores (mais fáceis de processar). A
modelagem baseada em triângulo é usada em quase todos os sistemas tridimensionais de computação grá�ica.
E� uma ferramenta central para a geração de grá�icos tridimensionais interativos e é usada para renderização
foto-realista, inclusive em �ilmes e jogos de computador.
A maioria dos computadores possui hardware grá�ico de �inalidade especial para o processamento de
triângulos, geralmente, na forma de uma GPU separada. Uma das operações essenciais para uma GPU é
desenhar um único triângulo na tela e preencher seu interior. O interior pode ser preenchido com uma cor
sólida ou, normalmente, pode ser sombreado com a cor variando ao longo do triângulo.
VOCÊ O CONHECE?
Katsuya Eguchi, nascido aos 15 de maio de 1965, em Tóquio, no Japão, é um game
designer que trabalha na Nintendo desde 1986. Ele foi um dos designers de Super
Mario	 Bros.	 3, Super	 Mario	World e responsável pelos jogos Wii	 Play, Wii	 Music, Wii
Sports	Resorts e Wii	Sports com mais de 82 milhões de unidades vendidas.
Além disso, o mapeamento de textura pode ser usado para pintar uma imagem ou textura no triângulo. As
GPUs são incrivelmente e�icazes nisso: com programação e inicialização adequadas, é possı́vel renderizar
muitos milhões de triângulos por segundo (ou até bilhões em aplicativos muito simpli�icados). São muitos
triângulos!
O objetivo de técnicas como triângulos de sombreamento ou texturização é tornar o objeto modelado
poligonalmente mais realista. Atualmente, os games mais básicos utilizam a técnica da texturização que torna
o cenário do jogo mais realista e agradável para os jogadores. Observem a seguir um exemplo do emprego da
técnica de texturização.
Antigamente, a aplicação destas técnicas nos jogos era um pouco restrita devido ao problema da falta de
recursos de processamento grá�ico, pois durante as cenas dos jogos estas técnicas teriam que ser aplicadas
continuamente, representando, muitas vezes, milhões de operações de renderização por segundo, trabalho
inviável para os hardwares da época.
Figura 3 - Esfera à esquerda e a esfera à direita com tratamento da texturização poligonal.
Fonte: TECHMUNDO, 2008.
2.3 Sistemas de Coordenadas
Ao renderizar um objeto geométrico, sua posição e forma são especi�icados em termos das posições de seus
vértices. Por exemplo, um triângulo é especi�icado em termos das posições de seus três vértices. As
linguagens de programação grá�ica, incluindo o OpenGL, permitem con�igurar seus próprios sistemas de
coordenadas para especi�icar posições de pontos e isso é feito usando uma matriz para de�inir um
mapeamento do seu sistema de coordenadas para as coordenadas da tela.
No plano bidimensional, também chamado de , a posição de um vértice é de�inida especi�icando suas
coordenadas . A convenção usual (ver �igura a seguir) é que o eixo é horizontal e apontando para a
direita, e o eixo é vertical e apontando para cima.
No espaço tridimensional, , as posições são especi�icadas pelas triplas ⟨a, b, c⟩, fornecendo as
coordenadas x, y e z do vértice. No entanto, a convenção de como os três eixos de coordenadas são
posicionados é diferente em Computação Grá�ica do que é habitual em Matemática. A �igura a seguir mostra a
orientação dos eixos de coordenadas, conforme usado na Computação Grá�ica.
Figura 4 - O plano , e a junção .
Fonte: Elaborado pelo autor, 2019.
Na computação grá�ica, o eixo está apontando para a direita, o eixo está apontando para cima e o eixo 
está apontando para o visualizador. Isso é diferente do que você pode estar acostumado. Por exemplo, no
cálculo, os eixos geralmente, apontam para frente, para a direita e para cima (respectivamente). A
convenção de computação grá�ica foi adotada, presumivelmente, porque mantém os eixos na mesma
posição do plano .
Figura 5 - Os eixos de coordenadas em e o ponto . O eixo está apontando para o
visualizador.
Fonte: Elaborado pelo autor, 2019.
2.4 Pontos, linhas e triângulos em OpenGL
Esta seção fornece uma visão geral de como o OpenGL especi�ica as geometrias de pontos, linhas e triângulos,
focando nos métodos mais simples e comuns. Um exemplo de código e explicações sobre esses e outros
recursos do OpenGL podem ser encontrados nos programas SimpleDrawModern, SimpleAnimModern e
BasicDrawModes, disponı́veis ao longo deste capı́tulo. Esses programas também ilustram como o código C ++,
as chamadas de função OpenGL e os programas de sombreamento se encaixam em um programa totalmente
funcional.
Por enquanto, discutimos apenas desenhar vértices em posições �ixas no plano ou no espaço . Eles
são especi�icados fornecendo uma matriz de posições de vértices, além das informações sobre como elas são
unidas para formar linhas ou triângulos.
2.4.1 Carregando vértices em um VBA e VBO
Pontos, linhas e triângulos são sempre especi�icados em termos de posições de vértice. As posições dos
vértices são, geralmente, dadas em termos de suas coordenadas em ou suas coordenadas 
 em . No entanto, mais tarde, ao trabalharmos com coordenadas homogêneas, veremos que as posições
podem ser dadas em termos de coordenadas . Vamos começar com um exemplo simples de seis
vértices no Em um programa C ou C ++, eles podem ser fornecidos, explicitamente, em uma matriz como
a seguir:
//Array de coordenadas para seis vértices
�loat verts[] = {
0.5 , 1.0, //vértice v0
2.0 , 2.0, //vértice v1
1.8 , 2.6, //vértice v2
0.7 , 2.2, //vértice v3
1.6 , 1.2, //vértice v4
1.0 , 0.5 //vértice v5
};
Essa declaração da matriz verts aloca espaço para 12 números �loats (números de ponto �lutuante),
fornecendo as coordenadas dos vértices . Por exemplo, e são iguais a 1.8 e
2.6 e fornecem as coordenadas do ponto . A �igura a seguir mostra as posições
desses vértices.
Figura 6 - Os seis pontos no array	verts.
Fonte: Elaborado pelo autor, 2019.
A matriz verts é alocada no espaço de memória do programa C ++, talvez até no armazenamento temporário na
pilha de execução do C ++. Para renderizar objetos usando esses vértices, é necessário carregar os dados no
espaço de memória do OpenGL. Infelizmente, isso é um pouco complexo, mas pode ser realizado com o
seguinte código (minimalista):
unsigned int theVAO; // Nome do Vértice Array Objeto (VAO)
glGenVertexArrays (1,&theVAO);
unsigned int theVBO; // Nome do Vértice Buffer Objeto (VBO)
glGenBuffers (1, &theVBO);
glBindBuffer (GLARRAYBUFFER,theVBO); // Selecione o VBO ativo
glBufferData (GLARRAYBUFFER, sizeof(verts), verts, GLSTATICDRAW);
unsigned int vPos loc = 0; // Localização do shader
glBindVertexArray(theVAO); // Selecione o VAO ativo
glVertexAttribPointer (vPos loc, 2, GL_FLOAT, GL_FALSE, 0,(void*)0 );
glEnableVertexAttribArray(vPos loc);
Há muitos detalhes nesse código. Observe que ele começa pedindo ao OpenGL para con�igurar um Vértice
Array Objeto (VAO) e um Vértice Buffer Objeto (VBO). Um VBO contém dados de vértice; no nosso exemplo,
ele contém as coordenadasdos vértices. Em outras aplicações, como será discutido mais adiante, o VBO
pode conter coordenadas de textura, normais da superfı́cie, propriedades da cor ou do material etc. Um VAO,
por sua vez, contém informações sobre como os dados de vértices são armazenados no VBO.
Nesse sentido, o objetivo principal de um VAO é informar aos programas shaders como acessar os dados
armazenados no VBO. O código copia os dados do vértice no VBO chamando glBufferData. A chamada para
glVertexAttribPointer informa ao VAO que os dados do vértice consistem em pares de números de ponto
�lutuante e que os dados começam no inı́cio do VBO.
Vértice	Buffer	Objeto. O VBO contém dados por vértice; ou seja, em nosso exemplo, cada vértice tem suas
próprias coordenadas x, y. Esses dados de vértice também são chamados de atributos de vértice. Observe as
linhas a seguir:
unsigned int theVBO; // Nome do Vértice Buffer Objeto (VBO)
glGenBuffers (1, &theVBO);
As linhas pedem ao OpenGL para con�igurar um novo VBO. O primeiro parâmetro em glGenBuffers é o número
de VBOs a serem con�igurados. Cada VBO é referenciada (ou nomeada) por um número inteiro não assinado.
O segundo parâmetro em glGenBuffers é o endereço no qual os nomes dos novos VBOs são retornados.
Observe agora as linhas a seguir:
glBindBuffer (GLARRAYBUFFER,theVBO); // Selecione o VBO ativo
glBufferData (GLARRAYBUFFER, sizeof(verts), verts, GLSTATICDRAW);
Essas linhas copiam os dados por vértice no VBO. O OpenGL usa vários tipos de buffers e um deles é o
GL_ARRAY_BUFFER e a chamada para glBindBuffer faz da VBO o atual GL_ARRAY_BUFFER. Por sua vez,
glBufferData é usado para copiar os dados por vértice para o VBO. Seu protótipo de função é:
glBufferData(GLenum target, int size, void* data, GLenum usage);
Importante ressaltar que este protótipo de função não está totalmente correto. Simpli�icaremos os protótipos
de funções por uma questão de simplicidade de entendimento. Pelo mesmo motivo, geralmente, encobrimos
muitos dos recursos de comando. Incentivamos você a aprender mais sobre essas funções do OpenGL
pesquisando on-line. Ao fazer isso, tenha cuidado ao pesquisar a documentação do OpenGL, e não a
documentação do OpenGL ES.
Uma alternativa ao GL_STATIC_DRAW, se os dados forem alterados toda vez que a cena for renderizada, é o
GL_DYNAMIC_DRAW. O destino especi�ica em qual buffer do OpenGL os dados devem ser copiados. O quarto
parâmetro fornece uma dica de como os dados serão usados.
Assim, o GL_STATIC_DRAW especi�ica que os dados são usados com frequência, mas não são alterados com
frequência. Isso incentiva o OpenGL a armazenar os dados na memória da GPU para obter melhor velocidade
de renderização. Uma alternativa ao GL_STATIC_DRAW, se os dados forem alterados toda vez que a cena for
renderizada, é o GL_DYNAMIC_DRAW. O segundo parâmetro, sizeof	 (verts), é o número de bytes de dados a
serem carregados. O VBO será redimensionado conforme necessário para acomodar os dados. O terceiro
parâmetro é um ponteiro para o inı́cio dos dados a serem copiados no VBO.
Vértice	Array	Objeto. O VAO mantém as informações sobre os atributos de vértice. No nosso caso, essas
informações são que os dados por vértice que consistem em pares de números de ponto �lutuante e são
armazenados em locais adjacentes, começando no inı́cio do VBO. Isso é realizado com as seguintes linhas de
código:
glBindBuffer (GLARRAYBUFFER,theVBO); // Selecione o VBO ativo
...
unsigned int vPos loc = 0; // Localização do shader
glBindVertexArray(theVAO); // Selecione o VAO ativo
glVertexAttribPointer (vPos loc, 2, GL_FLOAT, GL_FALSE, 0,(void*)0 );
Inicialmente, chamamos glBindBuffer e glBindVertexArray para selecionar o VAO e o VBO atuais. O protótipo
da função para glVertexAttribPointer é:
glVertexAttribPointer( int index, int size, GLenum type,
bool normalize, int stride, void* bufferOffset );
O primeiro parâmetro, index, é a "localização" do programa shader para os dados e mais tarde nosso shader de
vértice usará "location = 0" para acessar esses dados. O segundo e o terceiro parâmetro especi�icam o número
de valores de dados por vértice e seu tipo. Em nosso exemplo, cada vértice possui dois (2) números de ponto
�lutuante, portanto usamos "2, GL_FLOAT". O parâmetro �inal fornece o deslocamento em bytes no VBO onde
os dados são iniciados. Para nós, era "(void *) 0", pois os dados do vértice começam no inı́cio da VBO.
O quinto parâmetro, chamado de stride (passada), especi�ica o espaçamento entre os dados para vértices
sucessivos. O "stride" é o número de bytes desde o inı́cio dos dados de um vértice até o inı́cio dos dados até o
próximo vértice. Usamos "0" para o stride, que informa ao OpenGL para calcular a passada (stride) com base
na suposição de que os dados estão compactados. Nós também poderı́amos ter usado o comando:
glVertexAttribPointer( vPos loc, 2, GL_FLOAT, GL_FALSE,
2*sizeof(�loat), (void*)0 );
Aqui, "0" poderia ser substituı́do por "2 * sizeof (�loat)" para dar o passo explicitamente. O quarto parâmetro,
normalize (normalizar), controla como os valores inteiros são convertidos em ponto �lutuante quando
carregados no VBO. Desta forma, estamos enviando valores ponto �lutuante. Portanto, este parâmetro é
ignorado em nosso exemplo.
O passo �inal é dizer ao VAO para "ativar" os dados por vértice no VBO. Nosso código fez isso com o comando:
glEnableVertexAttribArray(vPos loc);
Assim, isso indica ao VAO que o atributo de vértice com o ı́ndice vertPos_loc é especi�icado em uma base por
vértice no VBO.
2.5 Projetando pontos e linhas
Agora que de�inimos uma matriz de posições de vértices e carregamos os dados necessários no VBO e no
VAO, estamos prontos para fornecer o código que realmente renderiza os pontos. Para renderizar os vértices
como seis pontos isolados, usamos o código C ++ a seguir:
glBindVertexArray(theVAO);
int vColor_loc = 1;
glVertexAttrib3f(vColor_loc, 0.0, 0.0, 0.0); // Cor preta ⟨0, 0, 0⟩ glDrawArrays(GL_POINTS, 0, 6);
Importante ressaltar que antes de fornecer esse código, é preciso também indicar qual programa de
sombreamento usar. Embora não seja foco dessa unidade, os shaders serão discutidos brevemente neste
capı́tulo.
O resultado dos comandos acima é desenhar os seis pontos, como mostra a �igura a seguir (“Os três modos
(tipos) diferentes de desenhar linhas conforme controlados pelo primeiro parâmetro glDrawArrays”) e
compare com a �igura anterior (“Os seis pontos no array	verts”). A chamada para glBindVertexArray seleciona
o VAO. Como o VAO sabe qual VBO contém os dados por vértice, não é necessário vincular explicitamente o
VBO. De fato, é possı́vel que vários VBOs sejam usados para armazenar diferentes atributos de vértice.
A chamada da função glVertexAttrib3f de�ine um valor de cor, nesse caso, a cor é preta. A cor é dada por três
números de ponto �lutuante e no intervalo de 0 a 1.0, fornecendo os componentes vermelho, verde e azul
(RGB) da cor. Em nosso código, a cor é um atributo genérico e isso signi�ica que todos os vértices têm a
mesma cor. Consequentemente, o valor da cor deve ser de�inido logo antes da renderização dos pontos, em
vez de ser armazenado no VBO por vértice. A vantagem disso é que, se todos os vértices tiverem a mesma cor,
não será necessário desperdiçar memória no VBO especi�icando a mesma cor repetidamente. A desvantagem é
VAMOS PRATICAR?
Os comandos existentes na API OpenGL facilitam criar e manipular di
�iguras geométricas durante a execução de atividades como a implement
jogos digitais. Escreva um programa com OpenGL utilizando Vértice Buffe
e Vértice Array Objeto para gerar alguns pontos e experimente mu
parâmetros no código criado para obter diferentes resultados e experiênci
que, pelo menos nas versões mais usadas do OpenGL, é necessário chamar glVertexAttrib3f cada vez que a cor
muda durante a renderização. O valor do vColor_loc é 1, pois nosso programa desombreador de vértices
usará location	=	1 para acessar a cor.
A chamada para glDrawArrays é o comando que realmente faz com que os vértices sejam renderizados. O
primeiro parâmetro, GL_POINTS, diz ao OpenGL para desenhar os vértices como pontos isolados. O segundo
parâmetro, 0, diz para começar com o vértice número 0, ou seja, o primeiro vértice. O terceiro parâmetro, 6, é
o número de vértices a serem renderizados.
Você também pode renderizar os pontos unidos por linhas. O primeiro modo, GL_LINES, usa o seguinte
código:
glBindVertexArray(theVAO);
int vColor loc = 1;
glVertexAttrib3f(vColor loc, 0.0, 0.0, 0.0); // Cor preta (0,0,0) glDrawArrays(GL LINES, 0, 6);
Isso é idêntico ao código usado para renderizar os vértices como pontos, mas usa GL_LINES no lugar de
GL_POINTS. Isso resulta no desenho das linhas mostradas na �igura a seguir. O efeito é usar cada par sucessivo
de vértices como pontos �inais de um segmento de linha. Ou seja, se há vértices ele
desenha o segmento de linha com os pontos �inais . Isso é
mostrado na �igura a seguir, item “b”.
Outra opção para linhas é GL_LINE_STRIP, que desenha uma sequência conectada de segmentos de linha,
começando com o primeiro vértice, unindo um segmento de linha a cada vértice sucessivo, terminando no
último vértice. Em outras palavras, quando existem vértices, se desenham os segmentos de linha que unem
, como vemos na �igura acima, item “c”.
A opção GL_LINE_LOOP desenha esses segmentos de linha, mais uma linha do vértice �inal de volta ao
primeiro vértice, renderizando, assim, um loop fechado de segmentos de linha. Isso desenha também o
segmento de linha que .
2.5.1 Desenhando triângulos
Figura 7 - Os três modos (tipos) diferentes de desenhar linhas conforme controlados pelo primeiro
parâmetro glDrawArrays.
Fonte: Elaborado pelo autor, 2019.
A operação de renderização fundamental para grá�icos 3D é desenhar um triângulo. Normalmente, os
triângulos são desenhados como formas sólidas e preenchidas. Ou seja, geralmente, desenhamos triângulos,
não arestas de triângulos ou vértices de triângulos. Em OpenGL, a maneira mais básica de desenhar triângulos
é usar o comando glDrawArrays com uma das opções GL_TRIANGLES, GL_TRIANGLE_STRIP ou
GL_TRIANGLE_FAN.
A �igura a seguir (item “a”) ilustra como os triângulos são renderizados com GL_TRIANGLES e glDrawArrays.
Aqui se assume que os seis vértices são armazenados no VBO: esses vértices são agrupados
em triplos e cada triplo de�ine os três vértices de um triângulo. Genericamente, se há vértices
, então, para todo , os vértices são usados para
formar um triângulo.
Observe que os triângulos são mostrados com a face frontal padrão visı́vel para o visualizador. Os vértices 
são numerados na ordem necessária para os modos de desenho. Para isso, é importante observar a diferença
na localização e numeração dos vértices em cada �igura, especialmente dos vértices u4 e u5 na primeira e na
última �igura. Cada triângulo tem uma frente e um lado de trás. No lado da frente, o visualizador vê os vértices
 ordenados no sentido anti-horário (CCW) ao redor do triângulo. No verso, um
visualizador vê os vértices contornando o triângulo na ordem dos ponteiros do relógio (CW).
A �igura anterior (item “b”) ilustra como os triângulos são renderizados com GL_TRIANGLES_FAN num padrão
de contorno semelhante a um ventilador. Novamente, há seis vértices (mas diferentes do item
“a”).
Se há vértices com GL_TRIANGLES_FAN, então, para cada , os
vértices são usados para formar um triângulo. Estes triângulos, novamente, têm um lado de
frente e uma traseira. Os lados de frente são vistos por meio dos vértices no sentido anti-
horário (CCW). Assim, observamos que os triângulos na �igura anterior (item “b”) estão todos de frente e
ilustra como os triângulos são renderizados com GL_TRIANGLES_STRIP.
Novamente, há seis vértices mas ordenados diferentemente dos anteriores. Este renderiza o
triângulo com vértices depois o triângulo com vértices depois o triângulo com
vértices e, �inalmente, triângulo com vértices As ordens dos vértices são
Figura 8 - Três modos de desenho do triângulo.
Fonte: Elaborado pelo autor, 2019.
escolhidas de maneira que as frentes dos triângulos sejam vistas em sentido anti-horário (CCW) e o item “c”,
da �igura anterior, nos mostra os triângulos com as faces frontais visı́veis.
Para renderizar os triângulos mostrados no item “a” da �igura anterior, podemos usar o código mostrado
abaixo. Primeiro, uma matriz é carregada com sete vértices, dados por suas coordenadas (as
coordenadas são todas zero):
//Array de x,y,z coordenadas com sete vértices
�loat verts2[] = {
0.25, 0.5, 0.0, // Vértice w0
1.25, 1.0, 0.0, // Vértice w1
0.75, 1.5, 0.0, // Vértice w2
1.75, 1.8, 0.0, // Vértice w3
2.0, 3.0, 0.0, // Vértice w4
1.05, 2.5, 0.0, // Vértice w5
0.4, 2.4, 0.0, // Vértice w6
};
A �igura a seguir mostra todos os pontos dos verts2. A matriz verts2 é carregada em um VAO e VBO com o
seguinte código (assumimos que o VAO e o VBO já foram con�igurados e que o vPos	loc foi de�inido):
glBindBuffer (GLARRAYBUFFER,theVBO); // Selecione o VBO ativo
glBufferData (GLARRAYBUFFER, sizeof(verts2), verts2, GLSTATICDRAW);
glBindVertexArray(theVAO); // Selecione o VAO ativo
glVertexAttribPointer (vPos_loc, 2, GL_FLOAT, GL_FALSE, 0,(void*)0 );
glEnableVertexAttribArray(vPos_loc);
Os triângulos mostrados no item “a” da �igura anterior (“Três modos de desenho do triângulo”) podem ser
renderizados com o código (assumindo que Color	loc está de�inido como antes) a seguir:
Figura 9 - Os pontos usados para renderizar os triângulos com glDrawElements.
Fonte: Elaborado pelo autor, 2019.
glBindVertexArray(theVAO);
glVertexAttrib3f(vColor loc, 0.7, 0.7, 0.7); // Cinza claro
glDrawArrays(GL TRIANGLES, 0, 6);
A chamada para glDrawArrays especi�ica desenhar triângulos usando um total de seis vértices, começando
com o número de vértice 0. Há um sétimo vértice em verts2 que também foi carregado no VBO, mas é
ignorado no momento. O código como escrito os renderizará como triângulos cinza claro sem bordas.
O triângulo em formato de ventilador e o triângulo em formato de faixa, mostrados na �igura anterior (“Três
modos de desenho do triângulo”), usam seis dos vértices dados nos verts2, mas as entradas verts2 não estão
na ordem correta para renderizá-las com glDrawArrays. A seguir, discutiremos como isso pode ser feito
usando matrizes de elementos.
2.6 Renderizando com Array de Elementos
Uma matriz de elementos permite o uso de ı́ndices de vértices para desenhar. Isso pode ser útil quando os
vértices são reutilizados para vários comandos de desenho. Por exemplo, um único vértice pode aparecer em
vários triângulos desenhados no modo GL_TRIANGLES ou em várias tiras de triângulo e / ou ventiladores de
triângulo. Em vez de fazer várias cópias dos vértices com todos os seus atributos, podemos fazer uma cópia
do vértice em um VBO e depois referenciá-lo várias vezes por meio de matrizes de elementos. Para isso, é
necessário que os atributos do vértice sejam os mesmos sempre que o vértice for referenciado.
A� s vezes, uma matriz de elementos é chamada de "buffer de matriz de elemento", "objeto de buffer de
elemento" (EBO) ou "objeto de buffer de ı́ndice" (IBO). Para um exemplo de como usar matrizes de elementos,
o código a seguir pode desenhar os triângulos mostrados na �igura anterior (“Três modos de desenho do
CASO
Os pro�issionais que trabalham com imagem utilizam muito o processo de
renderização, ou seja, aplicação de técnicas de processamento digital de imagens,
obtendo um produto �inal, método muito utilização em jogos 2 e 3D. Temos os
modelos de renderização em tempo real e renderização off-line também chamada de
Pré-renderização, mas qual é a melhor? E� óbvio que se utiliza o modelo de
renderização em tempo real durante a execuçãodos jogos, mas na indústria
cinematográ�ica é utilizada a renderização off-line, pois o trabalho objetiva um
resultado �inal, o �ilme.
triângulo”). Primeiro, alocamos e de�inimos a matriz de elementos da seguinte maneira:
unsigned int elements[] = {
0, 1, 2, 3, 4, 5, // GL_TRIANGLES
2, 0, 1, 3, 5, 6, // GL_TRIANGLE_FAN
0, 1, 2, 3, 5, 4 // GL_TRIANGLE_STRIP
};
Os ı́ndices na matriz de elementos indicam quais vértices da matriz de verts devem ser usados com
glDrawArrays. Por exemplo, o ventilador do triângulo será desenhado com os vértices
. O código a seguir aloca um objeto de buffer de elemento (EBO) e carrega os
dados da matriz de elementos no EBO:
unsigned int theEBO;
glGenBuffers( 1, &theEBO );
glBindVertexArray(theVAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, theEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
Esses comandos funcionam exatamente como o código anterior que carregava dados no VBO. Os triângulos do
item “a” da �igura anterior (“Três modos de desenho do triângulo”) podem, então, ser desenhados com:
glBindVertexArray(theVAO);
glVertexAttrib3f(vColor loc, 0.7, 0.7, 0.7); // Cinza claro
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0 );
Observe que agora estamos usando glDrawElements em vez de glDrawArrays. Os segundo e quarto
parâmetros para glDrawElements são 6 e 0 e eles especi�icam que o desenho deve usar os vértices
referenciados pelos seis ı́ndices que começam na posição 0 no EBO (a posição é medida em bytes). O terceiro
parâmetro informa ao OpenGL que os ı́ndices são armazenados como números inteiros não assinados. Para
desenhar o ventilador triangular do item “b” da �igura anterior (“Três modos de desenho do triângulo”), a
chamada glDrawElements é substituı́da por:
glDrawElements (GL_TRIANGLE_FAN, 6, GL_UNSIGNED_INT, (void*) (6 * sizeof (unsigned int)) );
Isso novamente usa seis vértices, mas agora os ı́ndices começam na posição de bytes sizeof (unsigned	int)
no EBO, ou seja, no sétimo ı́ndice da matriz. Por �im, para desenhar a tira triangular do item “c” da �igura
anterior (“Três modos de desenho do triângulo”), use:
glDrawElements (GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_INT, (void*) (12 * sizeof (unsigned int)) );
2.6.1 Cores diferentes por vértice
Os exemplos de código anteriores atribuı́ram a mesma cor a todos os vértices, usando glVertexAttrib3f para
de�inir a cor como um atributo genérico. Mas também é possı́vel de�inir cores diferentes por vértice,
armazenando-as na VBO de maneira semelhante à maneira como as posições dos vértices são de�inidas. A
seguir, ilustramos como fazer isso intercalando posições e cores de vértices em uma única matriz. Métodos
semelhantes podem ser usados para outros atributos de vértice, como coordenadas de textura, normais,
propriedades do material etc. Também é possı́vel armazenar diferentes atributos de vértices em diferentes
matrizes ou mesmo em diferentes VBOs, em vez de intercalá-los em uma única matriz.
//Array de x,y coordenadas e cores r,g,b para três vértices
�loat verts3[] = {
// x,y R,G,B
0.0, 0.0, 1.0,0.0,0.0, // 1o Vértice Vermelho (1,0,0)
2.0, 0.0, 0.0,1.0,0.0, // 2o Vértice Verde (0,1,0)
1.0, 1.5, 0.0,0.0,1.0 // 3o Vértice Azul (0,0,1)
};
A matriz verts3 fornece aos três vértices cores diferentes, fornecendo o componente vermelho, verde e azul da
cor usando um número no intervalo [0,1]. Outras cores podem ser especi�icadas misturando diferentes
quantidades de vermelho, verde e azul. Por exemplo, branco é especi�icado pela cor , amarelo é
especi�icado por , magenta por e por . Você pode encontrar muitos outros
códigos de cores pesquisando on-line "cores RGB". Normalmente, eles são especi�icados com componentes
de cores dados por números inteiros entre 0 e 255 e podem ser convertidos no intervalo dividindo por
255. Também é possı́vel usar números inteiros no intervalo de 0 a 255 com o OpenGL, por exemplo, você
pode usar GL_UNSIGNED_BYTE em vez de GL_FLOAT ao chamar glVertexAttribPointer.
O envio dos três vértices coloridos como um triângulo é feito com o comando usual, agora usando apenas três
vértices para renderizar um único triângulo:
glDrawArrays( GL TRIANGLES, 0, 3 );
O resultado é mostrado na �igura a seguir, item “a”. A cor do triângulo em cada vértice é a cor vermelha, verde
ou azul, conforme especi�icado na matriz verts3. Os pontos internos são coloridos como uma média das cores
dos vértices e isso é chamado de sombreamento ou sombreamento suave.
Observem na �igura anterior que há meio caminho entre o vértice vermelho e verde, a cor é um amarelo
escuro. Amarelo escuro é a média de vermelho e verde e é representado pela tripla ½ ½ . O centro do
triângulo é cinza escuro, representado pela tripla .
2.6.2 Orientação e seleção de rosto
Figura 10 - Dois triângulos: com o sombreamento suave padrão (a) e o sombreamento "brilho total" (b). Este
último é criado com o fragment	shader.
Fonte: Elaborado pelo autor, 2019.
O OpenGL controla se os triângulos estão voltados para o visualizador ou distantes do visualizador, ou seja, o
OpenGL atribui a cada triângulo uma face frontal e uma face traseira. A� s vezes, é desejável que apenas as faces
frontais dos triângulos sejam visı́veis e, outras vezes, você pode desejar que as faces frontal e traseira de um
triângulo sejam visı́veis.
Se de�inirmos as faces traseiras para �icarem invisı́veis "separando-as", qualquer triângulo cuja face traseira
seria vista, normalmente, não será desenhado. Com efeito, um rosto descartado se torna transparente. Por
padrão, nenhuma face é selecionada, portanto, as faces frontal e traseira �icam visı́veis.
O OpenGL determina qual face de um triângulo é a face frontal pela convenção padrão de que os vértices de
um triângulo são especi�icados no sentido anti-horário (com algumas exceções para tiras de triângulo). Os
triângulos mostrados nas da �igura anterior (“Três modos de desenho do triângulo”) e item “a” da �igura
anterior (“Dois triângulos: com o sombreamento suave padrão (a) e o sombreamento "brilho total" (b). Este
último é criado com o fragment	shader”) são todos mostrados com as faces frontais visı́veis.
Você pode alterar a convenção para a qual a face é a face frontal usando o comando glFrontFace. Este comando
tem o formato a seguir:
glFrontFace( { GL_CW | GL_CCW } )
No comando, “CW” e “CCW” representam no sentido horário e anti-horário. GL_CCW é o padrão. O uso do
GL_CW faz com que a convenção oposta para as faces frontal e traseira seja usada nos triângulos
subsequentes.
Para selecionar as faces frontal e /ou traseira, use os comandos a seguir:
glCullFace( { GL_FRONT | GL_BACK | GL_FRONT_AND_BACK } );
glEnable(GL_CULL_FACE);
Você deve ativar explicitamente a seleção de rosto com a chamada para glEnable. A seleção de rosto pode ser
desativada novamente com o comando glDisable correspondente. Quando a seleção é ativada, a con�iguração
padrão para glCullFace é GL_BACK.
O toro inferior de estrutura wireframe da �igura anterior é mostrado sem nenhuma seleção de face, enquanto o
superior apresenta seleção da face traseira.
2.6.3 Triangularização wireframe
Por padrão, o OpenGL desenha triângulos conforme preenchido. E� possı́vel alterar isso usando a função
glPolygonMode para especi�icar se deseja desenhar triângulos sólidos, triângulos de estrutura de arame ou
apenas os vértices dos triângulos. Isso facilita para um programa alternar entre o modo de estrutura de arame
e não estrutura de arame. A sintaxe do comando glPolygonMode é:
glPolygonMode( { GL_FRONT | GL_BACK | GL_FRONT_AND_BACK }, { GL_FILL | GL_LINE | GL_POINT} );
Figura 11 - Dois toros de estrutura wireframe. O toro superior usa seleção de face; o toro inferior tem as
faces traseiras desativadas.
Fonte: Elaborado pelo autor, 2019.
O primeiro parâmetro para glPolygonMode especi�ica se o modo se aplica às faces frontal e / ou traseira. O
segundo parâmetrode�ine se os triângulos são desenhados preenchidos, como linhas ou apenas como
vértices.
2.7 Animação com double buffering
O termo "animação" refere-se ao desenho de objetos ou cenas em movimento. O movimento é apenas uma
ilusão visual. Na prática, a animação é obtida desenhando uma sucessão de cenas estáticas, chamadas
quadros, cada uma mostrando um instantâneo estático em uma instância no tempo. A ilusão de movimento é
obtida exibindo rapidamente quadros sucessivos.
Filmes e vı́deos, normalmente, têm uma taxa de quadros de 24 ou 48 quadros por segundo. Taxas de quadros
mais altas fornecem resultados muito melhores para movimentos com velocidade mais alta. As taxas de
quadros em grá�icos de computador podem variar com a potência do computador e a complexidade da
renderização de grá�icos, mas, geralmente, é desejável ter 30 quadros por segundo e, mais idealmente, obter
60 quadros por segundo. Essas taxas de quadros são bastante adequadas para proporcionar um movimento
suave na tela. Para telas montadas na cabeça, em que a exibição muda com a posição da cabeça do espectador,
são necessárias taxas de quadros ainda mais altas para obter bons efeitos.
O double	buffering (buffer duplo) pode ser usado para gerar quadros sucessivos de maneira limpa. Enquanto
uma imagem é exibida na tela, o próximo quadro está sendo criado em outra parte da memória. Quando o
próximo quadro estiver pronto para ser exibido, o novo quadro substituirá o quadro antigo na tela
instantaneamente (ou melhor: na próxima vez que a tela for redesenhada, a nova imagem será usada).
Uma região da memória em que uma imagem está sendo criada ou armazenada é chamada de buffer. A
imagem exibida é armazenada no buffer frontal e o buffer traseiro mantém o próximo quadro à medida que ele
é criado. Quando os buffers são trocados, a nova imagem substitui a antiga na tela. Observe que a troca de
buffers, geralmente, não requer cópia de um buffer para o outro. Em vez disso, basta atualizar os ponteiros
para alternar as identidades dos buffers frontal e traseiro.
Um exemplo de programa com double	 buffering é exibido abaixo (SimpleAnimModern). O loop	main deste
programa usa a interface GLFW, conforme a seguir:
while (!glfwWindowShouldClose(window)) {
myRenderScene(); // Renderiza nova cena
glfwSwapBuffers(window); // Mostra nova cena
glfwWaitEventsTimeout(1.0/60.0); // 60 frames/segundo
}
Essa chamada para myRenderScene processa o buffer de quadro atual, o chamado buffer de retorno. Durante a
renderização, a tela mostra o conteúdo do buffer frontal para que a renderização não apareça instantaneamente
na tela. Então, glfwSwapBuffers troca os buffers frontal e traseiro. Isso faz com que a cena recém-renderizada
seja mostrada no visor. A imagem da tela anterior está pronta para ser substituı́da no próximo passo de
renderização.
A chamada para glfwWaitEvents diz ao OpenGL para esperar até que algum "evento" ocorra ou até que 1/60 de
segundo tenha decorrido. Um "evento" pode ser um clique ou movimento do mouse, um pressionamento de
tecla, um redimensionamento de janela etc. Quando não há eventos, a cena é redesenhada aproximadamente
60 vezes por segundo. Esse tempo não é particularmente preciso. Para obter resultados mais con�iáveis, seu
programa pode veri�icar o tempo decorrido real. Se for suportado, a sincronização vertical também pode ser
usada. Se a cena é �ixa e não animada, em vez de glfwWaitEventsTimeout, você pode usar:
glfwWaitEvents(); // Use isso se não houver animação
Isso fará com que a imagem seja redesenhada apenas quando um evento ocorrer. Por exemplo, se a janela for
redimensionada, a cena precisará ser renderizada novamente. Em alguns casos, você pode desejar animar o
mais rápido possı́vel, mas veri�ique se ainda há eventos. Para isso, você pode usar:
glfwPollEvents(); // Apenas veri�ica eventos
Os programas OpenGL SimpleDrawModern (mostrado anteriormente) e SimpleDrawAnim fornecem exemplos
de captura de teclas e redimensionamento da janela de grá�icos. Além disso, o ConnectDotsModern mostra
como capturar cliques do mouse.
VAMOS PRATICAR?
A animação com double	buffering é uma técnica computacional na qual se 
uma sucessão de quadros, dando a impressão que uma imagem e
movimento. Escreva um programa em OpenGL que utilize o recurso
buffering e crie uma imagem em movimento. Experimente mudar
parâmetros no programa para obter resultados diferentes, contribuindo
para uma experiência mais proveitosa.
2.8 Anti-aliasing com supersampling
Problemas de aliasing surgem ao converter entre representações analógicas e digitais, ou ao converter entre
diferentes representações digitais de resolução. Um exemplo simples são as linhas irregulares que resultam
ao desenhar uma linha reta em pixels de uma matriz retangular. Esses problemas de aliasing podem ser
particularmente perturbadores para cenas animadas.
Uma maneira simples de reduzir drasticamente os problemas de aliasing em um programa OpenGL é incluir
as duas linhas a seguir para ativar o anti-aliasing de multisampling (MSAA):
glfwWindowHint(GLFW_SAMPLES,4); // Invoca o MSAA
glEnable(GL_MULTISAMPLE);
O parâmetro "4" instrui o OpenGL a usar o "aliasing de várias amostras" (multisampling), com cada pixel da
tela segurando quatro valores de cor e profundidade, em um arranjo 2x2 de subpixels. Cada pixel da tela tem
sua cor calculada uma vez por triângulo que se sobrepõe ao pixel da tela: os valores de cor e profundidade são
salvos nos subpixels que são realmente cobertos pelo triângulo. Isso pode melhorar muito muitos problemas
de aliasing comuns com arestas de triângulos.
Assim, o anti-aliasing de várias amostras (MSAA) é bastante caro em termos de memória, pois exige quatro
valores de cores e profundidade por pixel. A� s vezes, isso pode causar uma desaceleração notável no
desempenho grá�ico. No entanto, o fato de ser tratado diretamente pelo hardware da GPU o torna relativamente
e�iciente.
VAMOS PRATICAR?
Escreva um programa OpenGL que renderize um cubo com seis faces d
diferentes. Forme o cubo com oito vértices e doze triângulos, certi�icand
que as faces frontais estejam voltadas para fora. Você pode fazer isso co
triângulos separados usando GL_TRIANGLES ou com duas ou mais t
triângulo. Experimente mudar entre sombreamento suave e sombreado p
você já sabe executar rotações, deixe seu programa incluir a capacidade d
cubo.
Síntese
Concluı́mos este capı́tulo abordando a história da tecnologia de realidade virtual e da indústria
cinematográ�ica, tecnologia Computer	Graphic	Imagery (CGI), formas matemáticas, utilização da API OpenGL
na criação e manipulação de imagens.
Nesta unidade, você teve a oportunidade de:
conhecer um pouco da história da tecnologia de realidade virtual
e da indústria cinematográfica;
aprender sobre a tecnologia Computer Graphic Imagery (CGI);
•
•
aprender sobre formas matemáticas e como são utilizadas em
trabalhos gráficos;
conhecer a API OpenGL e apreender alguns comandos de seu
funcionamento.
•
•
Bibliografia
ANTON, H.; RORRES, C. Álgebra	linear	com	aplicações. 10. ed. Porto Alegre: Bookman, 2012. Disponı́vel em:
https://integrada.minhabiblioteca.com.br/books/9788540701700. Acesso em: 11 out. 2019.
ASHDOWN, I. Radiosity: A Programmer’s Perspective. New York: John Wiley, 1994.
BE�ZIER, P. E. Mathematical and practical possibilities of UNISURF. In: BARNHILL, E.; RIESENFELD, R. F. (Eds.).
Computer	Aided	Geometric	Design. Proceedings of Conference held at the University of Utah. Salt Lake City.
New York: Academic Press, 1974. p. 127-152.
BE�ZIER, P. E. How Renault uses numerical control for car body design and tooling. In: Society of Automotive
Engineers’ Congress. Proceedings…	SAE Technical Paper 680010. New York: Academic Press, 1968.
Böhm, W.; Prautsch, H. The insertion algorithm. Computer-Aided	Design, v. 17, n. 2, p. 58-59, 1985.
BUSS, S. R.; FILLMORE, J. Spherical averages and applications to spherical splines and interpolation.ACM
Transactions	on	Graphics, v. 20, n. 2, p. 95-126, 2001.
HILL, F. S. Computer	Graphics	using	OpenGL. Upper Saddle River: Prentice Hall, 2001.
JOSE� , M. F.; REIS, B. S. Projetos	 grá�icos: fundamentos 2D e 3D. São Paulo: Erica, 2015. Disponı́vel em:
https://integrada.minhabiblioteca.com.br/books/9788536519517. Acesso em: 11 out. 2019.
LEARN OPENGL. Welcome	to	OpenGL, 2019. Disponı́vel em: https://learnopengl.com/. Acesso em: 11 out.
2019.
LINHARES, G. O que é CGI e computação grá�ica. CanalTech - Software, 2019. Disponı́vel em:
https://canaltech.com.br/windows/como-testar-as-novidades-da-atualizacao-de-novembro-do-windows-10-
152229/. Acesso em: 11 out. 2019.
TECHMUNDO. A história da realidade virtual. Youtube, 7 nov. 2017. Disponı́vel em:
https://www.youtube.com/watch?v=DjkIhyrSzvw. Acesso em: 11 out. 2019.