Aula 07 — Leitura de Objetos e Superfícies Ocultas
Objetivos
Ao final desta aula você deve ser capaz de:
- Comparar wireframes, malhas poligonais e representações de sólidos, reconhecendo que cada estrutura responde a perguntas diferentes sobre o objeto.
- Construir uma malha triangular indexada com uma lista de vértices e uma tabela de faces, sem repetir coordenadas compartilhadas.
- Orientar consistentemente os vértices das faces e explicar como essa orientação define frente, verso e vetor normal.
- Diferenciar teste de profundidade e descarte de faces traseiras, diagnosticando o defeito visual produzido quando cada mecanismo é desligado.
- Calcular a normal de uma face por produto vetorial e relacioná-la à orientação usada no descarte de faces traseiras.
- Carregar um modelo de um arquivo Wavefront OBJ, convertendo seus índices para a mesma malha indexada usada nos exemplos escritos à mão.
Conteúdo
Retomando: o que muda em relação à Aula 06
Na Aula 06, a pirâmide já tinha cinco vértices e uma tabela indexada de faces.
Cada face, porém, era usada apenas para percorrer seu contorno com
GL_LINE_LOOP. Isso bastava para desenhar o wireframe, mas ainda não exigia
decidir qual lado da face era exterior nem atribuir-lhe uma normal. Nesta aula,
a mesma organização em VERTICES e FACES passa a produzir superfícies
preenchidas; por isso, a ordem dos índices e as normais tornam-se essenciais.
No wireframe, percorrer os vértices de uma face em sentido horário ou anti-horário produz as mesmas linhas. A tabela da Aula 06, portanto, podia ter as faces laterais orientadas para dentro sem alterar a imagem. Ao ativar o descarte de faces traseiras, isso deixa de ser indiferente: a tabela usada aqui inverte a ordem necessária para que todas as normais apontem para fora. Reaproveitar literalmente as faces da aula anterior faria as quatro laterais desaparecerem com o culling ativo.
Modelagem geométrica é o conjunto de métodos usados para descrever a forma e as propriedades geométricas de um objeto de maneira que um sistema gráfico possa armazená-lo, transformá-lo e exibi-lo. Não existe uma única representação melhor para tudo: a estrutura adequada depende das operações que o programa precisa realizar.
Formas de representação
Cada família da Figura 1 é uma resposta diferente à pergunta "o que exatamente guardar sobre este objeto".
| Representação | Armazena principalmente | Ponto forte | Limitação típica |
|---|---|---|---|
| Wireframe | vértices e arestas | simples, leve e rápido | imagem ambígua; não define superfícies nem interior |
| Malha poligonal | vértices e faces | adequada à rasterização e a diferentes níveis de detalhe | aproxima superfícies curvas; não garante, sozinha, um sólido válido |
| B-Rep | fronteira orientada e conectividade | descreve a casca de um sólido | exige consistência topológica |
| CSG | árvore de primitivas e operações booleanas | construção paramétrica por união, interseção e diferença | precisa ser convertida para exibição convencional |
| Varredura | seção geratriz e trajetória | modela extrusões e sólidos de revolução | depende da escolha da seção e do caminho |
| Voxels / octree | células ocupadas no espaço | testes de pertencimento e colisão | alta resolução pode consumir muita memória |
Uma malha poligonal representa a superfície como um conjunto discreto de faces. Triângulos são preferidos porque três pontos não colineares sempre definem um plano, todo triângulo é convexo e o hardware gráfico os processa diretamente. Quadriláteros e polígonos maiores acabam triangulados antes da rasterização.
Uma coleção de triângulos pode ter buracos, faces duplicadas, auto-interseções ou orientações incompatíveis. Para delimitar um sólido, a malha deve ser fechada e coerente: cada aresta interna é compartilhada pelas faces esperadas, e suas orientações concordam sobre qual lado é exterior.
Malha indexada: coordenadas uma vez, conectividade por índices
Em uma malha indexada, VERTICES guarda as coordenadas e FACES guarda
índices. Assim, faces vizinhas compartilham o mesmo vértice de verdade, em vez
de manter cópias independentes da mesma coordenada.
VERTICES = [
(0.0, 1.5, 0.0), # 0: ápice
(-1.0, 0.0, -1.0), # 1..4: base
(1.0, 0.0, -1.0),
(1.0, 0.0, 1.0),
(-1.0, 0.0, 1.0),
]
FACES = [
(0, 2, 1), (0, 3, 2), (0, 4, 3), (0, 1, 4),
(1, 2, 3), (1, 3, 4), # base quadrada em dois triângulos
]
Os quatro triângulos laterais compartilham o ápice de índice 0. Se ele for
alterado, todas as faces que o referenciam mudam juntas. Essa separação entre
geometria (coordenadas) e topologia (quem se liga a quem) reduz
redundância e evita fendas causadas por cópias divergentes.
A economia cresce depressa. Nesta pirâmide, seis faces guardam 18 índices em vez de 54 números soltos; no toro de 1024 faces do terceiro exemplo desta aula, são 3072 índices contra 9216 coordenadas — além das coordenadas armazenadas uma vez na lista de vértices. Essa comparação conta índices e coordenadas separadamente; a economia em bytes depende do tipo usado para cada valor.
Ambiente e execução dos exemplos
Os arquivos completos são executáveis com Python 3.10+, PySide6, PyOpenGL e contexto compatível com OpenGL 2.1. Na raiz do repositório:
uv run aula-07-modelagem-geometrica/malha_indexada.py
uv run aula-07-modelagem-geometrica/visibilidade.py
uv run aula-07-modelagem-geometrica/carga_modelos.py
Para downloads isolados, instale as dependências com
python -m pip install PySide6 PyOpenGL e execute python nome_do_arquivo.py.
Guarde toro.obj junto de carga_modelos.py, ou passe seu caminho como
argumento. As setas giram os objetos e Esc fecha as janelas. Os trechos
curtos desta página são recortes para leitura.
Exemplo 1 — da estrutura de arame à malha
📥 Baixe o arquivo completo:
malha_indexada.py
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if self.wireframe else GL_FILL)
glBegin(GL_TRIANGLES)
for face, cor in zip(FACES, CORES):
glColor3f(*cor)
for indice in face:
glVertex3f(*VERTICES[indice])
glEnd()
Pressione W para alternar entre wireframe e preenchimento. Pressione T
para sobrepor a triangulação ao modelo preenchido. A geometria não muda: só
muda a forma como as mesmas faces são rasterizadas.
A Figura 2 compara três execuções da mesma malha: somente arestas, faces
preenchidas e preenchimento com arestas sobrepostas. O preenchimento oculta
as arestas traseiras que eram visíveis no wireframe. T não triangula o
objeto: ele apenas revela os triângulos que já estão em FACES. Para ver
a diagonal da base, gire o modelo até enxergar sua parte inferior.

Orientação das faces e normais
OpenGL considera, por padrão, frontal uma face cujos vértices aparecem em ordem anti-horária na tela. Ao construir uma malha fechada, organizamos as faces em sentido anti-horário quando vistas do exterior. Inverter dois índices troca a orientação do triângulo e, portanto, o sinal de sua normal.
Para uma face com vértices , e , dois vetores do plano são e . A normal é o produto vetorial normalizado:
A regra da mão direita conecta a ordem dos vértices à direção da normal: os dedos acompanham e o polegar aponta para . A Figura 3 mostra os dois casos lado a lado — a mesma geometria, mudando só a ordem dos índices na tabela de faces.
A normal calculada ajuda a conferir a orientação, mas glNormal3f não
controla o descarte: a API usa a ordem dos vértices projetados e glFrontFace.
Inverter só a normal afetará a iluminação na Aula 08, sem trocar frente e verso.
Se o produto vetorial tiver comprimento zero, os pontos são colineares ou
coincidentes: o triângulo é degenerado e não tem uma normal unitária definida.
Se uma face some assim que o descarte de faces traseiras é ligado, a primeira suspeita é a orientação invertida. A Aula 08 retoma as normais para calcular a interação entre luz e superfície.
Superfícies ocultas: dois mecanismos, duas perguntas
Em uma projeção 3D, vários fragmentos podem disputar o mesmo pixel. O teste de profundidade mantém, para cada posição da tela, o fragmento mais próximo já encontrado. Por isso o quadro precisa limpar tanto a cor quanto a profundidade:
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LESS) # padrão: aceita o fragmento mais próximo
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
O descarte de faces traseiras (back-face culling) elimina antes da rasterização faces orientadas para longe do observador:
glEnable(GL_CULL_FACE)
glCullFace(GL_BACK)
glFrontFace(GL_CCW)
glDepthFunc escolhe a comparação feita no depth buffer. O padrão
GL_LESS aceita o novo fragmento quando sua profundidade é menor que a já
armazenada. Outras comparações, como GL_LEQUAL, existem para casos
específicos. De modo semelhante, glCullFace(GL_BACK) descarta o verso;
GL_FRONT descarta a frente e GL_FRONT_AND_BACK descarta ambas — esta última
opção é útil para diagnóstico, mas não deixa polígonos para rasterizar.
Eles não são substitutos, porque respondem a perguntas diferentes:
| Teste de profundidade | Descarte de faces traseiras | |
|---|---|---|
| Pergunta que responde | qual fragmento está mais perto nesta posição da tela | esta face está voltada para longe do observador |
| Dado que usa | a profundidade de cada fragmento | a orientação dos vértices na tela |
| Quando age | depois da rasterização, fragmento a fragmento | antes da rasterização, face a face |
| Funciona entre objetos diferentes | sim | não |
| Precisa de malha fechada para executar | não | não; exige cuidado com superfícies abertas |
Para as superfícies opacas desta aula, o teste de profundidade resolve a oclusão por pixel. O descarte economiza o processamento de faces traseiras, mas não compara distâncias entre superfícies. A fração descartada depende da geometria e da câmera; não é necessariamente metade das faces.
Numa malha fechada e coerente, vista de fora, retirar o descarte normalmente preserva a imagem se o teste de profundidade estiver ativo. Uma folha ou uma parede sem espessura, porém, pode precisar mostrar os dois lados. O descarte funciona também em malhas abertas; cabe ao programa decidir se ocultar o verso é adequado. Transparência requer cuidados além deste roteiro de superfícies opacas.
Esses não são os únicos algoritmos de visibilidade. O algoritmo do pintor ordena superfícies do fundo para a frente; BSP-trees particionam o espaço; Warnock subdivide a tela; e técnicas como A-buffer, scan-line Z-buffer, depth sort, células e portais atendem a diferentes tipos de cena. Nesta aula, o depth buffer e o back-face culling são o foco porque estão disponíveis diretamente no pipeline do OpenGL usado pelos exemplos.
Exemplo 2 — profundidade e descarte sob controle
📥 Baixe o arquivo completo:
visibilidade.py
O segundo exemplo separa os dois mecanismos de visibilidade:
| Tecla | Alterna | Experimento |
|---|---|---|
D | teste de profundidade | gire o objeto e observe faces distantes cobrindo faces próximas quando desligado |
C | descarte de faces traseiras | compare uma face correta e a mesma face invertida |
I | inverte/restaura a terceira face | introduz um erro de orientação sem editar o arquivo |
R | restaura estados e rotação | profundidade ligada, descarte desligado, faces corretas |
glEnable(GL_DEPTH_TEST) if self.depth else glDisable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE) if self.culling else glDisable(GL_CULL_FACE)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
Experimento — isolar profundidade e orientação
- Pressione
R. Com descarte desligado, useDpara comparar profundidade ligada e desligada no mesmo ângulo, como na Figura 4. Sem a comparação de profundidade, triângulos desenhados depois podem cobrir os mais próximos. - Pressione
ReC. UseIpara inverter a terceira face, como na Figura 5. O defeito aparece sem desligar a profundidade. DesligueC: a face volta, embora seus índices continuem invertidos.Rrestaura tudo.
Na pirâmide convexa, ativar o descarte pode esconder o problema causado pela falta de profundidade: as faces traseiras deixam de ser desenhadas. Por isso a primeira comparação exige descarte desligado. Isso não torna os dois mecanismos equivalentes em cenas com vários objetos ou concavidades.


Carga de modelos: quando a malha não cabe no código-fonte
Até aqui, toda malha foi digitada no próprio programa. Isso funciona enquanto o modelo tem cinco vértices; não funciona para nada que se pareça com um objeto real. Modelos são criados em ferramentas de modelagem, como Blender, 3ds Max e Maya, e exportados para formatos de troca, que o programa lê em tempo de execução.
O Wavefront OBJ é o formato de troca mais simples de ler: texto puro, uma diretiva por linha, sem cabeçalho binário. Ele guarda exatamente a estrutura que esta aula construiu à mão.
| Registro | Significado | Corresponde a |
|---|---|---|
v x y z | um vértice | um elemento de VERTICES |
vn x y z | uma normal | um elemento de NORMAIS |
vt u v | uma coordenada de textura | assunto de uma aula posterior |
f a b c | uma face, por índices | um elemento de FACES |
Geometria no OBJ, aparência no MTL
O OBJ pode fazer referência a uma biblioteca de materiais com mtllib e
selecionar um material para as faces seguintes com usemtl. A biblioteca fica
em um arquivo MTL separado:
| Registro MTL | Informação |
|---|---|
newmtl | nome que poderá aparecer em usemtl |
Ka, Kd, Ks | coeficientes ambiente, difuso e especular |
Ns | expoente de brilho especular |
d | opacidade do material |
illum | modelo de iluminação sugerido pelo arquivo |
map_Kd | arquivo de textura associado à cor difusa |
Esses registros descrevem parâmetros; eles não iluminam o objeto sozinhos. O programa ainda precisa criar fontes, configurar o modelo de reflexão e aplicar os materiais durante o desenho. A Aula 08 faz essa ligação. O carregador desta aula lê apenas geometria e normais para manter o primeiro parser OBJ pequeno e auditável.
A pirâmide dos exemplos anteriores, escrita em OBJ, é literalmente a mesma malha indexada:
# ápice e quatro vértices da base
v 0.0 1.5 0.0
v -1.0 0.0 -1.0
v 1.0 0.0 -1.0
v 1.0 0.0 1.0
v -1.0 0.0 1.0
# quatro faces laterais e a base triangulada
f 1 3 2
f 1 4 3
f 1 5 4
f 1 2 5
f 2 3 4
f 2 4 5
Quatro armadilhas de quem escreve o primeiro carregador
- Os índices do OBJ começam em 1. A face
f 1 3 2é a tupla(0, 2, 1)em Python. Esquecer a conversão normalmente provocaIndexErrorassim que uma face referencia o último vértice, pois o índicelen(vertices)fica fora da faixa válida da lista. - Índices negativos contam de trás para frente.
f -3 -2 -1são os três últimos vértices lidos até ali. Exportadores usam essa forma para permitir concatenar arquivos. - Faces podem ter mais de três vértices. Um polígono de lados vira triângulos por triangulação em leque, todos compartilhando o primeiro vértice. O leque só é correto para polígonos convexos — para um polígono côncavo ele produz triângulos fora da face.
- Um vértice de face pode vir em quatro formas:
v,v/vt,v//vnev/vt/vn. Separar o campo por/e ler o que interessa é obrigatório; tratar1//1como um inteiro falha.
Normais: as do arquivo ou as da malha?
Um OBJ pode ou não trazer vn. Quando não traz, as normais são calculadas
da própria geometria, com o mesmo produto vetorial da seção anterior. Quando
traz, vale usá-las: elas podem carregar uma intenção que a geometria sozinha
não expressa — uma quina viva, por exemplo, é representada associando normais diferentes aos cantos das faces que compartilham a
mesma posição, e a média das faces vizinhas
apagaria justamente a quina.
Escala e posição do modelo carregado
Um arquivo qualquer pode vir em qualquer unidade e em qualquer posição. Carregar sem ajustar é a causa mais comum do "abri e não apareceu nada": o modelo ficou grande ou pequeno demais para a escala da cena, ou está longe da origem e ficou fora do volume de visualização. O exemplo centraliza o modelo na origem e o escala pela maior dimensão de sua caixa envolvente antes de desenhar.
Exemplo 3 — lendo um modelo de arquivo
📥 Baixe o programa:
carga_modelos.pye o modelo:toro.obj
# Cada canto guarda índices independentes de posição e de normal.
pedacos = campo.split("/")
iv = _indice(pedacos[0], len(vertices))
inormal = None
if len(pedacos) == 3 and pedacos[2]:
inormal = _indice(pedacos[2], len(normais_lidas))
cantos.append((iv, inormal))
# Depois de ler os cantos: triangulação em leque.
for k in range(1, len(cantos) - 1):
triangulo = (cantos[0], cantos[k], cantos[k + 1])
faces.append(tuple(canto[0] for canto in triangulo))
No arquivo completo, as normais também são guardadas por canto de triângulo. Assim, duas faces podem compartilhar a posição e usar normais diferentes. Se algum canto não tiver normal, este carregador usa as normais calculadas para a malha inteira; ele não mistura as duas origens no mesmo desenho.
O toro.obj tem 512 vértices e 1024 faces — uma superfície fechada, curva e
não convexa, e por isso um caso muito melhor que a pirâmide para observar a
triangulação e a visibilidade de uma superfície com concavidades:
| Tecla | Alterna | O que observar |
|---|---|---|
W | wireframe / preenchido | a densidade da malha que produz a curva aparente |
C | descarte de faces traseiras | em uma malha fechada e coerente, a imagem não muda |
N | normais do arquivo / calculadas | o título informa a origem selecionada; sem vn, o terminal informa a indisponibilidade |
0 | orientação inicial | retorna ao mesmo enquadramento |
L, S | iluminação e tonalização opcionais | ponte para a Aula 08; deixe a iluminação desligada nesta atividade |
O modo inicial usa cores alternadas por triângulo, com iluminação desligada.
A tecla N seleciona os dados, mas só altera a iluminação quando L e o
modo suave (S) estão ativos. Isso evita interpretar uma ausência de mudança
visual como falha na leitura de vn.
O programa também imprime, ao abrir, quantos índices a malha indexada usa contra quantas coordenadas seriam necessárias se cada face guardasse as suas.
Ele lê geometria e normais, e ignora materiais. Em um OBJ, mtllib aponta para
um arquivo MTL e usemtl seleciona um material definido nele; registros como
newmtl, Ka, Kd, Ks, Ns, d e illum descrevem nome, componentes de
reflexão, brilho, opacidade e modelo de iluminação. O carregador também ignora
coordenadas de textura, grupos e suavização. É o suficiente para esta aula;
texturas e materiais entram mais adiante no curso. Um carregador de produção
também verificaria faces degeneradas e orientações incoerentes. Este
exemplo já rejeita índices zero e fora da faixa, mas não é um validador geral de OBJ.
Na Figura 6, o mesmo arquivo OBJ aparece em wireframe e com triângulos
preenchidos. Para reproduzir o enquadramento, pressione 0 e depois a seta
para baixo nove vezes; isso eleva a rotação X de −20° para 25° e deixa
o furo visível. O furo central pertence à geometria do toro; ele não indica uma
face perdida. Já uma falha localizada que aparece ao ativar C sugere uma
orientação incorreta e deve ser investigada na tabela de faces.

Da modelagem à visibilidade
Sem faces não há superfície para rasterizar; sem orientação consistente o descarte falha; sem profundidade a visibilidade depende da ordem acidental do desenho. Como mostra a Figura 7, nenhuma dessas etapas consegue corrigir um problema introduzido na anterior.
Atividades de Laboratório
Aquecimento
- Em uma cópia de
malha_indexada.py, altere apenas a altura do ápice emVERTICES[0]. Preveja quais quatro faces mudam; execute e confira. Restaure a coordenada antes da próxima comparação. - Repita o experimento de profundidade e orientação com
R,D,CeI. Explique por que desligarCfaz a face reaparecer sem reparar os índices. - Salve o
piramide.objmostrado no conteúdo e abra-o compython carga_modelos.py piramide.obj. Confirme seis triângulos e ausência de normais no arquivo pela mensagem do terminal.
Atividade — Octaedro como malha triangular indexada
A Figura 8 compara o ponto de partida executável com a solução da atividade. As cores são escolhidas por face e não dependem de luz: nesta aula, elas servem para acompanhar os índices e diagnosticar a visibilidade.

} />
📥 Baixe o ponto de partida:
octaedro_base.py
Objetivo. Completar um octaedro alongado, formado por duas pirâmides de base quadrada, usando seis vértices e oito faces triangulares, calcular suas normais e renderizá-lo com visibilidade correta, como na Figura 8.
Roteiro
Passo 1 — reconheça os vértices e conecte as faces (TODO 1). Execute o
arquivo-base: aparecem seis pontos. Identifique topo, fundo e os quatro
pontos do equador em VERTICES. Preencha FACES com quatro triângulos ligados
ao topo e quatro ao fundo. Faces vizinhas devem percorrer a aresta compartilhada
em sentidos opostos. O desenho ainda mostra pontos até o passo 4.
Passo 2 — calcule e confira as normais (TODO 2). Implemente normal_face
com o produto vetorial normalizado. Para cada face, calcule também seu centro
pela média dos três vértices: como este modelo é convexo e centrado na origem,
o produto escalar entre centro e normal deve ser positivo. Valor negativo
indica orientação para dentro. Esse teste não é um validador geral para modelos
côncavos. A normal será usada na iluminação da Aula 08; aqui ela ajuda a
conferir a geometria, sem precisar de GL_LIGHTING.
Passo 3 — configure a visibilidade (TODO 3). Habilite GL_DEPTH_TEST e
GL_CULL_FACE em initializeGL. O programa já define descarte de faces
traseiras e frente anti-horária. Não acrescente luzes nem materiais.
Passo 4 — desenhe a malha (TODO 4). Substitua GL_POINTS por
GL_TRIANGLES. Percorra enumerate(FACES), use CORES[numero] com
glColor3f e envie as três posições de cada face. Cada índice seleciona um
elemento de VERTICES; não envie o índice como coordenada.
Passo 5 — introduza e corrija um defeito. Gire com esquerda/direita e confira a superfície fechada. Troque dois índices de uma face visível e observe seu desaparecimento com o descarte ativo. Restaure os índices e confirme a correção. Se a malha sumir inteira, confira o sentido das faces; se faces distantes cobrirem as próximas, confira o teste de profundidade.
Checklist de conclusão
- O modelo tem exatamente 6 vértices compartilhados e 8 faces triangulares.
- Nenhuma face desaparece indevidamente durante uma volta completa.
- As cores permitem distinguir as faces durante a rotação.
- O teste de profundidade continua correto em qualquer ângulo.
-
normal_facenão contém normais escritas manualmente.
Para responder
- Quantas coordenadas seriam repetidas se cada uma das oito faces armazenasse seus três vértices separadamente?
- Por que trocar a ordem de dois índices inverte a normal?
- Por que
GL_CULL_FACEnão substituiGL_DEPTH_TEST? - Exporte seu octaedro como um arquivo
.obje abra-o comcarga_modelos.py. Que ajuste os índices exigiram?
Atividade — Auditoria de um modelo OBJ
Objetivo. Diagnosticar problemas de orientação, triangulação e normais em um modelo carregado de arquivo, relacionando o texto do OBJ ao resultado renderizado.
Use carga_modelos.py e toro.obj. Crie uma cópia chamada
toro_auditoria.obj para preservar o modelo original.
Roteiro
Passo 1 — confira o original. Abra toro.obj e confirme 512 vértices e
1.024 triângulos no terminal. Pressione C: visto de fora, o modelo correto
continua fechado. Deixe iluminação desligada e restaure o ângulo com 0.
Passo 2 — altere somente a orientação. Na cópia toro_auditoria.obj,
escolha uma linha f e troque dois campos inteiros — por exemplo,
a//na b//nb c//nc passa a a//na c//nc b//nb. Preserve a associação entre
posição e normal de cada canto. Abra explicitamente a cópia:
python carga_modelos.py toro_auditoria.obj
Confira: ative C e gire até encontrar a face alterada. O triângulo pode
estar no lado oculto no enquadramento inicial; ausência de defeito nesse ângulo
não prova que a orientação está correta. Desligue C e compare. A contagem
de vértices e triângulos não muda quando apenas a ordem é invertida.
Passo 3 — altere somente a disponibilidade de normais. Restaure a ordem
da face. Remova as linhas vn e converta cada campo v//vn de f em apenas
v. Apagar só as linhas vn deixa referências inválidas: nesse caso o
carregador deve recusar o arquivo, em vez de adivinhar uma normal.
Confira: abra a cópia novamente e pressione N. O terminal informa que
só existem normais calculadas. A geometria e as cores por triângulo continuam
iguais. A ausência de mudança visual é esperada, pois a iluminação está
desligada. O uso visual dessas normais é assunto da Aula 08.
Passo 4 — restaure e explique. Abra novamente o original e confirme as contagens e as normais disponíveis. Distinga defeito de orientação, referência inválida e ausência legítima de normais; cada um exige uma correção diferente.
Checklist de conclusão
- O modelo original abre com 512 vértices e 1.024 triângulos.
- A face invertida produz um defeito reproduzível com o descarte ativo.
- O modelo sem
vnusa as normais calculadas a partir da geometria. - O arquivo original permanece inalterado.
Para responder
- Por que desligar o descarte faz uma face invertida reaparecer sem corrigir a malha?
- Qual informação se perde ao remover
vn? - Que validação você adicionaria ao carregador para detectar a face invertida antes da renderização?
Exercícios (checkpoints)
Questões dissertativas
Explique por que um wireframe de um cubo pode ser visualmente ambíguo e quais informações uma malha de faces acrescenta.
Uma malha é desenhada corretamente sem culling, mas algumas faces somem quando GL_CULL_FACE é ativado. Qual é a causa mais provável e como diagnosticá-la?
Um colega escreveu um carregador de OBJ e algumas faces aparecem ligadas aos vértices errados, às vezes sem mensagem de erro. Que falha na conversão de índices pode explicar o sintoma?
Um modelo carregado de arquivo traz normais (vn). Em que situação vale usar essas normais em vez de recalculá-las pela média das faces vizinhas?
Questões objetivas
1. Qual estrutura evita repetir as coordenadas de um vértice compartilhado por várias faces?
- a)Uma lista de vértices e uma tabela de faces por índices
- b)Uma lista independente de coordenadas para cada face
- c)Somente uma tabela de arestas
- d)Um depth buffer maior
- e)Uma normal diferente para cada pixel
2. Qual mecanismo decide qual fragmento está mais próximo em uma posição da tela?
- a)Descarte de faces traseiras
- b)GL_SMOOTH
- c)Teste de profundidade
- d)Normalização das normais
- e)Triangulação em leque
3. Ao trocar dois vértices de um triângulo, o que acontece?
- a)Sua área dobra
- b)Sua orientação e sua normal se invertem
- c)Ele deixa de ser planar
- d)O depth buffer é desativado
- e)Sua posição é transladada
4. Em um arquivo OBJ, a linha 'f 1 3 2' corresponde a qual tupla de índices em uma lista Python?
- a)(1, 3, 2)
- b)(0, 2, 1)
- c)(2, 4, 3)
- d)(1, 2, 3)
- e)(-1, -3, -2)
5. Um arquivo OBJ traz uma face convexa com cinco vértices. Quantos triângulos a triangulação em leque produz?
- a)Dois
- b)Três
- c)Quatro
- d)Cinco
- e)Seis
Referências
Principais (essenciais)
- AZEVEDO, E.; CONCI, A.; LETA, F. R. Computação Gráfica. Rio de Janeiro: Elsevier, 2003–2008. 2 v. (004.92 A994c)
- FOLEY, J. D. et al. Computer Graphics: Principles and Practice. 3. ed. Addison-Wesley, 2013. (004.92 C738)
- HEARN, D.; BAKER, M. P.; CARITHERS, W. R. Computer Graphics with OpenGL. 4. ed. Pearson Prentice Hall, 2011. (004.92 H436co)
- The Khronos Group. OpenGL 2.1 Reference Pages — glNormal. Disponível em: registry.khronos.org/OpenGL-Refpages/gl2.1
Aprofundamento (opcionais)
- COHEN, M.; MANSSOUR, I. H. OpenGL: uma abordagem prática e objetiva. São Paulo: Novatec, 2006. (004.92 C678o)
- HETEM JUNIOR, A. Computação gráfica. Rio de Janeiro: LTC, 2006. (004.92 H589c)
- BURDEA, G.; COIFFET, P. Virtual Reality Technology. 2. ed. Wiley-Interscience, 2003. (004.94 B949v)
- OpenGL Wiki. Face Culling. Disponível em: wikis.khronos.org/opengl/Face_Culling
- OpenGL Wiki. Depth Test. Disponível em: wikis.khronos.org/opengl/Depth_Test
- Wikipedia. Wavefront .obj file. Disponível em: en.wikipedia.org/wiki/Wavefront_.obj_file
- Wikipedia. Polygon mesh. Disponível em: en.wikipedia.org/wiki/Polygon_mesh